diff --git a/pkgs/tools/typesetting/tex/texlive/build-texlive-package.nix b/pkgs/tools/typesetting/tex/texlive/build-texlive-package.nix new file mode 100644 index 000000000000..1415d2d39f9f --- /dev/null +++ b/pkgs/tools/typesetting/tex/texlive/build-texlive-package.nix @@ -0,0 +1,140 @@ +{ lib +, fetchurl +, runCommand + + # script interpreters +, bash +, jdk +, perl +, python3 +, ruby +, snobol4 +, tk + + # TeX Live prerequisites +, texliveBinaries +}: + +{ pname +, revision +, version ? toString revision +, sha512 +, mirrors +, extraVersion ? "" +, fixedHashes ? { } +, postUnpack ? "" +, stripPrefix ? 1 +, license ? [ ] +, hasHyphens ? false +, hasManpages ? false +, hasRunfiles ? false +, hasTlpkg ? false +, ... +}@args: + +let + meta = { license = map (x: lib.licenses.${x}) license; }; + + commonPassthru = { + inherit pname revision version; + } // lib.optionalAttrs (args ? extraRevision) { + inherit (args) extraRevision; + }; + + # build run, doc, source, tlpkg containers + mkContainer = tlType: passthru: sha512: + let + # NOTE: the fixed naming scheme must match generated-fixed-hashes.nix + # the basename used by upstream (without ".tar.xz" suffix) + urlName = pname + (lib.optionalString (tlType != "run" && tlType != "tlpkg") ".${tlType}"); + # name + version for the derivation + tlName = urlName + (lib.optionalString (tlType == "tlpkg") ".tlpkg") + "-${version}${extraVersion}"; + fixedHash = fixedHashes.${tlType} or null; # be graceful about missing hashes + + urls = args.urls or (if args ? url then [ args.url ] else + map (up: "${up}/archive/${urlName}.r${toString revision}.tar.xz") mirrors); + in + runCommand "texlive-${tlName}" + ({ + src = fetchurl { inherit urls sha512; }; + inherit meta passthru stripPrefix tlType; + } // lib.optionalAttrs (fixedHash != null) { + outputHash = fixedHash; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }) + ('' + mkdir "$out" + if [[ "$tlType" == "tlpkg" ]]; then + tar -xf "$src" \ + --strip-components=1 \ + -C "$out" --anchored --exclude=tlpkg/tlpobj --keep-old-files \ + tlpkg + else + tar -xf "$src" \ + --strip-components="$stripPrefix" \ + -C "$out" --anchored --exclude=tlpkg --keep-old-files + fi + '' + postUnpack); + + tex = [ + ( + let passthru = commonPassthru + // lib.optionalAttrs (args ? deps) { tlDeps = args.deps; } + // lib.optionalAttrs (args ? formats) { inherit (args) formats; } + // lib.optionalAttrs hasHyphens { inherit hasHyphens; }; in + if hasRunfiles then mkContainer "run" passthru sha512.run + else (passthru // { tlType = "run"; }) + ) + ]; + + doc = let passthru = commonPassthru + // lib.optionalAttrs hasManpages { inherit hasManpages; }; in + lib.optional (sha512 ? doc) (mkContainer "doc" passthru sha512.doc); + + source = lib.optional (sha512 ? source) (mkContainer "source" commonPassthru sha512.source); + + tlpkg = let passthru = commonPassthru + // lib.optionalAttrs (args ? postactionScript) { postactionScript = args.postactionScript; }; in + lib.optional hasTlpkg (mkContainer "tlpkg" passthru sha512.run); + + bin = lib.optional (args ? binfiles && args.binfiles != [ ]) ( + let + # find interpreters for the script extensions found in tlpdb + extToInput = { + jar = jdk; + lua = texliveBinaries.luatex; + py = python3; + rb = ruby; + sno = snobol4; + tcl = tk; + texlua = texliveBinaries.luatex; + tlu = texliveBinaries.luatex; + }; + run = lib.head tex; + in + runCommand "texlive-${pname}.bin-${version}" + { + passthru = commonPassthru // { tlType = "bin"; }; + inherit meta; + # shebang interpreters + buildInputs = (args.extraBuildInputs or [ ]) ++ [ bash perl ] ++ (lib.attrVals (args.scriptExts or [ ]) extToInput); + # absolute scripts folder + scriptsFolder = lib.optionalString (run ? outPath) (run.outPath + "/scripts/" + args.scriptsFolder or pname); + # binaries info + inherit (args) binfiles; + binlinks = builtins.attrNames (args.binlinks or { }); + bintargets = builtins.attrValues (args.binlinks or { }); + binfolders = [ (lib.getBin texliveBinaries.core) ] ++ + lib.optional (texliveBinaries ? ${pname}) (lib.getBin texliveBinaries.${pname}); + # build scripts + patchScripts = ./patch-scripts.sed; + makeBinContainers = ./make-bin-containers.sh; + } + '' + . "$makeBinContainers" + ${args.postFixup or ""} + '' + ); +in +{ pkgs = tex ++ doc ++ source ++ tlpkg ++ bin; } diff --git a/pkgs/tools/typesetting/tex/texlive/default.nix b/pkgs/tools/typesetting/tex/texlive/default.nix index c93e7bb50ebb..6a58cb157629 100644 --- a/pkgs/tools/typesetting/tex/texlive/default.nix +++ b/pkgs/tools/typesetting/tex/texlive/default.nix @@ -33,7 +33,7 @@ let tlpdbVersion = tlpdb."00texlive.config"; # the set of TeX Live packages, collections, and schemes; using upstream naming - tl = let + overriddenTlpdb = let # most format -> engine links are generated by texlinks according to fmtutil.cnf at combine time # so we remove them from binfiles, and add back the ones texlinks purposefully ignore (e.g. mptopdf) removeFormatLinks = lib.mapAttrs (_: attrs: @@ -43,9 +43,9 @@ let in if binNotFormats != [] then attrs // { binfiles = binNotFormats; } else removeAttrs attrs [ "binfiles" ] else attrs); - orig = removeFormatLinks (removeAttrs tlpdb [ "00texlive.config" ]); + orig = removeFormatLinks (removeAttrs tlpdb [ "00texlive.config" ]); in - overridden = lib.recursiveUpdate orig rec { + lib.recursiveUpdate orig rec { #### overrides of texlive.tlpdb #### nonstandard script folders @@ -355,8 +355,8 @@ let # hardcode revision numbers (since texlive.infra, tlshell are not in either system or user texlive.tlpdb) tlshell.postFixup = '' substituteInPlace "$out"/bin/tlshell \ - --replace '[dict get $::pkgs texlive.infra localrev]' '${toString overridden."texlive.infra".revision}' \ - --replace '[dict get $::pkgs tlshell localrev]' '${toString overridden.tlshell.revision}' + --replace '[dict get $::pkgs texlive.infra localrev]' '${toString orig."texlive.infra".revision}' \ + --replace '[dict get $::pkgs tlshell localrev]' '${toString orig.tlshell.revision}' ''; #### dependency changes @@ -428,40 +428,6 @@ let }; }; # overrides - in lib.mapAttrs mkTLPkg overridden; - - # create a TeX package: an attribute set { pkgs = [ ... ]; ... } where pkgs is a list of derivations - mkTLPkg = pname: attrs: - let - version = attrs.version or (toString attrs.revision); - mkPkgV = tlType: let - pkg = attrs // { - sha512 = attrs.sha512.${if tlType == "tlpkg" then "run" else tlType}; - inherit pname tlType version; - } // lib.optionalAttrs (attrs.hasManpages or false) { - hasManpages = true; - }; - in mkPkg pkg; - run = if (attrs.hasRunfiles or false) then mkPkgV "run" - # the fake derivations are used for filtering of hyphenation patterns and formats - else ({ - inherit pname version; - inherit (attrs) revision; - tlType = "run"; - hasHyphens = attrs.hasHyphens or false; - tlDeps = map (n: tl.${n}) (attrs.deps or []); - } // lib.optionalAttrs (attrs ? formats) { inherit (attrs) formats; }); - in { - # TL pkg contains lists of packages: runtime files, docs, sources, tlpkg, binaries - pkgs = - # tarball of a collection/scheme itself only contains a tlobj file - [ run ] - ++ lib.optional (attrs.sha512 ? doc) (mkPkgV "doc") - ++ lib.optional (attrs.sha512 ? source) (mkPkgV "source") - ++ lib.optional (attrs.hasTlpkg or false) (mkPkgV "tlpkg") - ++ lib.optional (attrs ? binfiles && attrs.binfiles != []) (mkPkgBin pname version run attrs); - }; - version = { # day of the snapshot being taken year = "2023"; @@ -478,7 +444,7 @@ let # need to be used instead. Ideally, for the release branches of NixOS we # should be switching to the tlnet-final versions # (https://tug.org/historic/). - urlPrefixes = with version; lib.optionals final [ + mirrors = with version; lib.optionals final [ # tlnet-final snapshot; used when texlive.tlpdb is frozen # the TeX Live yearly freeze typically happens in mid-March "http://ftp.math.utah.edu/pub/tex/historic/systems/texlive/${toString texliveYear}/tlnet-final" @@ -492,7 +458,7 @@ let ]; tlpdbxz = fetchurl { - urls = map (up: "${up}/tlpkg/texlive.tlpdb.xz") urlPrefixes; + urls = map (up: "${up}/tlpkg/texlive.tlpdb.xz") mirrors; hash = "sha256-vm7DmkH/h183pN+qt1p1wZ6peT2TcMk/ae0nCXsCoMw="; }; @@ -507,103 +473,17 @@ let # map: name -> fixed-output hash fixedHashes = lib.optionalAttrs useFixedHashes (import ./fixed-hashes.nix); - # name for the URL - mkURLName = { pname, tlType, ... }: pname + lib.optionalString (tlType != "run" && tlType != "tlpkg") ".${tlType}"; - # NOTE: the fixed naming scheme must match generated-fixed-hashes.nix - # name + revision for the fixed output hashes - mkFixedName = { pname, tlType, revision, extraRevision ? "", ... }: "${pname}-${toString revision}${extraRevision}"; - # name + version for the derivation - mkTLName = { tlType, version, extraVersion ? "", ... }@attrs: mkURLName attrs + (lib.optionalString (tlType == "tlpkg") ".tlpkg") + "-${version}${extraVersion}"; + buildTeXLivePackage = import ./build-texlive-package.nix { + inherit lib fetchurl runCommand bash jdk perl python3 ruby snobol4 tk; + texliveBinaries = bin; + }; - # build tlType == "bin" containers based on `binfiles` in TLPDB - # see UPGRADING.md for how to keep the list of shebangs up to date - mkPkgBin = let extToInput = { - jar = jdk; - lua = bin.luatex; - py = python3; - rb = ruby; - sno = snobol4; - tcl = tk; - texlua = bin.luatex; - tlu = bin.luatex; - }; in pname: version: run: - { binfiles, scriptsFolder ? pname, postFixup ? "", scriptExts ? [], extraBuildInputs ? [], binlinks ? {}, ... }@args: - runCommand "texlive-${pname}.bin-${version}" - { - # metadata for texlive.combine - passthru = { - inherit pname version; - tlType = "bin"; - }; - # shebang interpreters - buildInputs = extraBuildInputs ++ [ bash perl ] ++ (lib.attrVals scriptExts extToInput); - # absolute scripts folder - scriptsFolder = lib.optionalString (run ? outPath) (run.outPath + "/scripts/" + scriptsFolder); - # binaries info - inherit binfiles; - binlinks = builtins.attrNames binlinks; - bintargets = builtins.attrValues binlinks; - binfolders = [ (lib.getBin bin.core) ] ++ lib.optional (bin ? ${pname}) (lib.getBin bin.${pname}); - # build scripts - patchScripts = ./patch-scripts.sed; - makeBinContainers = ./make-bin-containers.sh; - } - '' - . "$makeBinContainers" - ${postFixup} - ''; - - # create a derivation that contains an unpacked upstream TL package - mkPkg = { pname, tlType, revision, version, sha512, extraRevision ? "", postUnpack ? "", stripPrefix ? 1, hasManpages ? false, ... }@args: - let - # the basename used by upstream (without ".tar.xz" suffix) - urlName = mkURLName args; - tlName = mkTLName args; - fixedName = mkFixedName args; - fixedHash = if fixedHashes ? ${fixedName} then fixedHashes.${fixedName}.${tlType} or null else null; # be graceful about missing hashes - - urls = args.urls or (if args ? url then [ args.url ] else - map (up: "${up}/archive/${urlName}.r${toString revision}.tar.xz") (args.urlPrefixes or urlPrefixes)); - - in runCommand "texlive-${tlName}" - ( { - src = fetchurl { inherit urls sha512; }; - meta = { - license = map (x: lib.licenses.${x}) (args.license or []); - }; - inherit stripPrefix tlType; - # metadata for texlive.combine - passthru = { - inherit pname tlType revision version extraRevision; - } // lib.optionalAttrs (tlType == "run" && args ? deps) { - tlDeps = map (n: tl.${n}) args.deps; - } // lib.optionalAttrs (tlType == "run") { - hasHyphens = args.hasHyphens or false; - } // lib.optionalAttrs (tlType == "tlpkg" && args ? postactionScript) { - postactionScript = args.postactionScript; - } - // lib.optionalAttrs (tlType == "run" && args ? formats) { inherit (args) formats; } - // lib.optionalAttrs (tlType == "doc" && hasManpages) { hasManpages = true; }; - } // lib.optionalAttrs (fixedHash != null) { - outputHash = fixedHash; - outputHashAlgo = "sha256"; - outputHashMode = "recursive"; - } - ) - ( '' - mkdir "$out" - if [[ "$tlType" == "tlpkg" ]]; then - tar -xf "$src" \ - --strip-components=1 \ - -C "$out" --anchored --exclude=tlpkg/tlpobj --keep-old-files \ - tlpkg - else - tar -xf "$src" \ - --strip-components="$stripPrefix" \ - -C "$out" --anchored --exclude=tlpkg --keep-old-files - fi - '' + postUnpack - ); + tl = lib.mapAttrs (pname: { revision, extraRevision ? "", ... }@args: + buildTeXLivePackage (args + # NOTE: the fixed naming scheme must match generate-fixed-hashes.nix + // { inherit mirrors pname; fixedHashes = fixedHashes."${pname}-${toString revision}${extraRevision}" or { }; } + // lib.optionalAttrs (args ? deps) { deps = map (n: tl.${n}) (args.deps or [ ]); }) + ) overriddenTlpdb; # combine a set of TL packages into a single TL meta-package combinePkgs = pkgList: lib.catAttrs "pkg" ( @@ -642,6 +522,7 @@ in # for backward compatibility latexindent = lib.findFirst (p: p.tlType == "bin") tl.latexindent.pkgs; }; + combine = assert assertions; combine; # Pre-defined combined packages for TeX Live schemes, @@ -654,7 +535,7 @@ in scheme-basic = [ free gfl gpl1Only gpl2 gpl2Plus knuth lgpl21 lppl1 lppl13c mit ofl publicDomain ]; scheme-context = [ bsd2 bsd3 cc-by-sa-40 free gfl gfsl gpl1Only gpl2 gpl2Plus gpl3 gpl3Plus knuth lgpl2 lgpl21 lppl1 lppl13c mit ofl publicDomain x11 ]; - scheme-full = [ artistic1-cl8 asl20 bsd2 bsd3 bsdOriginal cc-by-10 cc-by-40 cc-by-sa-10 cc-by-sa-20 + scheme-full = [ artistic1-cl8 artistic2 asl20 bsd2 bsd3 bsdOriginal cc-by-10 cc-by-40 cc-by-sa-10 cc-by-sa-20 cc-by-sa-30 cc-by-sa-40 cc0 fdl13Only free gfl gfsl gpl1Only gpl2 gpl2Plus gpl3 gpl3Plus isc knuth lgpl2 lgpl21 lgpl3 lppl1 lppl12 lppl13a lppl13c mit ofl publicDomain x11 ]; scheme-gust = [ artistic1-cl8 asl20 bsd2 bsd3 cc-by-40 cc-by-sa-40 cc0 fdl13Only free gfl gfsl gpl1Only gpl2