aboutsummaryrefslogtreecommitdiffstats
path: root/texnix
blob: 1f7cf7e9170ad38abf01f8b3a93f7af8925d8286 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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