···81 name = "texlive-test-context";
82 format = "context";
83 texLive = texliveConTeXt;
0000000084 text = ''
85 \starttext
86 \startsection[title={ConTeXt test document}]
···331 {,"$schemeInfraOnly"/share/texmf-var/tex/generic/config/}"$fname" \
332 | tee "$out/scheme-infraonly/$fname.patch"
333 done
334- '';
335-336- # test that fmtutil.cnf is fully regenerated on scheme-full
337- fmtutilCnf = runCommand "texlive-test-fmtutil.cnf" {
338- kpathsea = texlive.pkgs.kpathsea.tex;
339- schemeFull = texliveFull;
340- } ''
341- mkdir -p "$out"
342-343- diff --ignore-matching-lines='^# Generated by ' -u \
344- {"$kpathsea","$schemeFull"/share/texmf-var}/web2c/fmtutil.cnf \
345- | tee "$out/fmtutil.cnf.patch"
346 '';
347348 # verify that the restricted mode gets enabled when
···81 name = "texlive-test-context";
82 format = "context";
83 texLive = texliveConTeXt;
84+ # check that the PDF has been created: we have hit cases of context
85+ # failing with exit status 0 due to a misconfigured texlive
86+ postTest = ''
87+ if [[ ! -f "$name".pdf ]] ; then
88+ echo "ConTeXt test failed: file '$name.pdf' not found"
89+ exit 1
90+ fi
91+ '';
92 text = ''
93 \starttext
94 \startsection[title={ConTeXt test document}]
···339 {,"$schemeInfraOnly"/share/texmf-var/tex/generic/config/}"$fname" \
340 | tee "$out/scheme-infraonly/$fname.patch"
341 done
000000000000342 '';
343344 # verify that the restricted mode gets enabled when
···1+# shellcheck shell=bash
2+3+# Replicate the post install phase of the upstream TeX Live installer.
4+#
5+# This script is based on the install-tl script and the TeXLive::TLUtils perl
6+# module, down to using the same (prefixed) function names and log messages.
7+#
8+# When updating to the next TeX Live release, review install-tl for changes and
9+# update this script accordingly.
10+11+### install-tl
12+13+# adjust texmf.cnf and texmfcnf.lua
14+installtl_do_texmf_cnf () {
15+ # unlike install-tl, we make a copy of the entire texmf.cnf
16+ # and point the binaries at $TEXMFCNF/texmf.cnf via wrappers
17+18+ mkdir -p "$TEXMFCNF"
19+ if [[ -e $texmfdist/web2c/texmfcnf.lua ]]; then
20+ tlutils_info "writing texmfcnf.lua to $TEXMFCNF/texmfcnf.lua"
21+ sed -e "s,\(TEXMFOS[ ]*=[ ]*\)[^\,]*,\1\"$texmfroot\",g" \
22+ -e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1\"$texmfdist\",g" \
23+ -e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSVAR\",g" \
24+ -e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSCONFIG\",g" \
25+ -e "s,\(TEXMFLOCAL[ ]*=[ ]*\)[^\,]*,\1\"$out/share/texmf-local\",g" \
26+ -e "s,\$SELFAUTOLOC,$out,g" \
27+ -e "s,selfautodir:/,$out/share/,g" \
28+ -e "s,selfautodir:,$out/share/,g" \
29+ -e "s,selfautoparent:/,$out/share/,g" \
30+ -e "s,selfautoparent:,$out/share/,g" \
31+ "$texmfdist/web2c/texmfcnf.lua" > "$TEXMFCNF/texmfcnf.lua"
32+ fi
33+34+ tlutils_info "writing texmf.cnf to $TEXMFCNF/texmf.cnf"
35+ sed -e "s,\(TEXMFROOT[ ]*=[ ]*\)[^\,]*,\1$texmfroot,g" \
36+ -e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1$texmfdist,g" \
37+ -e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSVAR,g" \
38+ -e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSCONFIG,g" \
39+ -e "s,\$SELFAUTOLOC,$out,g" \
40+ -e "s,\$SELFAUTODIR,$out/share,g" \
41+ -e "s,\$SELFAUTOPARENT,$out/share,g" \
42+ -e "s,\$SELFAUTOGRANDPARENT,$out/share,g" \
43+ "$texmfdist/web2c/texmf.cnf" > "$TEXMFCNF/texmf.cnf"
44+}
45+46+# run postaction scripts from texlive.tlpdb
47+# note that the other postactions (fileassoc, ...) are Windows only
48+installtl_do_tlpdb_postactions () {
49+ local postaction postInterp
50+ if [[ -n $postactionScripts ]] ; then
51+ tlutils_info "running package-specific postactions"
52+ for postaction in $postactionScripts ; do
53+ # see TeXLive::TLUtils::_installtl_do_postaction_script
54+ case "$postaction" in
55+ *.pl)
56+ postInterp=perl ;;
57+ *.texlua)
58+ postInterp=texlua ;;
59+ *)
60+ postInterp= ;;
61+ esac
62+ tlutils_info "${postInterp:+$postInterp }$postaction install $texmfroot"
63+ FORCE_SOURCE_DATE=1 $postInterp "$texmfroot/$postaction" install "$texmfroot" >>"$TEXMFSYSVAR/postaction-${postaction##*/}.log"
64+ done
65+ tlutils_info "finished with package-specific postactions"
66+ fi
67+}
68+69+installtl_do_path_adjustments () {
70+ # here install-tl would add a system symlink to the man pages
71+ # instead we run other nixpkgs related adjustments
72+73+ # generate wrappers
74+ tlutils_info "wrapping binaries"
75+76+ local bash cmd extraPaths link path target wrapCount
77+ bash="$(command -v bash)"
78+ enable -f "${bash%/bin/bash}"/lib/bash/realpath realpath
79+80+ # common runtime dependencies
81+ for cmd in cat awk sed grep gs ; do
82+ # do not fail if gs is absent
83+ path="$(PATH="$HOST_PATH" command -v "$cmd" || :)"
84+ if [[ -n $path ]] ; then
85+ extraPaths="${extraPaths:+$extraPaths:}${path%/"$cmd"}"
86+ fi
87+ done
88+89+ declare -i wrapCount=0
90+ for link in "$out"/bin/* ; do
91+ target="$(realpath "$link")"
92+93+ # skip non-executable files (such as context.lua)
94+ if [[ ! -x $target ]] ; then
95+ continue
96+ fi
97+98+ if [[ ${target##*/} != "${link##*/}" ]] ; then
99+ # detected alias with different basename, use immediate target of $link to preserve $0
100+ # relevant for mktexfmt, repstopdf, ...
101+ target="$(readlink "$link")"
102+ fi
103+104+ rm "$link"
105+ makeWrapper "$target" "$link" \
106+ --inherit-argv0 \
107+ --prefix PATH : "$extraPaths:$out/bin" \
108+ --set-default TEXMFCNF "$TEXMFCNF" \
109+ --set-default FONTCONFIG_FILE "$fontconfigFile"
110+ wrapCount=$((wrapCount + 1))
111+ done
112+113+ tlutils_info "wrapped $wrapCount binaries and scripts"
114+115+ # generate format symlinks (using fmtutil.cnf)
116+ tlutils_info "generating format symlinks"
117+ texlinks --quiet "$out/bin"
118+119+ # remove *-sys scripts since /nix/store is readonly
120+ rm "$out"/bin/*-sys
121+122+ # link TEXMFDIST in $out/share for backward compatibility
123+ ln -s "$texmfdist" "$out"/share/texmf
124+125+ # generate other outputs
126+ local otherOutput otherOutputName
127+ local otherOutputs="$otherOutputs"
128+ for otherOutputName in $outputs ; do
129+ if [[ $otherOutputName == out ]] ; then
130+ continue
131+ fi
132+ otherOutput="${otherOutputs%% *}"
133+ otherOutputs="${otherOutputs#* }"
134+ ln -s "$otherOutput" "${!otherOutputName}"
135+ done
136+}
137+138+# run all post install parts
139+installtl_do_postinst_stuff () {
140+ installtl_do_texmf_cnf
141+142+ # create various config files
143+ # in principle, we could use writeText and share them across different
144+ # environments, but the eval & build overhead is not worth the savings
145+ tlutils_create_fmtutil
146+ tlutils_create_updmap
147+ tlutils_create_language_dat
148+ tlutils_create_language_def
149+ tlutils_create_language_lua
150+151+ # make new files available
152+ tlutils_info "running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
153+ mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
154+155+ # update font maps
156+ tlutils_info "generating font maps"
157+ updmap-sys --quiet --force --nohash 2>&1
158+ # configure the paper size
159+ # tlmgr --no-execute-actions paper letter
160+ # install-tl: "rerun mktexlsr for updmap-sys and tlmgr paper updates"
161+ tlutils_info "re-running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
162+ mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
163+164+ tlutils_update_context_cache
165+166+ # generate formats
167+ # install-tl would run fmtutil-sys $common_fmtutil_args --no-strict --all
168+ # instead, we want fmtutil to exit with error on failure
169+ if [[ -n $fmtutilCnf ]] ; then
170+ tlutils_info "pre-generating all format files, be patient..."
171+ # many formats still ignore SOURCE_DATE_EPOCH even when FORCE_SOURCE_DATE=1
172+ # libfaketime fixes non-determinism related to timestamps ignoring FORCE_SOURCE_DATE
173+ # we cannot fix further randomness caused by luatex; for further details, see
174+ # https://salsa.debian.org/live-team/live-build/-/blob/master/examples/hooks/reproducible/2006-reproducible-texlive-binaries-fmt-files.hook.chroot#L52
175+ # note that calling faketime and fmtutil is fragile (faketime uses LD_PRELOAD, fmtutil calls /bin/sh, causing potential glibc issues on non-NixOS)
176+ # so we patch fmtutil to use faketime, rather than calling faketime fmtutil
177+ substitute "$texmfdist"/scripts/texlive/fmtutil.pl fmtutil \
178+ --replace-fail "my \$cmdline = \"\$eng -ini " "my \$cmdline = \"faketime -f '\@$(date +'%F %T' --date=@"$SOURCE_DATE_EPOCH") x0.001' \$eng -ini "
179+ FORCE_SOURCE_DATE=1 perl fmtutil --quiet --strict --sys --all 2>&1 | grep '^fmtutil' # too verbose
180+ fi
181+182+ installtl_do_path_adjustments
183+184+ installtl_do_tlpdb_postactions
185+186+ # remove log files to improve reproducibility
187+ find "$TEXMFSYSVAR" -name '*.log' -delete
188+}
189+190+### TeXLive::TLUtils
191+192+tlutils_info () {
193+ printf '%s\n' "texlive: $*"
194+}
195+196+tlutils_create_fmtutil () {
197+ # fmtutil.cnf created by install-tl already exists readonly in $texmfdist
198+ # so here we need to *disable* the entries that are not in $fmtutilCnf
199+ # and write the output in the writeable $TEXMFSYSVAR
200+201+ local engine fmt line outFile sedExpr
202+ outFile="$TEXMFSYSVAR"/web2c/fmtutil.cnf
203+204+ tlutils_info "writing fmtutil.cnf to $outFile"
205+206+ while IFS= read -r line ; do
207+ # a line is 'fmt engine ...' or '#! fmt engine ...'
208+ # (see fmtutil.pl::read_fmtutil_file)
209+ line="${line#\#! }"
210+ read -r fmt engine _ <<<"$line"
211+ # if a line for the ($fmt,$engine) pair exists, remove it to avoid
212+ # pointless warnings from fmtutil
213+ sedExpr="$sedExpr /^(#! )?$fmt $engine /d;"
214+ done <<<"$fmtutilCnf"
215+216+ # disable all the remaining formats
217+ sedExpr="$sedExpr /^[^#]/{ s/^/#! /p };"
218+219+ {
220+ echo "# Generated by nixpkgs"
221+ sed -E -n -e "$sedExpr" "$texmfdist"/web2c/fmtutil.cnf
222+ [[ -z $fmtutilCnf ]] || printf '%s' "$fmtutilCnf"
223+ } >"$outFile"
224+}
225+226+tlutils_create_updmap () {
227+ # updmap.cfg created by install-tl already exists readonly in $texmfdist
228+ # so here we need to *disable* the entries that are not in $updmapCfg
229+ # and write the output in the writeable $TEXMFSYSVAR
230+231+ local line map outFile sedExpr
232+ outFile="$TEXMFSYSVAR"/web2c/updmap.cfg
233+234+ tlutils_info "writing updmap.cfg to $outFile"
235+236+ while IFS= read -r line ; do
237+ # a line is 'type map' or '#! type map'
238+ # (see fmtutil.pl::read_updmap_file)
239+ read -r _ map <<<"$line"
240+ # if a line for $map exists, remove it to avoid
241+ # pointless warnings from updmap
242+ sedExpr="$sedExpr /^(#! )?[^ ]*Map $map$/d;"
243+ done <<<"$updmapCfg"
244+245+ # disable all the remaining font maps
246+ sedExpr="$sedExpr /^[^ ]*Map/{ s/^/#! /p };"
247+248+ {
249+ echo "# Generated by nixpkgs"
250+ sed -E -n -e "$sedExpr" "$texmfdist"/web2c/updmap.cfg
251+ [[ -z $updmapCfg ]] || printf '%s' "$updmapCfg"
252+ } >"$outFile"
253+}
254+255+tlutils__create_config_files () {
256+ # simplified arguments
257+ local header="$1"
258+ local dest="$2"
259+ local prefix="$3"
260+ local lines="$4"
261+ local suffix="$5"
262+ if [[ -z "$header" || -e "$header" ]] ; then
263+ tlutils_info "writing ${dest##*/} to $dest"
264+ {
265+ [[ -z $prefix ]] || printf '%s\n' "$prefix"
266+ [[ ! -e $header ]] || cat "$header"
267+ [[ -z $lines ]] || printf '%s\n' "$lines"
268+ [[ -z $suffix ]] || printf '%s\n' "$suffix"
269+ } >"$dest"
270+ fi
271+}
272+273+tlutils_create_language_dat () {
274+ tlutils__create_config_files \
275+ "$texmfdist"/tex/generic/config/language.us \
276+ "$TEXMFSYSVAR"/tex/generic/config/language.dat \
277+ '% Generated by nixpkgs' \
278+ "$languageDat" \
279+ ''
280+}
281+282+tlutils_create_language_def () {
283+ tlutils__create_config_files \
284+ "$texmfdist"/tex/generic/config/language.us.def \
285+ "$TEXMFSYSVAR"/tex/generic/config/language.def \
286+ '' \
287+ "$languageDef" \
288+ '%%% No changes may be made beyond this point.
289+290+\uselanguage {USenglish} %%% This MUST be the last line of the file.'
291+}
292+293+tlutils_create_language_lua () {
294+ tlutils__create_config_files \
295+ "$texmfdist"/tex/generic/config/language.us.lua \
296+ "$TEXMFSYSVAR"/tex/generic/config/language.dat.lua \
297+ '-- Generated by nixpkgs' \
298+ "$languageLua" \
299+ '}'
300+}
301+302+tlutils_update_context_cache () {
303+ if [[ -x $out/bin/mtxrun ]] ; then
304+ tlutils_info "setting up ConTeXt cache"
305+306+ # temporarily patch mtxrun.lua to generate uuid's deterministically from SOURCE_DATE_EPOCH
307+ mv "$out"/bin/mtxrun.lua{,.orig}
308+ substitute "$out"/bin/mtxrun.lua.orig "$out"/bin/mtxrun.lua \
309+ --replace-fail 'randomseed(math.initialseed)' "randomseed($SOURCE_DATE_EPOCH)"
310+311+ # this is very verbose, save the output for debugging purposes
312+ {
313+ mtxrun --generate
314+ context --luatex --generate
315+ [[ ! -x $out/bin/luajittex ]] || context --luajittex --generate
316+ } >"$TEXMFSYSVAR"/context-cache.log
317+318+ mv "$out"/bin/mtxrun.lua{.orig,}
319+ fi
320+}
321+322+# init variables (export only the ones that are used in the wrappers)
323+export PATH="$out/bin:$PATH"
324+TEXMFSYSCONFIG="$out/share/texmf-config"
325+TEXMFSYSVAR="$out/share/texmf-var"
326+export TEXMFCNF="$TEXMFSYSVAR/web2c"
327+328+installtl_do_postinst_stuff
···80 D # restart cycle from the current line
81 }
82000000000000000083 # detect presence of notable files
84 /^docfiles /{
85 s/^.*$// # ignore the first line
···129 # extract postaction scripts (right now, at most one per package, so a string suffices)
130 s/^postaction script file=(.*)$/ postactionScript = "\1";/p
131132- # extract hyphenation patterns and formats
133- # (this may create duplicate lines, use uniq to remove them)
134- /^execute\sAddHyphen/i\ hasHyphens = true;
000000000000000000000000000135136 # extract format details
137 /^execute\sAddFormat\s/{
···80 D # restart cycle from the current line
81 }
8283+ # extract font maps
84+ /^execute add.*Map /{
85+ # open a list
86+ i\ fontMaps = [
87+88+ # loop through following map lines
89+ :next-map
90+ s/^\n?execute add(.*Map .*)$/ "\1"/p # print map
91+ s/^.*$// # clear pattern space
92+ N; /^\nexecute add.*Map /b next-map
93+94+ # close the string
95+ i\ ];
96+ D # restart cycle from the current line
97+ }
98+99 # detect presence of notable files
100 /^docfiles /{
101 s/^.*$// # ignore the first line
···145 # extract postaction scripts (right now, at most one per package, so a string suffices)
146 s/^postaction script file=(.*)$/ postactionScript = "\1";/p
147148+ # extract hyphenation patterns
149+ /^execute\sAddHyphen\s/{
150+ # open a list
151+ i\ hyphenPatterns = [
152+153+ # create one attribute set per hyphenation pattern
154+155+ # plain keys: name, lefthyphenmin, righthyphenmin, file, file_patterns, file_exceptions, comment
156+ # optionally double quoted key: luaspecial, comment
157+ # comma-separated lists: databases, synonyms
158+ :next-hyphen
159+ s/(^|\n)execute\sAddHyphen/ {/
160+ s/\s+luaspecial="([^"]+)"/\n luaspecial = "\1";/
161+ s/\s+(name|lefthyphenmin|righthyphenmin|file|file_patterns|file_exceptions|luaspecial|comment)=([^ \t\n]*)/\n \1 = "\2";/g
162+ s/\s+(databases|synonyms)=([^ \t\n]+)/\n \1 = [ "\2" ];/g
163+ s/$/\n }/
164+165+ :split-hyphens
166+ s/"([^,]+),([^"]+)" ]/"\1" "\2" ]/;
167+ t split-hyphens # repeat until there are no commas
168+169+ p
170+ s/^.*$// # clear pattern space
171+ N
172+ /^\nexecute\sAddHyphen\s/b next-hyphen
173+174+ # close the list
175+ i\ ];
176+ D # restart cycle from the current line
177+ }
178179 # extract format details
180 /^execute\sAddFormat\s/{