aboutsummaryrefslogtreecommitdiffstats
path: root/texnix
diff options
context:
space:
mode:
Diffstat (limited to 'texnix')
-rwxr-xr-xtexnix102
1 files changed, 102 insertions, 0 deletions
diff --git a/texnix b/texnix
new file mode 100755
index 0000000..1f7cf7e
--- /dev/null
+++ b/texnix
@@ -0,0 +1,102 @@
+#! /bin/sh
+# usage: texnix TEXFILE...
+# Print Nix expression for creating a TeX working environment for a set of
+# TEXFILEs.
+
+set -efu
+
+texnix_version=1.0.0
+
+TMPDIR=$(mktemp --tmpdir -d texnix.XXXXXXXX)
+trap 'rm -R "$TMPDIR"' EXIT
+
+# Export TMPDIR for subsequent calls to mktemp.
+export TMPDIR
+
+# usage: extract_dependencies TEXFILE...
+# Print all (transitive) dependencies of TEXFILEs.
+extract_dependencies() {(
+ all_packages=$TMPDIR/all_packages
+ dependencies=$TMPDIR/dependencies
+ working_set=$TMPDIR/working_set
+
+ get_all_packages > "$all_packages"
+ truncate -s 0 "$dependencies"
+ get_packages "$@" | comm -12 - "$all_packages" > "$working_set"
+
+ while test -s "$working_set"; do
+ package=$(pop "$working_set")
+
+ echo "$package" | add "$dependencies"
+
+ tmp_working_set=$(mktemp working_set.XXXXXXXX)
+ { cat "$working_set"
+ texlive_cat "$package" | get_packages - | comm -2 - "$dependencies"
+ } | sort -u | comm -12 - "$all_packages" > "$tmp_working_set"
+ mv "$tmp_working_set" "$working_set"
+ done
+
+ cat "$dependencies"
+)}
+
+# usage: texlive_cat PACKAGE
+# Concatenate and print all files of a TeX live package.
+texlive_cat() {
+ nix-build --no-out-link '<nixpkgs>' -A texlive."$1".pkgs |
+ while read -r path; do
+ find "$path" -mindepth 1 -maxdepth 1 -name tex -exec find {} -type f \;
+ done |
+ xargs cat
+}
+
+# usage: get_all_packages
+# Print all TeX live packages.
+get_all_packages() {
+ nix-instantiate \
+ --eval \
+ --json \
+ --strict \
+ -E \
+ 'builtins.attrNames (import <nixpkgs> {}).texlive' \
+ |
+ jq -r .[] |
+ sort -u
+}
+
+# usage: get_packages TEXFILE...
+# Print all packages used in TEXFILEs.
+get_packages() {
+ sed -rn '
+ s:.*(usepackage|RequirePackage).*\{([^}]+)}:\2:;T
+ s:,:\n:g
+ p
+ ' "$@" |
+ sort -u
+}
+
+# usage: add SETFILE
+# Add lines read from stdin to SETFILE.
+add() {(
+ t=$(mktemp add.XXXXXXXX)
+ sort -u - "$1" > "$t"
+ mv "$t" "$1"
+)}
+
+# usage: pop FILE
+# Remove first line of FILE and print it to stdout.
+pop() {
+ head -1 "$1"
+ sed -i 1d "$1"
+}
+
+cat <<EOF
+# Generated with texnix $texnix_version
+{ texlive, extraTexPackages ? {} }:
+texlive.combine ({
+ inherit (texlive) scheme-small;
+ $(extract_dependencies "$@" | sed '
+ s/.*/"&" = texlive."&";/
+ 2,$s/^/ /
+ ')
+} // extraTexPackages)
+EOF