diff options
Diffstat (limited to 'nixpkgs/pkgs/tools/typesetting/tex/texlive/combine.nix')
-rw-r--r-- | nixpkgs/pkgs/tools/typesetting/tex/texlive/combine.nix | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/texlive/combine.nix b/nixpkgs/pkgs/tools/typesetting/tex/texlive/combine.nix new file mode 100644 index 000000000000..a4b0fb99f3e9 --- /dev/null +++ b/nixpkgs/pkgs/tools/typesetting/tex/texlive/combine.nix @@ -0,0 +1,291 @@ +params: with params; +# combine = +args@{ + pkgFilter ? (pkg: pkg.tlType == "run" || pkg.tlType == "bin" || pkg.pname == "core") +, extraName ? "combined", ... +}: +let + pkgSet = removeAttrs args [ "pkgFilter" "extraName" ] // { + # include a fake "core" package + core.pkgs = [ + (bin.core.out // { pname = "core"; tlType = "bin"; }) + (bin.core.doc // { pname = "core"; tlType = "doc"; }) + ]; + }; + pkgList = rec { + all = lib.filter pkgFilter (combinePkgs pkgSet); + splitBin = builtins.partition (p: p.tlType == "bin") all; + bin = mkUniqueOutPaths splitBin.right + ++ lib.optional + (lib.any (p: p.tlType == "run" && p.pname == "pdfcrop") splitBin.wrong) + (lib.getBin ghostscript); + nonbin = mkUniqueOutPaths splitBin.wrong; + + # extra interpreters needed for shebangs, based on 2015 schemes "medium" and "tetex" + # (omitted tk needed in pname == "epspdf", bin/epspdftk) + pkgNeedsPython = pkg: pkg.tlType == "run" && lib.elem pkg.pname + [ "de-macro" "pythontex" "dviasm" "texliveonfly" ]; + pkgNeedsRuby = pkg: pkg.tlType == "run" && pkg.pname == "match-parens"; + extraInputs = + lib.optional (lib.any pkgNeedsPython splitBin.wrong) python + ++ lib.optional (lib.any pkgNeedsRuby splitBin.wrong) ruby; + }; + + # TODO: replace by buitin once it exists + fastUnique = comparator: list: with lib; + let un_adj = l: if length l < 2 then l + else optional (head l != elemAt l 1) (head l) ++ un_adj (tail l); + in un_adj (lib.sort comparator list); + + uniqueStrings = fastUnique (a: b: a < b); + + mkUniqueOutPaths = pkgs: uniqueStrings + (map (p: p.outPath) (builtins.filter lib.isDerivation pkgs)); + +in buildEnv { + name = "texlive-${extraName}-${bin.texliveYear}"; + + extraPrefix = "/share/texmf"; + + ignoreCollisions = false; + paths = pkgList.nonbin; + + buildInputs = [ makeWrapper ] ++ pkgList.extraInputs; + + postBuild = '' + cd "$out" + mkdir -p ./bin + '' + + lib.concatMapStrings + (path: '' + for f in '${path}'/bin/*; do + if [[ -L "$f" ]]; then + cp -d "$f" ./bin/ + else + ln -s "$f" ./bin/ + fi + done + '') + pkgList.bin + + + + # Patch texlinks.sh back to 2015 version; + # otherwise some bin/ links break, e.g. xe(la)tex. + '' + ( + cd "$out/share/texmf/scripts/texlive" + local target="$(readlink texlinks.sh)" + rm texlinks.sh && cp "$target" texlinks.sh + patch --verbose -R texlinks.sh < '${./texlinks.diff}' + ) + '' + + '' + export PATH="$out/bin:$out/share/texmf/scripts/texlive:${perl}/bin:$PATH" + export TEXMFCNF="$out/share/texmf/web2c" + export TEXMFDIST="$out/share/texmf" + export TEXMFSYSCONFIG="$out/share/texmf-config" + export TEXMFSYSVAR="$out/share/texmf-var" + export PERL5LIB="$out/share/texmf/scripts/texlive" + '' + + # patch texmf-dist -> $out/share/texmf + # patch texmf-local -> $out/share/texmf-local + # TODO: perhaps do lua actions? + # tried inspiration from install-tl, sub do_texmf_cnf + '' + patchCnfLua() { + local cnfLua="$1" + + if [ -e "$cnfLua" ]; then + local cnfLuaOrig="$(realpath "$cnfLua")" + rm ./texmfcnf.lua + sed \ + -e 's,texmf-dist,texmf,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" \ + "$cnfLuaOrig" > "$cnfLua" + fi + } + + ( + cd ./share/texmf/web2c/ + local cnfOrig="$(realpath ./texmf.cnf)" + rm ./texmf.cnf + sed \ + -e 's,texmf-dist,texmf,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` \ + "$cnfOrig" > ./texmf.cnf + + patchCnfLua "./texmfcnf.lua" + + mkdir $out/share/texmf-local + ) + '' + + # now filter hyphenation patterns, in a hacky way ATM + (let + pnames = uniqueStrings (map (p: p.pname) pkgList.splitBin.wrong); + script = + writeText "hyphens.sed" ( + # pick up the header + "1,/^% from/p;" + # pick up all sections matching packages that we combine + + lib.concatMapStrings (pname: "/^% from ${pname}:$/,/^%/p;\n") pnames + ); + in '' + ( + cd ./share/texmf/tex/generic/config/ + for fname in language.dat language.def; do + [ -e $fname ] || continue; + cnfOrig="$(realpath ./$fname)" + rm ./$fname + cat "$cnfOrig" | sed -n -f '${script}' > ./$fname + done + ) + '') + + + # function to wrap created executables with required env vars + '' + wrapBin() { + for link in ./bin/*; do + [ -L "$link" -a -x "$link" ] || continue # if not link, assume OK + local target=$(readlink "$link") + + # skip simple local symlinks; mktexfmt in particular + echo "$target" | grep / > /dev/null || continue; + + echo -n "Wrapping '$link'" + rm "$link" + makeWrapper "$target" "$link" \ + --prefix PATH : "$out/bin:${perl}/bin" \ + --prefix PERL5LIB : "$out/share/texmf/scripts/texlive" + + # avoid using non-nix shebang in $target by calling interpreter + if [[ "$(head -c 2 "$target")" = "#!" ]]; then + local cmdline="$(head -n 1 "$target" | sed 's/^\#\! *//;s/ *$//')" + local relative=`basename "$cmdline" | sed 's/^env //' ` + local newInterp=`echo "$relative" | cut -d\ -f1` + local params=`echo "$relative" | cut -d\ -f2- -s` + local newPath="$(type -P "$newInterp")" + if [[ -z "$newPath" ]]; then + echo " Warning: unknown shebang '$cmdline' in '$target'" + continue + fi + echo " and patching shebang '$cmdline'" + sed "s|^exec |exec $newPath $params |" -i "$link" + + elif head -n 1 "$target" | grep -q 'exec perl'; then + # see #24343 for details of the problem + echo " and patching weird perl shebang" + sed "s|^exec |exec '${perl}/bin/perl' -w |" -i "$link" + + else + sed 's|^exec |exec -a "$0" |' -i "$link" + echo + fi + done + } + '' + + # texlive post-install actions + '' + mkdir -p "$out/share/texmf/scripts/texlive/" + ln -s '${bin.core.out}/share/texmf-dist/scripts/texlive/TeXLive' "$out/share/texmf/scripts/texlive/" + + for tool in updmap; do + ln -sf "$out/share/texmf/scripts/texlive/$tool."* "$out/bin/$tool" + done + '' + + # now hack to preserve "$0" for mktexfmt + '' + cp "$out"/share/texmf/scripts/texlive/fmtutil.pl "$out/bin/fmtutil" + patchShebangs "$out/bin/fmtutil" + sed "1s|$| -I $out/share/texmf/scripts/texlive|" -i "$out/bin/fmtutil" + ln -sf fmtutil "$out/bin/mktexfmt" + + perl `type -P mktexlsr.pl` ./share/texmf + texlinks.sh "$out/bin" && wrapBin + (perl `type -P fmtutil.pl` --sys --all || true) | grep '^fmtutil' # too verbose + #texlinks.sh "$out/bin" && wrapBin # do we need to regenerate format links? + + # Disable unavailable map files + echo y | perl `type -P updmap.pl` --sys --syncwithtrees --force + # Regenerate the map files (this is optional) + perl `type -P updmap.pl` --sys --force + + perl `type -P mktexlsr.pl` ./share/texmf-* # to make sure + '' + + # install (wrappers for) scripts, based on a list from upstream texlive + '' + ( + cd "$out/share/texmf/scripts" + source '${bin.core.out}/share/texmf-dist/scripts/texlive/scripts.lst' + for s in $texmf_scripts; do + [[ -x "./$s" ]] || continue + tName="$(basename $s | sed 's/\.[a-z]\+$//')" # remove extension + [[ ! -e "$out/bin/$tName" ]] || continue + ln -sv "$(realpath $s)" "$out/bin/$tName" # wrapped below + done + ) + '' + + # A hacky way to provide repstopdf + # * Copy is done to have a correct "$0" so that epstopdf enables the restricted mode + # * ./bin/repstopdf needs to be a symlink to be processed by wrapBin + '' + if [[ -e ./bin/epstopdf ]]; then + cp $(realpath ./bin/epstopdf) ./share/texmf/scripts/repstopdf + ln -s "$out"/share/texmf/scripts/repstopdf ./bin/repstopdf + fi + '' + + # finish up the wrappers + '' + rm "$out"/bin/*-sys + wrapBin + '' + + # Perform a small test to verify that the restricted mode get enabled when + # needed (detected by checking if it disallows --gscmd) + '' + if [[ -e ./bin/epstopdf ]]; then + echo "Testing restricted mode for {,r}epstopdf" + ! (epstopdf --gscmd echo /dev/null 2>&1 || true) | grep forbidden + (repstopdf --gscmd echo /dev/null 2>&1 || true) | grep forbidden + fi + '' + + # TODO: a context trigger https://www.preining.info/blog/2015/06/debian-tex-live-2015-the-new-layout/ + # http://wiki.contextgarden.net/ConTeXt_Standalone#Unix-like_platforms_.28Linux.2FMacOS_X.2FFreeBSD.2FSolaris.29 + + # I would just create links from "$out"/share/{man,info}, + # but buildenv has problems with merging symlinks with directories; + # note: it's possible we might need deepen the work-around to man/*. + '' + for d in {man,info}; do + [[ -e "./share/texmf/doc/$d" ]] || continue; + ( + mkdir -p "./share/$d" && cd "./share/$d" + ln -s -t . ../texmf/doc/"$d"/* + ) + done + '' + + # MkIV uses its own lookup mechanism and we need to initialize + # caches for it. Unsetting TEXMFCNF is needed to let mtxrun + # determine it from kpathsea so that the config path is given with + # "selfautodir:" as it will be in runtime. This is important because + # the cache is identified by a hash of this path. + '' + if [[ -e "$out/bin/mtxrun" ]]; then + ( + unset TEXMFCNF + mtxrun --generate + ) + fi + '' + + bin.cleanBrokenLinks + ; +} +# TODO: make TeX fonts visible by fontconfig: it should be enough to install an appropriate file +# similarly, deal with xe(la)tex font visibility? |