core/pkgs/by-name/te/texlive/default.nix
2024-05-13 22:24:10 +01:00

499 lines
12 KiB
Nix

/* TeX Live user docs
- source: ../../../../../doc/languages-frameworks/texlive.xml
- current html: https://nixos.org/nixpkgs/manual/#sec-language-texlive
*/
{ lib
#, stdenv
, gcc12Stdenv, fetchurl, runCommand, writeShellScript, writeText, buildEnv
, callPackage, ghostscript_headless, harfbuzz, makeWrapper, installShellFiles
, python3, ruby, perl, tk, jdk, bash, snobol4, coreutils, findutils, gawk
, getopt, gnugrep, gnumake, gnupg, gnused, gzip, html-tidy, ncurses, zip
, libfaketime, asymptote, biber-ms, makeFontsConf, useFixedHashes ? true
, recurseIntoAttrs }:
let stdenv = gcc12Stdenv;
in let
# various binaries (compiled)
bin = callPackage ./bin.nix {
ghostscript = ghostscript_headless;
harfbuzz = harfbuzz.override {
withIcu = true;
withGraphite2 = true;
};
inherit useFixedHashes;
tlpdb = overriddenTlpdb;
};
tlpdb = import ./tlpdb.nix;
tlpdbVersion = tlpdb."00texlive.config";
# the set of TeX Live packages, collections, and schemes; using upstream naming
overriddenTlpdb = let
overrides = import ./tlpdb-overrides.nix {
inherit stdenv lib bin tlpdb tlpdbxz tl installShellFiles coreutils
findutils gawk getopt ghostscript_headless gnugrep gnumake gnupg gnused
gzip html-tidy ncurses perl python3 ruby zip;
};
in overrides tlpdb;
version = {
# day of the snapshot being taken
year = "2024";
month = "03";
day = "16";
# TeX Live version
texliveYear = 2023;
# final (historic) release or snapshot
final = true;
};
# The tarballs on CTAN mirrors for the current release are constantly
# receiving updates, so we can't use those directly. Stable snapshots
# 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/).
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"
"ftp://tug.org/texlive/historic/${toString texliveYear}/tlnet-final"
] ++ [
# CTAN mirrors
"https://mirror.ctan.org/systems/texlive/tlnet"
# daily snapshots hosted by one of the texlive release managers;
# used for packages that in the meanwhile have been updated or removed from CTAN
# and for packages that have not reached yet the historic mirrors
# please note that this server is not meant for large scale deployment
# https://tug.org/pipermail/tex-live/2019-November/044456.html
# https://texlive.info/ MUST appear last (see tlpdbxz)
"https://texlive.info/tlnet-archive/${year}/${month}/${day}/tlnet"
];
tlpdbxz = fetchurl {
urls = map (up: "${up}/tlpkg/texlive.tlpdb.xz")
# use last mirror for daily snapshots as texlive.tlpdb.xz changes every day
# TODO make this less hacky
(if version.final then mirrors else [ (lib.last mirrors) ]);
hash = "sha256-w+04GBFDk/P/XvW7T9PotGD0nQslMkV9codca2urNK4=";
};
tlpdbNix = runCommand "tlpdb.nix" {
inherit tlpdbxz;
tl2nix = ./tl2nix.sed;
} ''
xzcat "$tlpdbxz" | sed -rn -f "$tl2nix" | uniq > "$out"
'';
# map: name -> fixed-output hash
fixedHashes = lib.optionalAttrs useFixedHashes (import ./fixed-hashes.nix);
buildTeXLivePackage = import ./build-texlive-package.nix {
inherit lib fetchurl runCommand writeShellScript bash jdk perl python3 ruby
snobol4 tk;
texliveBinaries = bin;
};
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;
# function for creating a working environment
buildTeXEnv = import ./build-tex-env.nix {
inherit bin tl;
ghostscript = ghostscript_headless;
inherit lib buildEnv libfaketime makeFontsConf makeWrapper runCommand
writeShellScript writeText toTLPkgSets bash perl coreutils gawk gnugrep
gnused;
};
### texlive.combine compatibility layer:
# convert TeX packages to { pkgs = [ ... ]; } lists
# respecting specified outputs
toTLPkgList = drv:
if drv.outputSpecified or false then
let
tlType = drv.tlType or tlOutToType.${
drv.tlOutputName or drv.outputName
} or null;
in lib.optional (tlType != null) (drv // { inherit tlType; })
else
[ (drv.tex // { tlType = "run"; }) ] ++ lib.optional (drv ? texdoc)
(drv.texdoc // {
tlType = "doc";
} // lib.optionalAttrs (drv ? man) { hasManpages = true; })
++ lib.optional (drv ? texsource)
(drv.texsource // { tlType = "source"; })
++ lib.optional (drv ? tlpkg) (drv.tlpkg // { tlType = "tlpkg"; })
++ lib.optional (drv ? out) (drv.out // { tlType = "bin"; });
tlOutToType = {
out = "bin";
tex = "run";
texsource = "source";
texdoc = "doc";
tlpkg = "tlpkg";
};
# convert { pkgs = [ ... ]; } lists to TeX packages
# possibly more than one, if pkgs is also used to specify dependencies
tlTypeToOut = {
run = "tex";
doc = "texdoc";
source = "texsource";
bin = "out";
tlpkg = "tlpkg";
};
toSpecifiedNV = p: rec {
name = value.tlOutputName;
value = builtins.removeAttrs p [ "pkgs" ] // {
outputSpecified = true;
tlOutputName = tlTypeToOut.${p.tlType};
};
};
toTLPkgSet = pname: drvs:
let
set = lib.listToAttrs (builtins.map toSpecifiedNV drvs);
mainDrv = set.out or set.tex or set.tlpkg or set.texdoc or set.texsource;
in builtins.removeAttrs mainDrv [ "outputSpecified" ];
toTLPkgSets = { pkgs, ... }:
lib.mapAttrsToList toTLPkgSet (builtins.groupBy (p: p.pname) pkgs);
# export TeX packages as { pkgs = [ ... ]; } in the top attribute set
allPkgLists = lib.mapAttrs (n: drv: { pkgs = toTLPkgList drv; }) tl;
# function for creating a working environment from a set of TL packages
# now a legacy wrapper around buildTeXEnv
combine = import ./combine-wrapper.nix {
inherit buildTeXEnv lib toTLPkgList toTLPkgSets;
};
assertions = with lib;
assertMsg (tlpdbVersion.year == version.texliveYear)
"TeX Live year in texlive does not match tlpdb.nix, refusing to evaluate"
&& assertMsg (tlpdbVersion.frozen == version.final)
"TeX Live final status in texlive does not match tlpdb.nix, refusing to evaluate";
# Pre-defined evironment packages for TeX Live schemes,
# to make nix-env usage more comfortable and build selected on Hydra.
# these license lists should be the sorted union of the licenses of the packages the schemes contain.
# The correctness of this collation is tested by tests.texlive.licenses
licenses = with lib.licenses; {
scheme-basic = [
free
gfl
gpl1Only
gpl2Only
gpl2Plus
knuth
lgpl21
lppl1
lppl13c
mit
ofl
publicDomain
];
scheme-bookpub = [
artistic2
asl20
bsd3
fdl13Only
free
gfl
gpl1Only
gpl2Only
gpl2Plus
knuth
lgpl21
lppl1
lppl12
lppl13a
lppl13c
mit
ofl
publicDomain
];
scheme-context = [
bsd2
bsd3
cc-by-sa-40
free
gfl
gfsl
gpl1Only
gpl2Only
gpl2Plus
gpl3Only
gpl3Plus
knuth
lgpl2
lgpl21
lppl1
lppl13c
mit
ofl
publicDomain
x11
];
scheme-full = [
artistic1-cl8
artistic2
asl20
bsd2
bsd3
bsdOriginal
cc-by-10
cc-by-20
cc-by-30
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
gpl2Only
gpl2Plus
gpl3Only
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
gpl2Only
gpl2Plus
gpl3Only
gpl3Plus
knuth
lgpl2
lgpl21
lppl1
lppl12
lppl13a
lppl13c
mit
ofl
publicDomain
x11
];
scheme-infraonly = [ gpl2Plus lgpl21 ];
scheme-medium = [
artistic1-cl8
asl20
bsd2
bsd3
cc-by-40
cc-by-sa-20
cc-by-sa-30
cc-by-sa-40
cc0
fdl13Only
free
gfl
gpl1Only
gpl2Only
gpl2Plus
gpl3Only
gpl3Plus
isc
knuth
lgpl2
lgpl21
lgpl3
lppl1
lppl12
lppl13a
lppl13c
mit
ofl
publicDomain
x11
];
scheme-minimal = [
free
gpl1Only
gpl2Plus
knuth
lgpl21
lppl1
lppl13c
mit
ofl
publicDomain
];
scheme-small = [
asl20
cc-by-40
cc-by-sa-40
cc0
fdl13Only
free
gfl
gpl1Only
gpl2Only
gpl2Plus
gpl3Only
gpl3Plus
knuth
lgpl2
lgpl21
lppl1
lppl12
lppl13a
lppl13c
mit
ofl
publicDomain
x11
];
scheme-tetex = [
artistic1-cl8
asl20
bsd2
bsd3
cc-by-30
cc-by-40
cc-by-sa-10
cc-by-sa-20
cc-by-sa-30
cc-by-sa-40
cc0
fdl13Only
free
gfl
gpl1Only
gpl2Only
gpl2Plus
gpl3Only
gpl3Plus
isc
knuth
lgpl2
lgpl21
lgpl3
lppl1
lppl12
lppl13a
lppl13c
mit
ofl
publicDomain
x11
];
};
meta = {
description = "TeX Live environment";
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [ veprbl ];
license = licenses.scheme-infraonly;
};
combined = recurseIntoAttrs (lib.genAttrs [
"scheme-basic"
"scheme-bookpub"
"scheme-context"
"scheme-full"
"scheme-gust"
"scheme-infraonly"
"scheme-medium"
"scheme-minimal"
"scheme-small"
"scheme-tetex"
] (pname:
(buildTeXEnv {
__extraName = "combined" + lib.removePrefix "scheme" pname;
__extraVersion = with version;
if final then "-final" else ".${year}${month}${day}";
requiredTeXPackages = ps: [ ps.${pname} ];
# to maintain full backward compatibility, enable texlive.combine behavior
__combine = true;
}).overrideAttrs {
meta = meta // {
description = "TeX Live environment for ${pname}";
license = licenses.${pname};
};
}));
schemes = lib.listToAttrs (map (s: {
name = "texlive" + s;
value =
lib.addMetaAttrs { license = licenses.${"scheme-" + (lib.toLower s)}; }
(buildTeXEnv {
requiredTeXPackages = ps: [ ps.${"scheme-" + (lib.toLower s)} ];
});
}) [
"Basic"
"BookPub"
"ConTeXt"
"Full"
"GUST"
"InfraOnly"
"Medium"
"Minimal"
"Small"
"TeTeX"
]);
in allPkgLists // {
pkgs = tl;
tlpdb = {
# nested in an attribute set to prevent them from appearing in search
nix = tlpdbNix;
xz = tlpdbxz;
};
bin = assert assertions;
bin // {
# for backward compatibility
latexindent = tl.latexindent;
};
combine = assert assertions; combine;
combined = assert assertions; combined;
inherit schemes;
# convenience alias
withPackages = (buildTeXEnv { }).withPackages;
}