Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/www/assets/typst/refresh.sh

4.5 KiB, 1 run

created by r2519314175:1071, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1#!/usr/bin/env bash
2# refresh.sh -- rebuild the vendored Typst packages under `packs/` from a local
3# typst package cache.
4#
5# It is shipped BESIDE what it produces, and served with it, deliberately: the
6# packs are sealed into `www/manifest.json` and the transparency chain, so the
7# recipe that made them belongs inside the same seal. A reader with the same
8# package cache runs this and gets the same bytes.
9#
10# bash www/assets/typst/refresh.sh # from ~/.cache/typst/packages
11# TYPST_CACHE=/some/where bash .../refresh.sh # from another cache
12#
13# NOTHING IS DOWNLOADED. The cache is read; if a package named below is not in
14# it, this script says so and stops rather than writing a set that is missing one.
15#
16# After running it, `www/assets/typst/packs/INDEX` has changed, and that file is
17# `include_str!`d by `src/wasm/typst.rs` -- so the wasm must be rebuilt and the
18# bundle resealed, or the wasm and the served packs describe different sets.
19
20set -euo pipefail
21
22HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23CACHE="${TYPST_CACHE:-$HOME/.cache/typst/packages}"
24OUT="$HERE/packs"
25
26# ── The set, and why each member is in it ───────────────────────────────────
27#
28# Namespace, name, version. Order is the order the INDEX lists them in, and the
29# INDEX is what a refusal reads out, so it is the order a person sees.
30#
31# cetz 0.3.4 the author's own book imports it; the whole reason for this
32# oxifmt 0.2.1 cetz 0.3.4 imports it, and cetz 0.3.2 does too
33# cetz 0.3.2 cetz-plot 0.1.1 imports THIS version, not 0.3.4
34# cetz-plot 0.1.1 charts and plots on top of cetz
35# fletcher 0.5.7 arrow diagrams; imports cetz 0.3.4
36#
37# cetz appears twice on purpose. A closure is not a wish list: cetz-plot names
38# `@preview/cetz:0.3.2` in `src/cetz.typ`, so shipping cetz-plot without 0.3.2
39# would ship a package that resolves and then fails on its own dependency --
40# which is the one failure this whole mechanism is written to make impossible to
41# mistake for something else.
42SET=(
43 "preview cetz 0.3.4"
44 "preview oxifmt 0.2.1"
45 "preview cetz 0.3.2"
46 "preview cetz-plot 0.1.1"
47 "preview fletcher 0.5.7"
48)
49
50# ── What is taken from each package ─────────────────────────────────────────
51#
52# The sources, the manifest that names the entrypoint, and the licence. Not the
53# README, not the gallery, not a built PDF: they are never read by a compile and
54# they are the bulk of what a package directory weighs. The licence IS taken --
55# these are other people's LGPL and MIT work and it ships inside our bundle.
56want() {
57 local root="$1"
58 ( cd "$root" && find . -type f \
59 \( -name '*.typ' -o -name 'typst.toml' -o -name 'LICENSE' -o -name 'LICENSE.*' \) \
60 -printf '%P\n' | LC_ALL=C sort )
61}
62
63rm -rf "$OUT"
64mkdir -p "$OUT"
65INDEX="$OUT/INDEX"
66
67{
68 echo "# Typst packages vendored into Daimond. Generated by www/assets/typst/refresh.sh."
69 echo "# One line per pack: namespace name version file-count pack-bytes."
70 echo "# The packs are at packs/<namespace>/<name>/<version>.pack."
71} > "$INDEX"
72
73for entry in "${SET[@]}"; do
74 read -r ns name ver <<< "$entry"
75 src="$CACHE/$ns/$name/$ver"
76 if [ ! -d "$src" ]; then
77 echo "refresh.sh: $ns/$name:$ver is not in $CACHE -- nothing written." >&2
78 exit 1
79 fi
80 entrypoint="$(sed -n 's/^[[:space:]]*entrypoint[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$src/typst.toml" | head -1)"
81 if [ -z "$entrypoint" ]; then
82 echo "refresh.sh: $ns/$name:$ver has no entrypoint in its typst.toml." >&2
83 exit 1
84 fi
85
86 mapfile -t files < <(want "$src")
87 if [ "${#files[@]}" -eq 0 ]; then
88 echo "refresh.sh: $ns/$name:$ver holds no sources." >&2
89 exit 1
90 fi
91
92 dest="$OUT/$ns/$name"
93 mkdir -p "$dest"
94 pack="$dest/$ver.pack"
95
96 # The header: ASCII lines, then ONE blank line, then the file bodies
97 # concatenated in the order listed. Lengths rather than delimiters, so a
98 # source containing anything at all cannot end a file early.
99 {
100 echo "DAIMOND TYPST PACK 1"
101 echo "namespace $ns"
102 echo "name $name"
103 echo "version $ver"
104 echo "entrypoint $entrypoint"
105 for f in "${files[@]}"; do
106 echo "file $(stat -c%s "$src/$f") $f"
107 done
108 echo
109 } > "$pack"
110 for f in "${files[@]}"; do
111 cat "$src/$f" >> "$pack"
112 done
113
114 echo "pack $ns $name $ver ${#files[@]} $(stat -c%s "$pack")" >> "$INDEX"
115 echo "packed $ns/$name:$ver -- ${#files[@]} files, $(stat -c%s "$pack") bytes"
116done
117
118echo
119echo "INDEX:"
120cat "$INDEX"
121echo
122echo "src/wasm/typst.rs include_str!s that INDEX -- rebuild the wasm and reseal."