Change:
Building this package twice does not produce the bit-by-bit identical result each time, making it harder to detect CI breaches. You can read more about this at https://reproducible- . nix-build '<nixpkgs' -A --check --keep-failed You can use to analyze the differences in the output of the two builds. To view the build log of the build that produced the artifact in the binary cache: nix-store --read-log $(nix-instantiate '<nixpkgs' -A ) Tested on nixpkgs Notably the ordering of the words in and similar seem nondeterministic, perhaps the other differences are effects of that.
That is an issue with , respectively the tools called by , so it should be solved upstream.
fmtutil here is coming from texlive-scripts in - but it's the output of that's not reproducible. I'm now sure it's in dumping out the hyphenation exception strings in the (random) order in which they appear in the lua hashtable. I guess we should sort them in dictionary order. There is already a qsort routine, so perhaps we should put the exceptions in an array, sort that array using qsort, and only produce the result from that.
I think this is already referring to .
Huh! Indeed that covers the same issue - I did search before digging into this problem, but not good enough apparently :laughing: .

Discussion:
inherit (common) src prePatch; <ins> patches = [ # improves reproducibility of fmt files. This patch has been proposed upstream, # but they are considering some other approaches as well. This is fairly # conservative so we can safely apply it until they make a decision # https://mailman.ntg.nl/pipermail/dev-luatex/2022-April/006650.html (fetchpatch { name = "reproducible_exception_strings.patch"; url = "https://bugs.debian.org/cgi-bin/bugreport.cgi?att=1;bug=1009196;filename=reproducible_exception_strings.patch;msg=5"; sha256 = "sha256-RNZoEeTcWnrLaltcYrhNIORh42fFdwMzBfxMRWVurbk="; }) ]; </ins> hardeningDisable = [ "format" ]; inherit (core) nativeBuildInputs;

"/tex/generic/config" # make it a real directory for scheme-infraonly ]; <del> nativeBuildInputs = [ makeWrapper ]; </del> <ins> nativeBuildInputs = [ makeWrapper libfaketime ]; </ins> buildInputs = pkgList.extraInputs; # This is set primarily to help find-tarballs.nix to do its job

FORCE_SOURCE_DATE=1 perl `type -P fmtutil.pl` --sys --all | grep '^fmtutil' # too verbose #${bin.texlinks}/bin/texlinks "$out/bin" && wrapBin # do we need to regenerate format links? <ins> # tex intentionally ignores SOURCE_DATE_EPOCH even when FORCE_SOURCE_DATE=1 # https://salsa.debian.org/live-team/live-build/-/blob/master/examples/hooks/reproducible/0139-reproducible-texlive-binaries-fmt-files.hook.chroot#L52 if [[ -d share/texmf-var/web2c/tex ]] then cd share/texmf-var/web2c/tex faketime $(date --utc -d@$SOURCE_DATE_EPOCH --iso-8601=seconds) tex -ini -jobname=tex -progname=tex tex.ini cd - fi if [[ -d share/texmf-var/web2c/luahbtex ]] then cd share/texmf-var/web2c/luahbtex faketime $(date --utc -d@$SOURCE_DATE_EPOCH --iso-8601=seconds) luahbtex -ini -jobname=lualatex -progname=lualatex lualatex.ini cd - fi </ins> # Disable unavailable map files echo y | perl `type -P updmap.pl` --sys --syncwithtrees --force # Regenerate the map files (this is optional)

{ stdenv, lib, fetchurl, runCommand, writeText, buildEnv , callPackage, ghostscriptX, harfbuzz , makeWrapper, python3, ruby, perl, gnused, gnugrep, coreutils <ins> , libfaketime </ins> , useFixedHashes ? true , recurseIntoAttrs }:

# function for creating a working environment from a set of TL packages combine = import ./combine.nix { inherit bin combinePkgs buildEnv lib makeWrapper writeText <del> stdenv python3 ruby perl gnused gnugrep coreutils; </del> <ins> stdenv python3 ruby perl gnused gnugrep coreutils libfaketime; </ins> ghostscript = ghostscriptX; # could be without X, probably, but we use X above };