diff --git a/pkgs/misc/tex/nix/default.nix b/pkgs/misc/tex/nix/default.nix index 2fb50bf7023..0f0c798a2e2 100644 --- a/pkgs/misc/tex/nix/default.nix +++ b/pkgs/misc/tex/nix/default.nix @@ -10,7 +10,6 @@ rec { , extraFiles ? [] , compressBlanksInIndex ? true , packages ? [] - , searchRelativeTo ? dirOf (toString rootFile) # !!! duplication , copySources ? false }: @@ -25,31 +24,57 @@ rec { inherit rootFile generatePDF generatePS extraFiles compressBlanksInIndex copySources; - includes = import (findLaTeXIncludes {inherit rootFile searchRelativeTo;}); + includes = map (x: [x.key (baseNameOf (toString x.key))]) + (findLaTeXIncludes {inherit rootFile;}); buildInputs = [ pkgs.tetex pkgs.perl ] ++ packages; }; - + + # Returns the closure of the "dependencies" of a LaTeX source file. + # Dependencies are other LaTeX source files (e.g. included using + # \input{}), images (e.g. \includegraphics{}), bibliographies, and + # so on. findLaTeXIncludes = { rootFile - , searchRelativeTo ? dirOf (toString rootFile) }: - pkgs.stdenv.mkDerivation { - name = "latex-includes"; + builtins.genericClosure { + startSet = [{key = rootFile;}]; + + operator = + {key, ...}: - realBuilder = pkgs.perl + "/bin/perl"; - args = [ ./find-includes.pl ]; + let - rootFile = toString rootFile; # !!! hacky + trace = x: builtins.trace x x; - inherit searchRelativeTo; + # `find-includes.pl' returns the dependencies of the current + # source file (`key') as a list, e.g. [{type = "tex"; name = + # "introduction.tex";} {type = "img"; name = "example"}]. + # The type denotes the kind of dependency, which determines + # what extensions we use to look for it. + deps = import (pkgs.runCommand "latex-includes" + { src = trace key; } + "${pkgs.perl}/bin/perl ${./find-includes.pl}"); - # Forces rebuilds. - hack = builtins.currentTime; + # Look for the dependencies of `key', trying various + # extensions determined by the type of each dependency. + # TODO: support a search path. + foundDeps = dep: xs: + let + exts = + if dep.type == "img" then [".pdf" ".png" ".ps" ".jpg"] + else if dep.type == "tex" then [".tex" ""] + else [""]; + fn = pkgs.lib.findFirst (fn: builtins.pathExists fn) null + (map (ext: "${dirOf key}/${dep.name}${ext}") exts); + in if fn != null then [{key = fn;}] ++ xs + else builtins.trace "not found: ${dep.name}" xs; + + in pkgs.lib.fold foundDeps [] deps; }; - + dot2pdf = { dotGraph @@ -158,7 +183,6 @@ rec { inherit packages; generatePDF = false; generatePS = true; - searchRelativeTo = dirOf (toString body); }; }; @@ -176,7 +200,6 @@ rec { inherit body preamble; }; inherit packages; - searchRelativeTo = dirOf (toString body); }; diff --git a/pkgs/misc/tex/nix/find-includes.pl b/pkgs/misc/tex/nix/find-includes.pl index eb36cefc7de..99204b46750 100644 --- a/pkgs/misc/tex/nix/find-includes.pl +++ b/pkgs/misc/tex/nix/find-includes.pl @@ -1,102 +1,60 @@ use strict; use File::Basename; -my $root = $ENV{"rootFile"}; +my $src = $ENV{"src"}; my $out = $ENV{"out"}; my $path = $ENV{"searchRelativeTo"}; -my $store = $ENV{"NIX_STORE"}; open OUT, ">$out" or die; print OUT "[\n"; -my @workset = (); -my %doneset = (); +open FILE, "< $src" or die; -sub addToWorkSetExts { - my $base = shift; - foreach my $ext (@_) { - push @workset, "$base$ext"; +sub addName { + my ($type, $name) = @_; + print OUT "{ type = \"$type\"; name = \"$name\"; }\n"; +} + +while () { + if (/\\input\{(.*)\}/) { + my $fn2 = $1; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "tex", "$fn2"; + } elsif (/\\usepackage(\[.*\])?\{(.*)\}/) { + my $fn2 = $2; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "misc", "$fn2.sty"; + } elsif (/\\documentclass(\[.*\])?\{(.*)\}/) { + my $fn2 = $2; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "misc", "$fn2.cls"; + } elsif (/\\bibliographystyle\{(.*)\}/) { + my $fn2 = $1; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "misc", "$fn2.bst"; + } elsif (/\\bibliography\{(.*)\}/) { + foreach my $bib (split /,/, $1) { + $bib =~ s/^\s+//; # remove leading / trailing whitespace + $bib =~ s/\s+$//; + addName "misc", "$bib.bib"; + } + } elsif (/\\includegraphics(\[.*\])?\{(.*)\}/) { + my $fn2 = $2; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "img", "$fn2"; + } elsif (/\\pgfdeclareimage(\[.*\])?\{.*\}\{(.*)\}/) { + my $fn2 = $2; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "img", "$fn2"; + } elsif (/\\pgfimage(\[.*\])?\{(.*)\}/) { + my $fn2 = $2; + die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; + addName "img", "$fn2"; } + # !!! also support \usepackage } -push @workset, $root; - -while (scalar @workset > 0) { - - my $fn = pop @workset; - next if (defined $doneset{$fn}); - - $doneset{$fn} = 1; - - if (!-e "$fn") { - print STDERR "cannot access `$fn': $!\n" if !$!{ENOENT}; - next; - } - - next unless -e "$fn"; - - - # Print out the full path *and* its relative path to $root. - - if (substr($fn, 0, length $path) eq $path) { - my $relFN = substr($fn, (length $path) + 1); - print OUT "$fn \"$relFN\"\n"; - } else { - my $base = basename $fn; - my $x = substr($fn, 0, length($store) + 1); - if (substr($fn, 0, length($store) + 1) eq "$store/") { - $base = substr($base, 33); - } - print OUT "$fn \"$base\"\n"; - } - - - # If this is a TeX file, recursively find include in $fn. - next unless $fn =~ /.tex$/ or $fn =~ /.ltx$/; - open FILE, "< $fn" or die; - - while () { - if (/\\input\{(.*)\}/) { - my $fn2 = $1; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - push @workset, "$path/$fn2.tex"; - push @workset, "$path/$fn2"; - } elsif (/\\usepackage(\[.*\])?\{(.*)\}/) { - my $fn2 = $2; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - push @workset, "$path/$fn2.sty"; - } elsif (/\\documentclass(\[.*\])?\{(.*)\}/) { - my $fn2 = $2; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - push @workset, "$path/$fn2.cls"; - } elsif (/\\bibliographystyle\{(.*)\}/) { - my $fn2 = $1; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - push @workset, "$path/$fn2.bst"; - } elsif (/\\bibliography\{(.*)\}/) { - foreach my $bib (split /,/, $1) { - $bib =~ s/^\s+//; # remove leading / trailing whitespace - $bib =~ s/\s+$//; - push @workset, "$path/$bib.bib"; - } - } elsif (/\\includegraphics(\[.*\])?\{(.*)\}/) { - my $fn2 = $2; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - addToWorkSetExts("$path/$fn2", ".pdf", ".png", ".ps", ".jpg"); - } elsif (/\\pgfdeclareimage(\[.*\])?\{.*\}\{(.*)\}/) { - my $fn2 = $2; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - addToWorkSetExts("$path/$fn2", ".pdf", ".png", ".jpg"); - } elsif (/\\pgfimage(\[.*\])?\{(.*)\}/) { - my $fn2 = $2; - die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/"; - addToWorkSetExts("$path/$fn2", ".pdf", ".png", ".jpg"); - } - # !!! also support \usepackage - } - - close FILE; -} +close FILE; print OUT "]\n"; close OUT; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 8385ad4fefd..8513d50d326 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -7851,7 +7851,7 @@ let }; texFunctions = import ../misc/tex/nix { - inherit stdenv perl tetex graphviz ghostscript makeFontsConf imagemagick; + inherit stdenv perl tetex graphviz ghostscript makeFontsConf imagemagick runCommand lib; }; texLive = builderDefsPackage (import ../misc/tex/texlive) {