···8181 name = "texlive-test-context";
8282 format = "context";
8383 texLive = texliveConTeXt;
8484+ # check that the PDF has been created: we have hit cases of context
8585+ # failing with exit status 0 due to a misconfigured texlive
8686+ postTest = ''
8787+ if [[ ! -f "$name".pdf ]] ; then
8888+ echo "ConTeXt test failed: file '$name.pdf' not found"
8989+ exit 1
9090+ fi
9191+ '';
8492 text = ''
8593 \starttext
8694 \startsection[title={ConTeXt test document}]
···331339 {,"$schemeInfraOnly"/share/texmf-var/tex/generic/config/}"$fname" \
332340 | tee "$out/scheme-infraonly/$fname.patch"
333341 done
334334- '';
335335-336336- # test that fmtutil.cnf is fully regenerated on scheme-full
337337- fmtutilCnf = runCommand "texlive-test-fmtutil.cnf" {
338338- kpathsea = texlive.pkgs.kpathsea.tex;
339339- schemeFull = texliveFull;
340340- } ''
341341- mkdir -p "$out"
342342-343343- diff --ignore-matching-lines='^# Generated by ' -u \
344344- {"$kpathsea","$schemeFull"/share/texmf-var}/web2c/fmtutil.cnf \
345345- | tee "$out/fmtutil.cnf.patch"
346342 '';
347343348344 # verify that the restricted mode gets enabled when
···11+# shellcheck shell=bash
22+33+# Replicate the post install phase of the upstream TeX Live installer.
44+#
55+# This script is based on the install-tl script and the TeXLive::TLUtils perl
66+# module, down to using the same (prefixed) function names and log messages.
77+#
88+# When updating to the next TeX Live release, review install-tl for changes and
99+# update this script accordingly.
1010+1111+### install-tl
1212+1313+# adjust texmf.cnf and texmfcnf.lua
1414+installtl_do_texmf_cnf () {
1515+ # unlike install-tl, we make a copy of the entire texmf.cnf
1616+ # and point the binaries at $TEXMFCNF/texmf.cnf via wrappers
1717+1818+ mkdir -p "$TEXMFCNF"
1919+ if [[ -e $texmfdist/web2c/texmfcnf.lua ]]; then
2020+ tlutils_info "writing texmfcnf.lua to $TEXMFCNF/texmfcnf.lua"
2121+ sed -e "s,\(TEXMFOS[ ]*=[ ]*\)[^\,]*,\1\"$texmfroot\",g" \
2222+ -e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1\"$texmfdist\",g" \
2323+ -e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSVAR\",g" \
2424+ -e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSCONFIG\",g" \
2525+ -e "s,\(TEXMFLOCAL[ ]*=[ ]*\)[^\,]*,\1\"$out/share/texmf-local\",g" \
2626+ -e "s,\$SELFAUTOLOC,$out,g" \
2727+ -e "s,selfautodir:/,$out/share/,g" \
2828+ -e "s,selfautodir:,$out/share/,g" \
2929+ -e "s,selfautoparent:/,$out/share/,g" \
3030+ -e "s,selfautoparent:,$out/share/,g" \
3131+ "$texmfdist/web2c/texmfcnf.lua" > "$TEXMFCNF/texmfcnf.lua"
3232+ fi
3333+3434+ tlutils_info "writing texmf.cnf to $TEXMFCNF/texmf.cnf"
3535+ sed -e "s,\(TEXMFROOT[ ]*=[ ]*\)[^\,]*,\1$texmfroot,g" \
3636+ -e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1$texmfdist,g" \
3737+ -e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSVAR,g" \
3838+ -e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSCONFIG,g" \
3939+ -e "s,\$SELFAUTOLOC,$out,g" \
4040+ -e "s,\$SELFAUTODIR,$out/share,g" \
4141+ -e "s,\$SELFAUTOPARENT,$out/share,g" \
4242+ -e "s,\$SELFAUTOGRANDPARENT,$out/share,g" \
4343+ "$texmfdist/web2c/texmf.cnf" > "$TEXMFCNF/texmf.cnf"
4444+}
4545+4646+# run postaction scripts from texlive.tlpdb
4747+# note that the other postactions (fileassoc, ...) are Windows only
4848+installtl_do_tlpdb_postactions () {
4949+ local postaction postInterp
5050+ if [[ -n $postactionScripts ]] ; then
5151+ tlutils_info "running package-specific postactions"
5252+ for postaction in $postactionScripts ; do
5353+ # see TeXLive::TLUtils::_installtl_do_postaction_script
5454+ case "$postaction" in
5555+ *.pl)
5656+ postInterp=perl ;;
5757+ *.texlua)
5858+ postInterp=texlua ;;
5959+ *)
6060+ postInterp= ;;
6161+ esac
6262+ tlutils_info "${postInterp:+$postInterp }$postaction install $texmfroot"
6363+ FORCE_SOURCE_DATE=1 $postInterp "$texmfroot/$postaction" install "$texmfroot" >>"$TEXMFSYSVAR/postaction-${postaction##*/}.log"
6464+ done
6565+ tlutils_info "finished with package-specific postactions"
6666+ fi
6767+}
6868+6969+installtl_do_path_adjustments () {
7070+ # here install-tl would add a system symlink to the man pages
7171+ # instead we run other nixpkgs related adjustments
7272+7373+ # generate wrappers
7474+ tlutils_info "wrapping binaries"
7575+7676+ local bash cmd extraPaths link path target wrapCount
7777+ bash="$(command -v bash)"
7878+ enable -f "${bash%/bin/bash}"/lib/bash/realpath realpath
7979+8080+ # common runtime dependencies
8181+ for cmd in cat awk sed grep gs ; do
8282+ # do not fail if gs is absent
8383+ path="$(PATH="$HOST_PATH" command -v "$cmd" || :)"
8484+ if [[ -n $path ]] ; then
8585+ extraPaths="${extraPaths:+$extraPaths:}${path%/"$cmd"}"
8686+ fi
8787+ done
8888+8989+ declare -i wrapCount=0
9090+ for link in "$out"/bin/* ; do
9191+ target="$(realpath "$link")"
9292+9393+ # skip non-executable files (such as context.lua)
9494+ if [[ ! -x $target ]] ; then
9595+ continue
9696+ fi
9797+9898+ if [[ ${target##*/} != "${link##*/}" ]] ; then
9999+ # detected alias with different basename, use immediate target of $link to preserve $0
100100+ # relevant for mktexfmt, repstopdf, ...
101101+ target="$(readlink "$link")"
102102+ fi
103103+104104+ rm "$link"
105105+ makeWrapper "$target" "$link" \
106106+ --inherit-argv0 \
107107+ --prefix PATH : "$extraPaths:$out/bin" \
108108+ --set-default TEXMFCNF "$TEXMFCNF" \
109109+ --set-default FONTCONFIG_FILE "$fontconfigFile"
110110+ wrapCount=$((wrapCount + 1))
111111+ done
112112+113113+ tlutils_info "wrapped $wrapCount binaries and scripts"
114114+115115+ # generate format symlinks (using fmtutil.cnf)
116116+ tlutils_info "generating format symlinks"
117117+ texlinks --quiet "$out/bin"
118118+119119+ # remove *-sys scripts since /nix/store is readonly
120120+ rm "$out"/bin/*-sys
121121+122122+ # link TEXMFDIST in $out/share for backward compatibility
123123+ ln -s "$texmfdist" "$out"/share/texmf
124124+125125+ # generate other outputs
126126+ local otherOutput otherOutputName
127127+ local otherOutputs="$otherOutputs"
128128+ for otherOutputName in $outputs ; do
129129+ if [[ $otherOutputName == out ]] ; then
130130+ continue
131131+ fi
132132+ otherOutput="${otherOutputs%% *}"
133133+ otherOutputs="${otherOutputs#* }"
134134+ ln -s "$otherOutput" "${!otherOutputName}"
135135+ done
136136+}
137137+138138+# run all post install parts
139139+installtl_do_postinst_stuff () {
140140+ installtl_do_texmf_cnf
141141+142142+ # create various config files
143143+ # in principle, we could use writeText and share them across different
144144+ # environments, but the eval & build overhead is not worth the savings
145145+ tlutils_create_fmtutil
146146+ tlutils_create_updmap
147147+ tlutils_create_language_dat
148148+ tlutils_create_language_def
149149+ tlutils_create_language_lua
150150+151151+ # make new files available
152152+ tlutils_info "running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
153153+ mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
154154+155155+ # update font maps
156156+ tlutils_info "generating font maps"
157157+ updmap-sys --quiet --force --nohash 2>&1
158158+ # configure the paper size
159159+ # tlmgr --no-execute-actions paper letter
160160+ # install-tl: "rerun mktexlsr for updmap-sys and tlmgr paper updates"
161161+ tlutils_info "re-running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
162162+ mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
163163+164164+ tlutils_update_context_cache
165165+166166+ # generate formats
167167+ # install-tl would run fmtutil-sys $common_fmtutil_args --no-strict --all
168168+ # instead, we want fmtutil to exit with error on failure
169169+ if [[ -n $fmtutilCnf ]] ; then
170170+ tlutils_info "pre-generating all format files, be patient..."
171171+ # many formats still ignore SOURCE_DATE_EPOCH even when FORCE_SOURCE_DATE=1
172172+ # libfaketime fixes non-determinism related to timestamps ignoring FORCE_SOURCE_DATE
173173+ # we cannot fix further randomness caused by luatex; for further details, see
174174+ # https://salsa.debian.org/live-team/live-build/-/blob/master/examples/hooks/reproducible/2006-reproducible-texlive-binaries-fmt-files.hook.chroot#L52
175175+ # note that calling faketime and fmtutil is fragile (faketime uses LD_PRELOAD, fmtutil calls /bin/sh, causing potential glibc issues on non-NixOS)
176176+ # so we patch fmtutil to use faketime, rather than calling faketime fmtutil
177177+ substitute "$texmfdist"/scripts/texlive/fmtutil.pl fmtutil \
178178+ --replace-fail "my \$cmdline = \"\$eng -ini " "my \$cmdline = \"faketime -f '\@$(date +'%F %T' --date=@"$SOURCE_DATE_EPOCH") x0.001' \$eng -ini "
179179+ FORCE_SOURCE_DATE=1 perl fmtutil --quiet --strict --sys --all 2>&1 | grep '^fmtutil' # too verbose
180180+ fi
181181+182182+ installtl_do_path_adjustments
183183+184184+ installtl_do_tlpdb_postactions
185185+186186+ # remove log files to improve reproducibility
187187+ find "$TEXMFSYSVAR" -name '*.log' -delete
188188+}
189189+190190+### TeXLive::TLUtils
191191+192192+tlutils_info () {
193193+ printf '%s\n' "texlive: $*"
194194+}
195195+196196+tlutils_create_fmtutil () {
197197+ # fmtutil.cnf created by install-tl already exists readonly in $texmfdist
198198+ # so here we need to *disable* the entries that are not in $fmtutilCnf
199199+ # and write the output in the writeable $TEXMFSYSVAR
200200+201201+ local engine fmt line outFile sedExpr
202202+ outFile="$TEXMFSYSVAR"/web2c/fmtutil.cnf
203203+204204+ tlutils_info "writing fmtutil.cnf to $outFile"
205205+206206+ while IFS= read -r line ; do
207207+ # a line is 'fmt engine ...' or '#! fmt engine ...'
208208+ # (see fmtutil.pl::read_fmtutil_file)
209209+ line="${line#\#! }"
210210+ read -r fmt engine _ <<<"$line"
211211+ # if a line for the ($fmt,$engine) pair exists, remove it to avoid
212212+ # pointless warnings from fmtutil
213213+ sedExpr="$sedExpr /^(#! )?$fmt $engine /d;"
214214+ done <<<"$fmtutilCnf"
215215+216216+ # disable all the remaining formats
217217+ sedExpr="$sedExpr /^[^#]/{ s/^/#! /p };"
218218+219219+ {
220220+ echo "# Generated by nixpkgs"
221221+ sed -E -n -e "$sedExpr" "$texmfdist"/web2c/fmtutil.cnf
222222+ [[ -z $fmtutilCnf ]] || printf '%s' "$fmtutilCnf"
223223+ } >"$outFile"
224224+}
225225+226226+tlutils_create_updmap () {
227227+ # updmap.cfg created by install-tl already exists readonly in $texmfdist
228228+ # so here we need to *disable* the entries that are not in $updmapCfg
229229+ # and write the output in the writeable $TEXMFSYSVAR
230230+231231+ local line map outFile sedExpr
232232+ outFile="$TEXMFSYSVAR"/web2c/updmap.cfg
233233+234234+ tlutils_info "writing updmap.cfg to $outFile"
235235+236236+ while IFS= read -r line ; do
237237+ # a line is 'type map' or '#! type map'
238238+ # (see fmtutil.pl::read_updmap_file)
239239+ read -r _ map <<<"$line"
240240+ # if a line for $map exists, remove it to avoid
241241+ # pointless warnings from updmap
242242+ sedExpr="$sedExpr /^(#! )?[^ ]*Map $map$/d;"
243243+ done <<<"$updmapCfg"
244244+245245+ # disable all the remaining font maps
246246+ sedExpr="$sedExpr /^[^ ]*Map/{ s/^/#! /p };"
247247+248248+ {
249249+ echo "# Generated by nixpkgs"
250250+ sed -E -n -e "$sedExpr" "$texmfdist"/web2c/updmap.cfg
251251+ [[ -z $updmapCfg ]] || printf '%s' "$updmapCfg"
252252+ } >"$outFile"
253253+}
254254+255255+tlutils__create_config_files () {
256256+ # simplified arguments
257257+ local header="$1"
258258+ local dest="$2"
259259+ local prefix="$3"
260260+ local lines="$4"
261261+ local suffix="$5"
262262+ if [[ -z "$header" || -e "$header" ]] ; then
263263+ tlutils_info "writing ${dest##*/} to $dest"
264264+ {
265265+ [[ -z $prefix ]] || printf '%s\n' "$prefix"
266266+ [[ ! -e $header ]] || cat "$header"
267267+ [[ -z $lines ]] || printf '%s\n' "$lines"
268268+ [[ -z $suffix ]] || printf '%s\n' "$suffix"
269269+ } >"$dest"
270270+ fi
271271+}
272272+273273+tlutils_create_language_dat () {
274274+ tlutils__create_config_files \
275275+ "$texmfdist"/tex/generic/config/language.us \
276276+ "$TEXMFSYSVAR"/tex/generic/config/language.dat \
277277+ '% Generated by nixpkgs' \
278278+ "$languageDat" \
279279+ ''
280280+}
281281+282282+tlutils_create_language_def () {
283283+ tlutils__create_config_files \
284284+ "$texmfdist"/tex/generic/config/language.us.def \
285285+ "$TEXMFSYSVAR"/tex/generic/config/language.def \
286286+ '' \
287287+ "$languageDef" \
288288+ '%%% No changes may be made beyond this point.
289289+290290+\uselanguage {USenglish} %%% This MUST be the last line of the file.'
291291+}
292292+293293+tlutils_create_language_lua () {
294294+ tlutils__create_config_files \
295295+ "$texmfdist"/tex/generic/config/language.us.lua \
296296+ "$TEXMFSYSVAR"/tex/generic/config/language.dat.lua \
297297+ '-- Generated by nixpkgs' \
298298+ "$languageLua" \
299299+ '}'
300300+}
301301+302302+tlutils_update_context_cache () {
303303+ if [[ -x $out/bin/mtxrun ]] ; then
304304+ tlutils_info "setting up ConTeXt cache"
305305+306306+ # temporarily patch mtxrun.lua to generate uuid's deterministically from SOURCE_DATE_EPOCH
307307+ mv "$out"/bin/mtxrun.lua{,.orig}
308308+ substitute "$out"/bin/mtxrun.lua.orig "$out"/bin/mtxrun.lua \
309309+ --replace-fail 'randomseed(math.initialseed)' "randomseed($SOURCE_DATE_EPOCH)"
310310+311311+ # this is very verbose, save the output for debugging purposes
312312+ {
313313+ mtxrun --generate
314314+ context --luatex --generate
315315+ [[ ! -x $out/bin/luajittex ]] || context --luajittex --generate
316316+ } >"$TEXMFSYSVAR"/context-cache.log
317317+318318+ mv "$out"/bin/mtxrun.lua{.orig,}
319319+ fi
320320+}
321321+322322+# init variables (export only the ones that are used in the wrappers)
323323+export PATH="$out/bin:$PATH"
324324+TEXMFSYSCONFIG="$out/share/texmf-config"
325325+TEXMFSYSVAR="$out/share/texmf-var"
326326+export TEXMFCNF="$TEXMFSYSVAR/web2c"
327327+328328+installtl_do_postinst_stuff
···8080 D # restart cycle from the current line
8181 }
82828383+ # extract font maps
8484+ /^execute add.*Map /{
8585+ # open a list
8686+ i\ fontMaps = [
8787+8888+ # loop through following map lines
8989+ :next-map
9090+ s/^\n?execute add(.*Map .*)$/ "\1"/p # print map
9191+ s/^.*$// # clear pattern space
9292+ N; /^\nexecute add.*Map /b next-map
9393+9494+ # close the string
9595+ i\ ];
9696+ D # restart cycle from the current line
9797+ }
9898+8399 # detect presence of notable files
84100 /^docfiles /{
85101 s/^.*$// # ignore the first line
···129145 # extract postaction scripts (right now, at most one per package, so a string suffices)
130146 s/^postaction script file=(.*)$/ postactionScript = "\1";/p
131147132132- # extract hyphenation patterns and formats
133133- # (this may create duplicate lines, use uniq to remove them)
134134- /^execute\sAddHyphen/i\ hasHyphens = true;
148148+ # extract hyphenation patterns
149149+ /^execute\sAddHyphen\s/{
150150+ # open a list
151151+ i\ hyphenPatterns = [
152152+153153+ # create one attribute set per hyphenation pattern
154154+155155+ # plain keys: name, lefthyphenmin, righthyphenmin, file, file_patterns, file_exceptions, comment
156156+ # optionally double quoted key: luaspecial, comment
157157+ # comma-separated lists: databases, synonyms
158158+ :next-hyphen
159159+ s/(^|\n)execute\sAddHyphen/ {/
160160+ s/\s+luaspecial="([^"]+)"/\n luaspecial = "\1";/
161161+ s/\s+(name|lefthyphenmin|righthyphenmin|file|file_patterns|file_exceptions|luaspecial|comment)=([^ \t\n]*)/\n \1 = "\2";/g
162162+ s/\s+(databases|synonyms)=([^ \t\n]+)/\n \1 = [ "\2" ];/g
163163+ s/$/\n }/
164164+165165+ :split-hyphens
166166+ s/"([^,]+),([^"]+)" ]/"\1" "\2" ]/;
167167+ t split-hyphens # repeat until there are no commas
168168+169169+ p
170170+ s/^.*$// # clear pattern space
171171+ N
172172+ /^\nexecute\sAddHyphen\s/b next-hyphen
173173+174174+ # close the list
175175+ i\ ];
176176+ D # restart cycle from the current line
177177+ }
135178136179 # extract format details
137180 /^execute\sAddFormat\s/{