mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-29 10:23:29 +00:00
texlive.withPackages: replace postBuild with install-tl like script
This commit is contained in:
parent
ea6ca290e2
commit
10989de86c
@ -38,6 +38,12 @@ lib.fix (self: {
|
||||
}@args:
|
||||
|
||||
let
|
||||
### buildEnv with custom attributes
|
||||
buildEnv' = args: (buildEnv
|
||||
({ inherit (args) name paths; })
|
||||
// lib.optionalAttrs (args ? extraOutputsToInstall) { inherit (args) extraOutputsToInstall; })
|
||||
.overrideAttrs (removeAttrs args [ "extraOutputsToInstall" "name" "paths" "pkgs" ]);
|
||||
|
||||
### texlive.combine backward compatibility
|
||||
# if necessary, convert old style { pkgs = [ ... ]; } packages to attribute sets
|
||||
isOldPkgList = p: ! p.outputSpecified or false && p ? pkgs && builtins.all (p: p ? tlType) p.pkgs;
|
||||
@ -78,7 +84,7 @@ let
|
||||
otherOutputs = lib.genAttrs otherOutputNames (n: builtins.catAttrs n specified.wrong);
|
||||
outputsToInstall = builtins.catAttrs "key" (builtins.genericClosure {
|
||||
startSet = map (key: { inherit key; })
|
||||
([ "out" ] ++ lib.optional (splitOutputs ? man) "man"
|
||||
([ "out" ] ++ lib.optional (otherOutputs ? man) "man"
|
||||
++ lib.concatLists (builtins.catAttrs "outputsToInstall" (builtins.catAttrs "meta" specified.wrong)));
|
||||
operator = _: [ ];
|
||||
});
|
||||
@ -103,6 +109,14 @@ let
|
||||
|
||||
# outputs that do not become part of the environment
|
||||
nonEnvOutputs = lib.subtractLists [ "out" "tex" "texdoc" "texsource" "tlpkg" ] otherOutputNames;
|
||||
|
||||
# packages that contribute to config files and formats
|
||||
fontMaps = lib.filter (p: p ? fontMaps && (p.tlOutputName or p.outputName == "tex")) nonbin;
|
||||
sortedFontMaps = builtins.sort (a: b: a.pname < b.pname) fontMaps;
|
||||
hyphenPatterns = lib.filter (p: p ? hyphenPatterns && (p.tlOutputName or p.outputName == "tex")) nonbin;
|
||||
sortedHyphenPatterns = builtins.sort (a: b: a.pname < b.pname) hyphenPatterns;
|
||||
formatPkgs = lib.filter (p: p ? formats && (p.outputSpecified or false -> p.tlOutputName or p.outputName == "tex") && builtins.any (f: f.enabled or true) p.formats) all;
|
||||
sortedFormatPkgs = builtins.sort (a: b: a.pname < b.pname) formatPkgs;
|
||||
};
|
||||
|
||||
# list generated by inspecting `grep -IR '\([^a-zA-Z]\|^\)gs\( \|$\|"\)' "$TEXMFDIST"/scripts`
|
||||
@ -113,7 +127,7 @@ let
|
||||
name = if __combine then "texlive-${__extraName}-${bin.texliveYear}${__extraVersion}" # texlive.combine: old name name
|
||||
else "texlive-${bin.texliveYear}-env";
|
||||
|
||||
texmfdist = (buildEnv {
|
||||
texmfdist = buildEnv' {
|
||||
name = "${name}-texmfdist";
|
||||
|
||||
# remove fake derivations (without 'outPath') to avoid undesired build dependencies
|
||||
@ -126,14 +140,14 @@ let
|
||||
''
|
||||
mktexlsr "$out"
|
||||
'';
|
||||
}).overrideAttrs (_: { allowSubstitutes = true; });
|
||||
};
|
||||
|
||||
tlpkg = (buildEnv {
|
||||
tlpkg = buildEnv {
|
||||
name = "${name}-tlpkg";
|
||||
|
||||
# remove fake derivations (without 'outPath') to avoid undesired build dependencies
|
||||
paths = builtins.catAttrs "outPath" pkgList.tlpkg;
|
||||
}).overrideAttrs (_: { allowSubstitutes = true; });
|
||||
};
|
||||
|
||||
# the 'non-relocated' packages must live in $TEXMFROOT/texmf-dist
|
||||
# and sometimes look into $TEXMFROOT/tlpkg (notably fmtutil, updmap look for perl modules in both)
|
||||
@ -170,12 +184,10 @@ let
|
||||
(requiredTeXPackages tl);
|
||||
};
|
||||
|
||||
# emulate split output derivation
|
||||
splitOutputs = {
|
||||
texmfdist = texmfdist // { outputSpecified = true; };
|
||||
texmfroot = texmfroot // { outputSpecified = true; };
|
||||
} // (lib.genAttrs pkgList.nonEnvOutputs (outName: (buildEnv {
|
||||
# other outputs
|
||||
nonEnvOutputs = lib.genAttrs pkgList.nonEnvOutputs (outName: buildEnv' {
|
||||
inherit name;
|
||||
outputs = [ outName ];
|
||||
paths = builtins.catAttrs "outPath"
|
||||
(pkgList.otherOutputs.${outName} or [ ] ++ pkgList.specifiedOutputs.${outName} or [ ]);
|
||||
# force the output to be ${outName} or nix-env will not work
|
||||
@ -183,11 +195,9 @@ let
|
||||
export out="''${${outName}-}"
|
||||
'') ];
|
||||
inherit meta passthru;
|
||||
}).overrideAttrs { outputs = [ outName ]; } // { outputSpecified = true; }));
|
||||
});
|
||||
|
||||
passthru = {
|
||||
# these are not part of pkgList.nonEnvOutputs and must be exported in passthru
|
||||
inherit (splitOutputs) texmfdist texmfroot;
|
||||
# This is set primarily to help find-tarballs.nix to do its job
|
||||
requiredTeXPackages = builtins.filter lib.isDerivation (pkgList.bin ++ pkgList.nonbin
|
||||
++ lib.optionals (! __fromCombineWrapper)
|
||||
@ -201,13 +211,57 @@ let
|
||||
withPackages = reqs: self (args // { requiredTeXPackages = ps: requiredTeXPackages ps ++ reqs ps; __fromCombineWrapper = false; });
|
||||
};
|
||||
|
||||
# TeXLive::TLOBJ::fmtutil_cnf_lines
|
||||
fmtutilLine = { name, engine, enabled ? true, patterns ? [ "-" ], options ? "", ... }:
|
||||
lib.optionalString (! enabled) "#! " + "${name} ${engine} ${lib.concatStringsSep "," patterns} ${options}";
|
||||
fmtutilLines = { pname, formats, ...}:
|
||||
[ "#" "# from ${pname}:" ] ++ map fmtutilLine formats;
|
||||
|
||||
# TeXLive::TLOBJ::language_dat_lines
|
||||
langDatLine = { name, file, synonyms ? [ ], ... }:
|
||||
[ "${name} ${file}" ] ++ map (s: "=" + s) synonyms;
|
||||
langDatLines = { pname, hyphenPatterns, ... }:
|
||||
[ "% from ${pname}:" ] ++ builtins.concatMap langDatLine hyphenPatterns;
|
||||
|
||||
# TeXLive::TLOBJ::language_def_lines
|
||||
# see TeXLive::TLUtils::parse_AddHyphen_line for default values
|
||||
langDefLine = { name, file, lefthyphenmin ? "", righthyphenmin ? "", synonyms ? [ ], ... }:
|
||||
map (n: "\\addlanguage{${n}}{${file}}{}{${if lefthyphenmin == "" then "2" else lefthyphenmin}}{${if righthyphenmin == "" then "3" else righthyphenmin}}")
|
||||
([ name ] ++ synonyms);
|
||||
langDefLines = { pname, hyphenPatterns, ... }:
|
||||
[ "% from ${pname}:" ] ++ builtins.concatMap langDefLine hyphenPatterns;
|
||||
|
||||
# TeXLive::TLOBJ::language_lua_lines
|
||||
# see TeXLive::TLUtils::parse_AddHyphen_line for default values
|
||||
langLuaLine = { name, file, lefthyphenmin ? "", righthyphenmin ? "", synonyms ? [ ], ... }@args: ''
|
||||
''\t['${name}'] = {
|
||||
''\t''\tloader = '${file}',
|
||||
''\t''\tlefthyphenmin = ${if lefthyphenmin == "" then "2" else lefthyphenmin},
|
||||
''\t''\trighthyphenmin = ${if righthyphenmin == "" then "3" else righthyphenmin},
|
||||
''\t''\tsynonyms = { ${lib.concatStringsSep ", " (map (s: "'${s}'") synonyms)} },
|
||||
''
|
||||
+ lib.optionalString (args ? file_patterns) "\t\tpatterns = '${args.file_patterns}',\n"
|
||||
+ lib.optionalString (args ? file_exceptions) "\t\thyphenation = '${args.file_exceptions}',\n"
|
||||
+ lib.optionalString (args ? luaspecial) "\t\tspecial = '${args.luaspecial}',\n"
|
||||
+ "\t},";
|
||||
langLuaLines = { pname, hyphenPatterns, ... }:
|
||||
[ "-- from ${pname}:" ] ++ map langLuaLine hyphenPatterns;
|
||||
|
||||
assembleConfigLines = f: packages:
|
||||
builtins.concatStringsSep "\n" (builtins.concatMap f packages);
|
||||
|
||||
updmapLines = { pname, fontMaps, ...}:
|
||||
[ "# from ${pname}:" ] ++ fontMaps;
|
||||
|
||||
out =
|
||||
# no indent for git diff purposes
|
||||
(buildEnv {
|
||||
buildEnv' {
|
||||
|
||||
inherit name;
|
||||
|
||||
ignoreCollisions = false;
|
||||
# use attrNames, attrValues to ensure the two lists are sorted in the same way
|
||||
outputs = [ "out" ] ++ lib.optionals (! __combine) (builtins.attrNames nonEnvOutputs);
|
||||
otherOutputs = lib.optionals (! __combine) (builtins.attrValues nonEnvOutputs);
|
||||
|
||||
# remove fake derivations (without 'outPath') to avoid undesired build dependencies
|
||||
paths = builtins.catAttrs "outPath" pkgList.bin
|
||||
@ -230,219 +284,26 @@ let
|
||||
perl
|
||||
];
|
||||
|
||||
buildInputs = [ coreutils gawk gnugrep gnused ] ++ lib.optional needsGhostscript ghostscript;
|
||||
|
||||
inherit meta passthru;
|
||||
|
||||
postBuild =
|
||||
# create outputs
|
||||
lib.optionalString (! __combine) ''
|
||||
for otherOutputName in $outputs ; do
|
||||
if [[ "$otherOutputName" == 'out' ]] ; then continue ; fi
|
||||
otherOutput="otherOutput_$otherOutputName"
|
||||
ln -s "''${!otherOutput}" "''${!otherOutputName}"
|
||||
done
|
||||
'' +
|
||||
# environment variables (note: only export the ones that are used in the wrappers)
|
||||
''
|
||||
TEXMFROOT="${texmfroot}"
|
||||
TEXMFDIST="${texmfdist}"
|
||||
export PATH="$out/bin:$PATH"
|
||||
TEXMFSYSCONFIG="$out/share/texmf-config"
|
||||
TEXMFSYSVAR="$out/share/texmf-var"
|
||||
export TEXMFCNF="$TEXMFSYSVAR/web2c"
|
||||
'' +
|
||||
# wrap executables with required env vars as early as possible
|
||||
# 1. we use the wrapped binaries in the scripts below, to catch bugs
|
||||
# 2. we do not want to wrap links generated by texlinks
|
||||
''
|
||||
enable -f '${bash}/lib/bash/realpath' realpath
|
||||
declare -i wrapCount=0
|
||||
for link in "$out"/bin/*; do
|
||||
target="$(realpath "$link")"
|
||||
if [[ "''${target##*/}" != "''${link##*/}" ]] ; then
|
||||
# detected alias with different basename, use immediate target of $link to preserve $0
|
||||
# relevant for mktexfmt, repstopdf, ...
|
||||
target="$(readlink "$link")"
|
||||
fi
|
||||
inherit texmfdist texmfroot;
|
||||
|
||||
# skip non-executable files (such as context.lua)
|
||||
if [[ ! -x "$target" ]] ; then continue ; fi
|
||||
fontconfigFile = makeFontsConf { fontDirectories = [ "${texmfroot}/texmf-dist/fonts" ]; };
|
||||
|
||||
rm "$link"
|
||||
makeWrapper "$target" "$link" \
|
||||
--inherit-argv0 \
|
||||
--prefix PATH : "${
|
||||
# very common dependencies that are not detected by tests.texlive.binaries
|
||||
lib.makeBinPath ([ coreutils gawk gnugrep gnused ] ++ lib.optional needsGhostscript ghostscript)}:$out/bin" \
|
||||
--set-default TEXMFCNF "$TEXMFCNF" \
|
||||
--set-default FONTCONFIG_FILE "${
|
||||
# necessary for XeTeX to find the fonts distributed with texlive
|
||||
makeFontsConf { fontDirectories = [ "${texmfroot}/texmf-dist/fonts" ]; }
|
||||
}"
|
||||
wrapCount=$((wrapCount + 1))
|
||||
done
|
||||
echo "wrapped $wrapCount binaries and scripts"
|
||||
'' +
|
||||
# patch texmf-dist -> $TEXMFDIST
|
||||
# patch texmf-local -> $out/share/texmf-local
|
||||
# patch texmf.cnf -> $TEXMFSYSVAR/web2c/texmf.cnf
|
||||
# TODO: perhaps do lua actions?
|
||||
# tried inspiration from install-tl, sub do_texmf_cnf
|
||||
''
|
||||
mkdir -p "$TEXMFCNF"
|
||||
if [ -e "$TEXMFDIST/web2c/texmfcnf.lua" ]; then
|
||||
sed \
|
||||
-e "s,\(TEXMFOS[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFROOT\",g" \
|
||||
-e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFDIST\",g" \
|
||||
-e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSVAR\",g" \
|
||||
-e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSCONFIG\",g" \
|
||||
-e "s,\(TEXMFLOCAL[ ]*=[ ]*\)[^\,]*,\1\"$out/share/texmf-local\",g" \
|
||||
-e "s,\$SELFAUTOLOC,$out,g" \
|
||||
-e "s,selfautodir:/,$out/share/,g" \
|
||||
-e "s,selfautodir:,$out/share/,g" \
|
||||
-e "s,selfautoparent:/,$out/share/,g" \
|
||||
-e "s,selfautoparent:,$out/share/,g" \
|
||||
"$TEXMFDIST/web2c/texmfcnf.lua" > "$TEXMFCNF/texmfcnf.lua"
|
||||
fi
|
||||
fmtutilCnf = assembleConfigLines fmtutilLines pkgList.sortedFormatPkgs;
|
||||
updmapCfg = assembleConfigLines updmapLines pkgList.sortedFontMaps;
|
||||
|
||||
sed \
|
||||
-e "s,\(TEXMFROOT[ ]*=[ ]*\)[^\,]*,\1$TEXMFROOT,g" \
|
||||
-e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1$TEXMFDIST,g" \
|
||||
-e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSVAR,g" \
|
||||
-e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSCONFIG,g" \
|
||||
-e "s,\$SELFAUTOLOC,$out,g" \
|
||||
-e "s,\$SELFAUTODIR,$out/share,g" \
|
||||
-e "s,\$SELFAUTOPARENT,$out/share,g" \
|
||||
-e "s,\$SELFAUTOGRANDPARENT,$out/share,g" \
|
||||
-e "/^mpost,/d" `# CVE-2016-10243` \
|
||||
"$TEXMFDIST/web2c/texmf.cnf" > "$TEXMFCNF/texmf.cnf"
|
||||
'' +
|
||||
# now filter hyphenation patterns and formats
|
||||
(let
|
||||
hyphens = lib.filter (p: p ? hyphenPatterns && p.tlOutputName or p.outputName == "tex") pkgList.nonbin;
|
||||
hyphenPNames = map (p: p.pname) hyphens;
|
||||
formats = lib.filter (p: p ? formats && p.tlOutputName or p.outputName == "tex") pkgList.nonbin;
|
||||
formatPNames = map (p: p.pname) formats;
|
||||
# sed expression that prints the lines in /start/,/end/ except for /end/
|
||||
section = start: end: "/${start}/,/${end}/{ /${start}/p; /${end}/!p; };\n";
|
||||
script =
|
||||
writeText "hyphens.sed" (
|
||||
# document how the file was generated (for language.dat)
|
||||
"1{ s/^(% Generated by .*)$/\\1, modified by ${if __combine then "texlive.combine" else "Nixpkgs"}/; p; }\n"
|
||||
# pick up the header
|
||||
+ "2,/^% from/{ /^% from/!p; };\n"
|
||||
# pick up all sections matching packages that we combine
|
||||
+ lib.concatMapStrings (pname: section "^% from ${pname}:$" "^% from|^%%% No changes may be made beyond this point.$") hyphenPNames
|
||||
# pick up the footer (for language.def)
|
||||
+ "/^%%% No changes may be made beyond this point.$/,$p;\n"
|
||||
);
|
||||
scriptLua =
|
||||
writeText "hyphens.lua.sed" (
|
||||
"1{ s/^(-- Generated by .*)$/\\1, modified by ${if __combine then "texlive.combine" else "Nixpkgs"}/; p; }\n"
|
||||
+ "2,/^-- END of language.us.lua/p;\n"
|
||||
+ lib.concatMapStrings (pname: section "^-- from ${pname}:$" "^}$|^-- from") hyphenPNames
|
||||
+ "$p;\n"
|
||||
);
|
||||
# formats not being installed must be disabled by prepending #! (see man fmtutil)
|
||||
# sed expression that enables the formats in /start/,/end/
|
||||
enableFormats = pname: "/^# from ${pname}:$/,/^# from/{ s/^#! //; };\n";
|
||||
fmtutilSed =
|
||||
writeText "fmtutil.sed" (
|
||||
# document how file was generated
|
||||
"1{ s/^(# Generated by .*)$/\\1, modified by ${if __combine then "texlive.combine" else "Nixpkgs"}/; }\n"
|
||||
# disable all formats, even those already disabled
|
||||
+ "s/^([^#]|#! )/#! \\1/;\n"
|
||||
# enable the formats from the packages being installed
|
||||
+ lib.concatMapStrings enableFormats formatPNames
|
||||
# clean up formats that have been disabled twice
|
||||
+ "s/^#! #! /#! /;\n"
|
||||
);
|
||||
in ''
|
||||
mkdir -p "$TEXMFSYSVAR/tex/generic/config"
|
||||
for fname in tex/generic/config/language.{dat,def}; do
|
||||
[[ -e "$TEXMFDIST/$fname" ]] && sed -E -n -f '${script}' "$TEXMFDIST/$fname" > "$TEXMFSYSVAR/$fname"
|
||||
done
|
||||
[[ -e "$TEXMFDIST"/tex/generic/config/language.dat.lua ]] && sed -E -n -f '${scriptLua}' \
|
||||
"$TEXMFDIST"/tex/generic/config/language.dat.lua > "$TEXMFSYSVAR"/tex/generic/config/language.dat.lua
|
||||
[[ -e "$TEXMFDIST"/web2c/fmtutil.cnf ]] && sed -E -f '${fmtutilSed}' "$TEXMFDIST"/web2c/fmtutil.cnf > "$TEXMFCNF"/fmtutil.cnf
|
||||
languageDat = assembleConfigLines langDatLines pkgList.sortedHyphenPatterns;
|
||||
languageDef = assembleConfigLines langDefLines pkgList.sortedHyphenPatterns;
|
||||
languageLua = assembleConfigLines langLuaLines pkgList.sortedHyphenPatterns;
|
||||
|
||||
# create $TEXMFSYSCONFIG database, make new $TEXMFSYSVAR files visible to kpathsea
|
||||
mktexlsr "$TEXMFSYSCONFIG" "$TEXMFSYSVAR"
|
||||
'') +
|
||||
# generate format links (reads fmtutil.cnf to know which ones) *after* the wrappers have been generated
|
||||
''
|
||||
texlinks --quiet "$out/bin"
|
||||
'' +
|
||||
# temporarily patch mtxrun.lua to generate uuid's deterministically from SOURCE_DATE_EPOCH
|
||||
''
|
||||
if [[ -e "$out/bin/mtxrun" ]]; then
|
||||
mv "$out"/bin/mtxrun.lua{,.orig}
|
||||
substitute "$TEXMFDIST"/scripts/context/lua/mtxrun.lua "$out"/bin/mtxrun.lua \
|
||||
--replace-fail 'randomseed(math.initialseed)' "randomseed($SOURCE_DATE_EPOCH)"
|
||||
fi
|
||||
'' +
|
||||
# texlive postactions (see TeXLive::TLUtils::_do_postaction_script)
|
||||
# this step includes generating the ConTeXt file databases since TL 2023
|
||||
(lib.concatMapStrings (pkg: ''
|
||||
postaction='${pkg.postactionScript}'
|
||||
case "$postaction" in
|
||||
*.pl) postInterp=perl ;;
|
||||
*.texlua) postInterp=texlua ;;
|
||||
*) postInterp= ;;
|
||||
esac
|
||||
echo "postaction install script for ${pkg.pname}: ''${postInterp:+$postInterp }$postaction install $TEXMFROOT"
|
||||
FORCE_SOURCE_DATE=1 TZ= $postInterp "$TEXMFROOT"/$postaction install "$TEXMFROOT"
|
||||
'') (lib.filter (pkg: pkg ? postactionScript) pkgList.tlpkg)) +
|
||||
# restore the original mtxrun.lua
|
||||
''
|
||||
if [[ -e "$out/bin/mtxrun" ]]; then
|
||||
mv "$out"/bin/mtxrun.lua{.orig,}
|
||||
fi
|
||||
'' +
|
||||
# generate formats
|
||||
# TODO generate ConTeXt formats (based on fmtutil.cnf?)
|
||||
''
|
||||
# many formats still ignore SOURCE_DATE_EPOCH even when FORCE_SOURCE_DATE=1
|
||||
# libfaketime fixes non-determinism related to timestamps ignoring FORCE_SOURCE_DATE
|
||||
# we cannot fix further randomness caused by luatex; for further details, see
|
||||
# https://salsa.debian.org/live-team/live-build/-/blob/master/examples/hooks/reproducible/2006-reproducible-texlive-binaries-fmt-files.hook.chroot#L52
|
||||
# note that calling faketime and fmtutil is fragile (faketime uses LD_PRELOAD, fmtutil calls /bin/sh, causing potential glibc issues on non-NixOS)
|
||||
# so we patch fmtutil to use faketime, rather than calling faketime fmtutil
|
||||
substitute "$TEXMFDIST"/scripts/texlive/fmtutil.pl fmtutil \
|
||||
--replace-fail 'my $cmdline = "$eng -ini ' 'my $cmdline = "faketime -f '"'"'\@1980-01-01 00:00:00 x0.001'"'"' $eng -ini '
|
||||
FORCE_SOURCE_DATE=1 TZ= perl fmtutil --sys --all | grep '^fmtutil' # too verbose
|
||||
postactionScripts = builtins.catAttrs "postactionScript" pkgList.tlpkg;
|
||||
|
||||
# Disable unavailable map files
|
||||
echo y | updmap --sys --syncwithtrees --force 2>&1 | grep '^\(updmap\| /\)'
|
||||
# Regenerate the map files (this is optional)
|
||||
updmap --sys --force 2>&1 | grep '^\(updmap\| /\)'
|
||||
|
||||
# sort entries to improve reproducibility
|
||||
[[ -f "$TEXMFSYSCONFIG"/web2c/updmap.cfg ]] && sort -o "$TEXMFSYSCONFIG"/web2c/updmap.cfg "$TEXMFSYSCONFIG"/web2c/updmap.cfg
|
||||
|
||||
mktexlsr "$TEXMFSYSCONFIG" "$TEXMFSYSVAR" # to make sure (of what?)
|
||||
'' +
|
||||
# remove *-sys scripts since /nix/store is readonly
|
||||
''
|
||||
rm "$out"/bin/*-sys
|
||||
'' +
|
||||
# Get rid of all log files. They are not needed, but take up space
|
||||
# and render the build unreproducible by their embedded timestamps
|
||||
# and other non-deterministic diagnostics.
|
||||
''
|
||||
find "$TEXMFSYSVAR"/web2c -name '*.log' -delete
|
||||
'' +
|
||||
# link TEXMFDIST in $out/share for backward compatibility
|
||||
''
|
||||
ln -s "$TEXMFDIST" "$out"/share/texmf
|
||||
''
|
||||
;
|
||||
}).overrideAttrs (prev:
|
||||
{ allowSubstitutes = true; }
|
||||
// lib.optionalAttrs (! __combine) ({
|
||||
outputs = [ "out" ] ++ pkgList.nonEnvOutputs;
|
||||
meta = prev.meta // { inherit (pkgList) outputsToInstall; };
|
||||
} // builtins.listToAttrs
|
||||
(map (out: { name = "otherOutput_" + out; value = splitOutputs.${out}; }) pkgList.nonEnvOutputs)
|
||||
)
|
||||
);
|
||||
in out)
|
||||
postBuild = ''
|
||||
. "${./build-tex-env.sh}"
|
||||
'';
|
||||
};
|
||||
# outputsToInstall must be set *after* overrideAttrs (used in buildEnv') or it fails the checkMeta tests
|
||||
in if __combine then out else lib.addMetaAttrs { inherit (pkgList) outputsToInstall; } out)
|
||||
|
328
pkgs/tools/typesetting/tex/texlive/build-tex-env.sh
Normal file
328
pkgs/tools/typesetting/tex/texlive/build-tex-env.sh
Normal file
@ -0,0 +1,328 @@
|
||||
# shellcheck shell=bash
|
||||
|
||||
# Replicate the post install phase of the upstream TeX Live installer.
|
||||
#
|
||||
# This script is based on the install-tl script and the TeXLive::TLUtils perl
|
||||
# module, down to using the same (prefixed) function names and log messages.
|
||||
#
|
||||
# When updating to the next TeX Live release, review install-tl for changes and
|
||||
# update this script accordingly.
|
||||
|
||||
### install-tl
|
||||
|
||||
# adjust texmf.cnf and texmfcnf.lua
|
||||
installtl_do_texmf_cnf () {
|
||||
# unlike install-tl, we make a copy of the entire texmf.cnf
|
||||
# and point the binaries at $TEXMFCNF/texmf.cnf via wrappers
|
||||
|
||||
mkdir -p "$TEXMFCNF"
|
||||
if [[ -e $texmfdist/web2c/texmfcnf.lua ]]; then
|
||||
tlutils_info "writing texmfcnf.lua to $TEXMFCNF/texmfcnf.lua"
|
||||
sed -e "s,\(TEXMFOS[ ]*=[ ]*\)[^\,]*,\1\"$texmfroot\",g" \
|
||||
-e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1\"$texmfdist\",g" \
|
||||
-e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSVAR\",g" \
|
||||
-e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1\"$TEXMFSYSCONFIG\",g" \
|
||||
-e "s,\(TEXMFLOCAL[ ]*=[ ]*\)[^\,]*,\1\"$out/share/texmf-local\",g" \
|
||||
-e "s,\$SELFAUTOLOC,$out,g" \
|
||||
-e "s,selfautodir:/,$out/share/,g" \
|
||||
-e "s,selfautodir:,$out/share/,g" \
|
||||
-e "s,selfautoparent:/,$out/share/,g" \
|
||||
-e "s,selfautoparent:,$out/share/,g" \
|
||||
"$texmfdist/web2c/texmfcnf.lua" > "$TEXMFCNF/texmfcnf.lua"
|
||||
fi
|
||||
|
||||
tlutils_info "writing texmf.cnf to $TEXMFCNF/texmf.cnf"
|
||||
sed -e "s,\(TEXMFROOT[ ]*=[ ]*\)[^\,]*,\1$texmfroot,g" \
|
||||
-e "s,\(TEXMFDIST[ ]*=[ ]*\)[^\,]*,\1$texmfdist,g" \
|
||||
-e "s,\(TEXMFSYSVAR[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSVAR,g" \
|
||||
-e "s,\(TEXMFSYSCONFIG[ ]*=[ ]*\)[^\,]*,\1$TEXMFSYSCONFIG,g" \
|
||||
-e "s,\$SELFAUTOLOC,$out,g" \
|
||||
-e "s,\$SELFAUTODIR,$out/share,g" \
|
||||
-e "s,\$SELFAUTOPARENT,$out/share,g" \
|
||||
-e "s,\$SELFAUTOGRANDPARENT,$out/share,g" \
|
||||
"$texmfdist/web2c/texmf.cnf" > "$TEXMFCNF/texmf.cnf"
|
||||
}
|
||||
|
||||
# run postaction scripts from texlive.tlpdb
|
||||
# note that the other postactions (fileassoc, ...) are Windows only
|
||||
installtl_do_tlpdb_postactions () {
|
||||
local postaction postInterp
|
||||
if [[ -n $postactionScripts ]] ; then
|
||||
tlutils_info "running package-specific postactions"
|
||||
for postaction in $postactionScripts ; do
|
||||
# see TeXLive::TLUtils::_installtl_do_postaction_script
|
||||
case "$postaction" in
|
||||
*.pl)
|
||||
postInterp=perl ;;
|
||||
*.texlua)
|
||||
postInterp=texlua ;;
|
||||
*)
|
||||
postInterp= ;;
|
||||
esac
|
||||
tlutils_info "${postInterp:+$postInterp }$postaction install $texmfroot"
|
||||
FORCE_SOURCE_DATE=1 $postInterp "$texmfroot/$postaction" install "$texmfroot" >>"$TEXMFSYSVAR/postaction-${postaction##*/}.log"
|
||||
done
|
||||
tlutils_info "finished with package-specific postactions"
|
||||
fi
|
||||
}
|
||||
|
||||
installtl_do_path_adjustments () {
|
||||
# here install-tl would add a system symlink to the man pages
|
||||
# instead we run other nixpkgs related adjustments
|
||||
|
||||
# generate wrappers
|
||||
tlutils_info "wrapping binaries"
|
||||
|
||||
local bash cmd extraPaths link path target wrapCount
|
||||
bash="$(command -v bash)"
|
||||
enable -f "${bash%/bin/bash}"/lib/bash/realpath realpath
|
||||
|
||||
# common runtime dependencies
|
||||
for cmd in cat awk sed grep gs ; do
|
||||
# do not fail if gs is absent
|
||||
path="$(PATH="$HOST_PATH" command -v "$cmd" || :)"
|
||||
if [[ -n $path ]] ; then
|
||||
extraPaths="${extraPaths:+$extraPaths:}${path%/"$cmd"}"
|
||||
fi
|
||||
done
|
||||
|
||||
declare -i wrapCount=0
|
||||
for link in "$out"/bin/* ; do
|
||||
target="$(realpath "$link")"
|
||||
|
||||
# skip non-executable files (such as context.lua)
|
||||
if [[ ! -x $target ]] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ ${target##*/} != "${link##*/}" ]] ; then
|
||||
# detected alias with different basename, use immediate target of $link to preserve $0
|
||||
# relevant for mktexfmt, repstopdf, ...
|
||||
target="$(readlink "$link")"
|
||||
fi
|
||||
|
||||
rm "$link"
|
||||
makeWrapper "$target" "$link" \
|
||||
--inherit-argv0 \
|
||||
--prefix PATH : "$extraPaths:$out/bin" \
|
||||
--set-default TEXMFCNF "$TEXMFCNF" \
|
||||
--set-default FONTCONFIG_FILE "$fontconfigFile"
|
||||
wrapCount=$((wrapCount + 1))
|
||||
done
|
||||
|
||||
tlutils_info "wrapped $wrapCount binaries and scripts"
|
||||
|
||||
# generate format symlinks (using fmtutil.cnf)
|
||||
tlutils_info "generating format symlinks"
|
||||
texlinks --quiet "$out/bin"
|
||||
|
||||
# remove *-sys scripts since /nix/store is readonly
|
||||
rm "$out"/bin/*-sys
|
||||
|
||||
# link TEXMFDIST in $out/share for backward compatibility
|
||||
ln -s "$texmfdist" "$out"/share/texmf
|
||||
|
||||
# generate other outputs
|
||||
local otherOutput otherOutputName
|
||||
local otherOutputs="$otherOutputs"
|
||||
for otherOutputName in $outputs ; do
|
||||
if [[ $otherOutputName == out ]] ; then
|
||||
continue
|
||||
fi
|
||||
otherOutput="${otherOutputs%% *}"
|
||||
otherOutputs="${otherOutputs#* }"
|
||||
ln -s "$otherOutput" "${!otherOutputName}"
|
||||
done
|
||||
}
|
||||
|
||||
# run all post install parts
|
||||
installtl_do_postinst_stuff () {
|
||||
installtl_do_texmf_cnf
|
||||
|
||||
# create various config files
|
||||
# in principle, we could use writeText and share them across different
|
||||
# environments, but the eval & build overhead is not worth the savings
|
||||
tlutils_create_fmtutil
|
||||
tlutils_create_updmap
|
||||
tlutils_create_language_dat
|
||||
tlutils_create_language_def
|
||||
tlutils_create_language_lua
|
||||
|
||||
# make new files available
|
||||
tlutils_info "running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
|
||||
mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
|
||||
|
||||
# update font maps
|
||||
tlutils_info "generating font maps"
|
||||
updmap-sys --quiet --force --nohash 2>&1
|
||||
# configure the paper size
|
||||
# tlmgr --no-execute-actions paper letter
|
||||
# install-tl: "rerun mktexlsr for updmap-sys and tlmgr paper updates"
|
||||
tlutils_info "re-running mktexlsr $TEXMFSYSVAR $TEXMFSYSCONFIG"
|
||||
mktexlsr "$TEXMFSYSVAR" "$TEXMFSYSCONFIG"
|
||||
|
||||
tlutils_update_context_cache
|
||||
|
||||
# generate formats
|
||||
# install-tl would run fmtutil-sys $common_fmtutil_args --no-strict --all
|
||||
# instead, we want fmtutil to exit with error on failure
|
||||
if [[ -n $fmtutilCnf ]] ; then
|
||||
tlutils_info "pre-generating all format files, be patient..."
|
||||
# many formats still ignore SOURCE_DATE_EPOCH even when FORCE_SOURCE_DATE=1
|
||||
# libfaketime fixes non-determinism related to timestamps ignoring FORCE_SOURCE_DATE
|
||||
# we cannot fix further randomness caused by luatex; for further details, see
|
||||
# https://salsa.debian.org/live-team/live-build/-/blob/master/examples/hooks/reproducible/2006-reproducible-texlive-binaries-fmt-files.hook.chroot#L52
|
||||
# note that calling faketime and fmtutil is fragile (faketime uses LD_PRELOAD, fmtutil calls /bin/sh, causing potential glibc issues on non-NixOS)
|
||||
# so we patch fmtutil to use faketime, rather than calling faketime fmtutil
|
||||
substitute "$texmfdist"/scripts/texlive/fmtutil.pl fmtutil \
|
||||
--replace-fail "my \$cmdline = \"\$eng -ini " "my \$cmdline = \"faketime -f '\@$(date +'%F %T' --date=@"$SOURCE_DATE_EPOCH") x0.001' \$eng -ini "
|
||||
FORCE_SOURCE_DATE=1 perl fmtutil --quiet --strict --sys --all 2>&1 | grep '^fmtutil' # too verbose
|
||||
fi
|
||||
|
||||
installtl_do_path_adjustments
|
||||
|
||||
installtl_do_tlpdb_postactions
|
||||
|
||||
# remove log files to improve reproducibility
|
||||
find "$TEXMFSYSVAR" -name '*.log' -delete
|
||||
}
|
||||
|
||||
### TeXLive::TLUtils
|
||||
|
||||
tlutils_info () {
|
||||
printf '%s\n' "texlive: $*"
|
||||
}
|
||||
|
||||
tlutils_create_fmtutil () {
|
||||
# fmtutil.cnf created by install-tl already exists readonly in $texmfdist
|
||||
# so here we need to *disable* the entries that are not in $fmtutilCnf
|
||||
# and write the output in the writeable $TEXMFSYSVAR
|
||||
|
||||
local engine fmt line outFile sedExpr
|
||||
outFile="$TEXMFSYSVAR"/web2c/fmtutil.cnf
|
||||
|
||||
tlutils_info "writing fmtutil.cnf to $outFile"
|
||||
|
||||
while IFS= read -r line ; do
|
||||
# a line is 'fmt engine ...' or '#! fmt engine ...'
|
||||
# (see fmtutil.pl::read_fmtutil_file)
|
||||
line="${line#\#! }"
|
||||
read -r fmt engine _ <<<"$line"
|
||||
# if a line for the ($fmt,$engine) pair exists, remove it to avoid
|
||||
# pointless warnings from fmtutil
|
||||
sedExpr="$sedExpr /^(#! )?$fmt $engine /d;"
|
||||
done <<<"$fmtutilCnf"
|
||||
|
||||
# disable all the remaining formats
|
||||
sedExpr="$sedExpr /^[^#]/{ s/^/#! /p };"
|
||||
|
||||
{
|
||||
echo "# Generated by nixpkgs"
|
||||
sed -E -n -e "$sedExpr" "$texmfdist"/web2c/fmtutil.cnf
|
||||
[[ -z $fmtutilCnf ]] || printf '%s' "$fmtutilCnf"
|
||||
} >"$outFile"
|
||||
}
|
||||
|
||||
tlutils_create_updmap () {
|
||||
# updmap.cfg created by install-tl already exists readonly in $texmfdist
|
||||
# so here we need to *disable* the entries that are not in $updmapCfg
|
||||
# and write the output in the writeable $TEXMFSYSVAR
|
||||
|
||||
local line map outFile sedExpr
|
||||
outFile="$TEXMFSYSVAR"/web2c/updmap.cfg
|
||||
|
||||
tlutils_info "writing updmap.cfg to $outFile"
|
||||
|
||||
while IFS= read -r line ; do
|
||||
# a line is 'type map' or '#! type map'
|
||||
# (see fmtutil.pl::read_updmap_file)
|
||||
read -r _ map <<<"$line"
|
||||
# if a line for $map exists, remove it to avoid
|
||||
# pointless warnings from updmap
|
||||
sedExpr="$sedExpr /^(#! )?[^ ]*Map $map$/d;"
|
||||
done <<<"$updmapCfg"
|
||||
|
||||
# disable all the remaining font maps
|
||||
sedExpr="$sedExpr /^[^ ]*Map/{ s/^/#! /p };"
|
||||
|
||||
{
|
||||
echo "# Generated by nixpkgs"
|
||||
sed -E -n -e "$sedExpr" "$texmfdist"/web2c/updmap.cfg
|
||||
[[ -z $updmapCfg ]] || printf '%s' "$updmapCfg"
|
||||
} >"$outFile"
|
||||
}
|
||||
|
||||
tlutils__create_config_files () {
|
||||
# simplified arguments
|
||||
local header="$1"
|
||||
local dest="$2"
|
||||
local prefix="$3"
|
||||
local lines="$4"
|
||||
local suffix="$5"
|
||||
if [[ -z "$header" || -e "$header" ]] ; then
|
||||
tlutils_info "writing ${dest##*/} to $dest"
|
||||
{
|
||||
[[ -z $prefix ]] || printf '%s\n' "$prefix"
|
||||
[[ ! -e $header ]] || cat "$header"
|
||||
[[ -z $lines ]] || printf '%s\n' "$lines"
|
||||
[[ -z $suffix ]] || printf '%s\n' "$suffix"
|
||||
} >"$dest"
|
||||
fi
|
||||
}
|
||||
|
||||
tlutils_create_language_dat () {
|
||||
tlutils__create_config_files \
|
||||
"$texmfdist"/tex/generic/config/language.us \
|
||||
"$TEXMFSYSVAR"/tex/generic/config/language.dat \
|
||||
'% Generated by nixpkgs' \
|
||||
"$languageDat" \
|
||||
''
|
||||
}
|
||||
|
||||
tlutils_create_language_def () {
|
||||
tlutils__create_config_files \
|
||||
"$texmfdist"/tex/generic/config/language.us.def \
|
||||
"$TEXMFSYSVAR"/tex/generic/config/language.def \
|
||||
'' \
|
||||
"$languageDef" \
|
||||
'%%% No changes may be made beyond this point.
|
||||
|
||||
\uselanguage {USenglish} %%% This MUST be the last line of the file.'
|
||||
}
|
||||
|
||||
tlutils_create_language_lua () {
|
||||
tlutils__create_config_files \
|
||||
"$texmfdist"/tex/generic/config/language.us.lua \
|
||||
"$TEXMFSYSVAR"/tex/generic/config/language.dat.lua \
|
||||
'-- Generated by nixpkgs' \
|
||||
"$languageLua" \
|
||||
'}'
|
||||
}
|
||||
|
||||
tlutils_update_context_cache () {
|
||||
if [[ -x $out/bin/mtxrun ]] ; then
|
||||
tlutils_info "setting up ConTeXt cache"
|
||||
|
||||
# temporarily patch mtxrun.lua to generate uuid's deterministically from SOURCE_DATE_EPOCH
|
||||
mv "$out"/bin/mtxrun.lua{,.orig}
|
||||
substitute "$out"/bin/mtxrun.lua.orig "$out"/bin/mtxrun.lua \
|
||||
--replace-fail 'randomseed(math.initialseed)' "randomseed($SOURCE_DATE_EPOCH)"
|
||||
|
||||
# this is very verbose, save the output for debugging purposes
|
||||
{
|
||||
mtxrun --generate
|
||||
context --luatex --generate
|
||||
[[ ! -x $out/bin/luajittex ]] || context --luajittex --generate
|
||||
} >"$TEXMFSYSVAR"/context-cache.log
|
||||
|
||||
mv "$out"/bin/mtxrun.lua{.orig,}
|
||||
fi
|
||||
}
|
||||
|
||||
# init variables (export only the ones that are used in the wrappers)
|
||||
export PATH="$out/bin:$PATH"
|
||||
TEXMFSYSCONFIG="$out/share/texmf-config"
|
||||
TEXMFSYSVAR="$out/share/texmf-var"
|
||||
export TEXMFCNF="$TEXMFSYSVAR/web2c"
|
||||
|
||||
installtl_do_postinst_stuff
|
Loading…
Reference in New Issue
Block a user