about summary refs log tree commit diff
path: root/nixpkgs/pkgs/tools/typesetting/tex/nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/tools/typesetting/tex/nix')
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/animatedot.sh9
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/copy-includes.pl43
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/default.nix249
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/dot2pdf.sh20
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/dot2ps.sh19
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/find-includes.pl69
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/find-lhs2tex-includes.sh3
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/lhs2tex.sh19
-rw-r--r--nixpkgs/pkgs/tools/typesetting/tex/nix/run-latex.sh164
9 files changed, 595 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/animatedot.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/animatedot.sh
new file mode 100644
index 000000000000..f038b83ff7ad
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/animatedot.sh
@@ -0,0 +1,9 @@
+source $stdenv/setup
+
+mkdir -p $out
+
+for ((i = 1; i <= $nrFrames; i++)); do
+    echo "producing frame $i...";
+    targetName=$out/$(basename $(stripHash $dotGraph) .dot)-f-$i.dot
+    cpp -DFRAME=$i < $dotGraph > $targetName
+done
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/copy-includes.pl b/nixpkgs/pkgs/tools/typesetting/tex/nix/copy-includes.pl
new file mode 100644
index 000000000000..2cec62fc7cb6
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/copy-includes.pl
@@ -0,0 +1,43 @@
+use strict;
+use File::Basename;
+
+sub createDirs;
+sub createDirs {
+    my $path = shift;
+    return unless $path =~ /^(.*)\/([^\/]*)$/;
+    my $dir = $1;
+    return if -d $dir;
+    return if -e $dir;
+    createDirs $dir;
+    mkdir $dir or die "cannot create directory `$dir'";
+}
+
+my $maxParents = 0;
+for (my $n = 0; $n < @ARGV; $n += 2) {
+    my $fullPath = $ARGV[$n];
+    my $relPath = $ARGV[$n + 1];
+    my $parents = 0;
+    foreach my $comp (split /\//, $relPath) {
+        $parents++ if ($comp eq "..") 
+    }
+    $maxParents = $parents if $parents > $maxParents;
+}
+
+my $startDir = "./";
+for (my $n = 0; $n < $maxParents; $n++) {
+    $startDir .= "dotdot/";
+    mkdir "$startDir" or die "cannot create directory `$startDir': $!";
+}
+
+chdir $startDir or die;
+
+for (my $n = 0; $n < @ARGV; $n += 2) {
+    my $fullPath = $ARGV[$n];
+    my $relPath = $ARGV[$n + 1];
+
+    createDirs $relPath;
+        
+    symlink $fullPath, $relPath or die "cannot create symlink `$relPath'";
+}
+
+print "$startDir\n";
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/default.nix b/nixpkgs/pkgs/tools/typesetting/tex/nix/default.nix
new file mode 100644
index 000000000000..4ee45bf4bc8f
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/default.nix
@@ -0,0 +1,249 @@
+pkgs:
+
+rec {
+
+
+  runLaTeX =
+    { rootFile
+    , generatePDF ? true # generate PDF, not DVI
+    , generatePS ? false # generate PS in addition to DVI
+    , extraFiles ? []
+    , compressBlanksInIndex ? true
+    , packages ? []
+    , texPackages ? {}
+    , copySources ? false
+    }:
+
+    assert generatePDF -> !generatePS;
+
+    let
+      tex = pkgs.texlive.combine
+        # always include basic stuff you need for LaTeX
+        ({inherit (pkgs.texlive) scheme-basic;} // texPackages);
+    in
+
+    pkgs.stdenv.mkDerivation {
+      name = "doc";
+
+      builder = ./run-latex.sh;
+      copyIncludes = ./copy-includes.pl;
+
+      inherit rootFile generatePDF generatePS extraFiles
+        compressBlanksInIndex copySources;
+
+      includes = map (x: [x.key (baseNameOf (toString x.key))])
+        (findLaTeXIncludes {inherit rootFile;});
+
+      buildInputs = [ tex 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
+    }:
+
+    builtins.genericClosure {
+      startSet = [{key = rootFile;}];
+
+      operator =
+        {key, ...}:
+
+        let
+
+          # `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"
+            { rootFile = baseNameOf (toString rootFile); src = key; }
+            "${pkgs.perl}/bin/perl ${./find-includes.pl}");
+
+          # 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 xs;
+
+        in pkgs.lib.fold foundDeps [] deps;
+    };
+
+
+  findLhs2TeXIncludes =
+    { rootFile
+    }:
+
+    builtins.genericClosure {
+      startSet = [{key = rootFile;}];
+
+      operator =
+        {key, ...}:
+
+        let
+
+          deps = import (pkgs.runCommand "lhs2tex-includes"
+            { src = key; }
+            "${pkgs.stdenv.bash}/bin/bash ${./find-lhs2tex-includes.sh}");
+
+        in pkgs.lib.concatMap (x: if builtins.pathExists x then [{key = x;}] else [])
+                              (map (x: dirOf key + ("/" + x)) deps);
+    };
+
+  dot2pdf =
+    { dotGraph
+    }:
+
+    pkgs.stdenv.mkDerivation {
+      name = "pdf";
+      builder = ./dot2pdf.sh;
+      inherit dotGraph fontsConf;
+      buildInputs = [
+        pkgs.perl pkgs.graphviz
+      ];
+    };
+
+
+  dot2ps =
+    { dotGraph
+    }:
+
+    pkgs.stdenv.mkDerivation {
+      name = "ps";
+      builder = ./dot2ps.sh;
+      inherit dotGraph;
+      buildInputs = [
+        pkgs.perl pkgs.graphviz pkgs.ghostscript
+      ];
+    };
+
+  lhs2tex =
+    { source, flags ? null } :
+    pkgs.stdenv.mkDerivation {
+      name = "tex";
+      builder = ./lhs2tex.sh;
+      inherit source flags;
+      buildInputs = [ pkgs.lhs2tex pkgs.perl ];
+      copyIncludes = ./copy-includes.pl;
+      includes = map (x: [x.key (baseNameOf (toString x.key))])
+        (findLhs2TeXIncludes {rootFile = source;});
+    };
+
+  animateDot = dotGraph: nrFrames: pkgs.stdenv.mkDerivation {
+    name = "dot-frames";
+    builder = ./animatedot.sh;
+    inherit dotGraph nrFrames;
+  };
+
+
+  # Wrap a piece of TeX code in a document.  Useful when generating
+  # inline images from TeX code.
+  wrapSimpleTeX =
+    { preamble ? null
+    , body
+    , name ? baseNameOf (toString body)
+    }:
+
+    pkgs.stdenv.mkDerivation {
+      inherit name preamble body;
+      buildCommand = ''
+        touch $out
+        echo '\documentclass{article}' >> $out
+        echo '\pagestyle{empty}' >> $out
+        if test -n "$preamble"; then cat $preamble >> $out; fi
+        echo '\begin{document}' >> $out
+        cat $body >> $out
+        echo '\end{document}' >> $out
+      '';
+    };
+
+
+  # Convert a Postscript file to a PNG image, trimming it so that
+  # there is no unnecessary surrounding whitespace.
+  postscriptToPNG =
+    { postscript
+    }:
+
+    pkgs.stdenv.mkDerivation {
+      name = "png";
+      inherit postscript;
+
+      buildInputs = [pkgs.imagemagick pkgs.ghostscript];
+
+      buildCommand = ''
+        if test -d $postscript; then
+          input=$(ls $postscript/*.ps)
+        else
+          input=$(stripHash $postscript)
+          ln -s $postscript $input
+        fi
+
+        mkdir -p $out
+        convert -units PixelsPerInch \
+          -density 600 \
+          -trim \
+          -matte \
+          -transparent '#ffffff' \
+          -type PaletteMatte \
+          +repage \
+          $input \
+          "$out/$(basename $input .ps).png"
+      ''; # */
+    };
+
+
+  # Convert a piece of TeX code to a PNG image.
+  simpleTeXToPNG =
+    { preamble ? null
+    , body
+    , packages ? []
+    }:
+
+    postscriptToPNG {
+      postscript = runLaTeX {
+        rootFile = wrapSimpleTeX {
+          inherit body preamble;
+        };
+        inherit packages;
+        generatePDF = false;
+        generatePS = true;
+      };
+    };
+
+
+  # Convert a piece of TeX code to a PDF.
+  simpleTeXToPDF =
+    { preamble ? null
+    , body
+    , packages ? []
+    }:
+
+    runLaTeX {
+      rootFile = wrapSimpleTeX {
+        inherit body preamble;
+      };
+      inherit packages;
+    };
+
+
+  # Some tools (like dot) need a fontconfig configuration file.
+  # This should be extended to allow the called to add additional
+  # fonts.
+  fontsConf = pkgs.makeFontsConf {
+    fontDirectories = [
+      "${pkgs.ghostscript}/share/ghostscript/fonts"
+    ];
+  };
+
+}
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2pdf.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2pdf.sh
new file mode 100644
index 000000000000..71cf601dfac0
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2pdf.sh
@@ -0,0 +1,20 @@
+source $stdenv/setup
+
+mkdir -p $out
+
+dot2pdf() {
+    sourceFile=$1
+    targetName=$out/$(basename $(stripHash $sourceFile) .dot).pdf
+    echo "converting $sourceFile to $targetName..."
+    export FONTCONFIG_FILE=$fontsConf
+    dot -Tpdf $sourceFile > $targetName
+}
+
+for i in $dotGraph; do
+    if test -d $i; then
+        for j in $i/*; do dot2pdf $j; done
+    else
+        dot2pdf $i
+    fi
+done
+
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2ps.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2ps.sh
new file mode 100644
index 000000000000..dd8de4a23dbc
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/dot2ps.sh
@@ -0,0 +1,19 @@
+source $stdenv/setup
+
+mkdir -p $out
+
+dot2ps() {
+    sourceFile=$1
+    targetName=$out/$(basename $(stripHash $sourceFile) .dot).ps
+    echo "converting $sourceFile to $targetName..."
+    dot -Tps $sourceFile > $targetName
+}
+
+for i in $dotGraph; do
+    if test -d $i; then
+        for j in $i/*; do dot2ps $j; done
+    else
+        dot2ps $i
+    fi
+done
+
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/find-includes.pl b/nixpkgs/pkgs/tools/typesetting/tex/nix/find-includes.pl
new file mode 100644
index 000000000000..41675e939f60
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/find-includes.pl
@@ -0,0 +1,69 @@
+use strict;
+use File::Basename;
+
+my $src = $ENV{"src"};
+my $out = $ENV{"out"};
+my $path = $ENV{"searchRelativeTo"};
+
+open OUT, ">$out" or die;
+print OUT "[\n";
+
+open FILE, "< $src" or die;
+
+sub addName {
+    my ($type, $name) = @_;
+    print OUT "{ type = \"$type\"; name = \"$name\"; }\n";
+}
+    
+while (<FILE>) {
+    if (/\\input\{(.*)\}/) {
+        my $fn2 = $1;
+        die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/";
+        addName "tex", "$fn2";
+    } elsif (/\\input (.*)$/) {
+        my $fn2 = $1;
+        die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/";
+        addName "tex", "$fn2";
+    } elsif (/\\RequirePackage(\[.*\])?\{(.*)\}/) {
+        my $fn2 = $2;
+        die "absolute path! $fn2" if substr($fn2, 0, 1) eq "/";
+        addName "misc", "$fn2.sty";
+    } 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";
+            addName "misc", (basename($ENV{"rootFile"}, ".tex", ".ltx") . ".bbl");
+        }
+    } 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
+}
+
+close FILE;
+
+print OUT "]\n";
+close OUT;
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/find-lhs2tex-includes.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/find-lhs2tex-includes.sh
new file mode 100644
index 000000000000..2dc12aa517a7
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/find-lhs2tex-includes.sh
@@ -0,0 +1,3 @@
+echo '[' > $out
+grep '^%include ' $src | cut -d ' ' -f 2 | sed 's/^\(.*\)$/"\1"/' >> $out
+echo ']' >> $out
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/lhs2tex.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/lhs2tex.sh
new file mode 100644
index 000000000000..bfef3df6b0e1
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/lhs2tex.sh
@@ -0,0 +1,19 @@
+source $stdenv/setup
+
+mkdir -p $out
+
+mkdir root
+cd root
+
+startDir=$(perl $copyIncludes $includes)
+cd $startDir
+
+lhstex() {
+    sourceFile=$1
+    targetName=$out/$(basename $(stripHash $sourceFile) .lhs).tex
+    echo "converting $sourceFile to $targetName..."
+    lhs2TeX -o "$targetName" $flags "$sourceFile"
+}
+
+lhstex $source
+
diff --git a/nixpkgs/pkgs/tools/typesetting/tex/nix/run-latex.sh b/nixpkgs/pkgs/tools/typesetting/tex/nix/run-latex.sh
new file mode 100644
index 000000000000..3f8a16580ea5
--- /dev/null
+++ b/nixpkgs/pkgs/tools/typesetting/tex/nix/run-latex.sh
@@ -0,0 +1,164 @@
+source $stdenv/setup
+
+mkdir -p $out
+
+export VARTEXFONTS=$TMPDIR/texfonts
+export TEXMFCNF=$TMPDIR:
+echo 'max_print_line = 8192' >> $TMPDIR/texmf.cnf
+
+mkdir root
+cd root
+
+startDir=$(perl $copyIncludes $includes)
+cd $startDir
+
+for i in $extraFiles; do
+    if test -d $i; then
+        ln -s $i/* .
+    else
+        ln -s $i $(stripHash $i)
+    fi
+done
+
+rootName=$(basename $(stripHash "$rootFile"))
+
+rootNameBase=$(echo "$rootName" | sed 's/\..*//')
+
+if test -n "$generatePDF"; then
+    latex=pdflatex
+else
+    latex=latex
+fi
+
+latexFlags="-file-line-error"
+tmpFile=$out/log
+
+showError() {
+    echo
+    echo "LATEX ERROR (LAST LOG LINES SHOWN):"
+    tail -n 20 $tmpFile
+    bzip2 $tmpFile
+    exit 1
+}
+
+pass=0
+
+runLaTeX() {
+    ((pass=pass+1))
+    echo "PASS $pass..."
+    if ! $latex $latexFlags $rootName >$tmpFile 2>&1; then showError; fi
+    runNeeded=
+    if fgrep -q \
+        -e "LaTeX Warning: Label(s) may have changed." \
+        -e "Rerun to get citations correct." \
+        -e "Please rerun LaTeX." \
+        "$tmpFile"; then
+        runNeeded=1
+    fi
+    echo
+}
+
+echo
+
+
+if test -n "$copySources"; then
+    cp -prd $TMPDIR/root $out/tex-srcs
+fi
+
+
+runLaTeX
+
+for auxFile in $(find . -name "*.aux"); do
+    # Run bibtex to process all bibliographies.  There may be several
+    # when we're using the multibib package.
+    if grep -q '\\citation' $auxFile; then
+        auxBase=$(basename $auxFile .aux)
+        if [ -e $auxBase.bbl ]; then
+            echo "SKIPPING BIBTEX ON $auxFile!"
+        else
+            echo "RUNNING BIBTEX ON $auxFile..."
+            bibtex --terse $auxBase
+            cp $auxBase.bbl $out
+            runNeeded=1
+        fi
+        echo
+    fi
+
+    # "\pgfsyspdfmark" in the aux file seems to indicate that PGF/TikZ
+    # requires a second run (e.g. to resolve arrows between pictures).
+    if grep -q pgfsyspdfmark $auxFile; then
+        runNeeded=1
+    fi
+done
+
+if test "$runNeeded"; then
+    runLaTeX
+fi
+
+
+if test -f $rootNameBase.idx; then
+    echo "MAKING INDEX..."
+    if test -n "$compressBlanksInIndex"; then
+        makeindexFlags="$makeindexFlags -c"
+    fi
+    makeindex $makeindexFlags $rootNameBase.idx
+    runNeeded=1
+    echo
+fi
+
+# We check that pass is less than 2 to catch situations where the document is
+# simple enough (no bibtex, etc.) so that it would otherwise require only one
+# pass but also contains a ToC.
+# In essence this check ensures that we do at least two passes on all documents.
+if test "$runNeeded" = 1 -o "$pass" -lt 2 ; then
+    runLaTeX
+fi
+
+if test "$runNeeded"; then
+    runLaTeX
+fi
+
+
+if test "$runNeeded"; then
+    echo "Hm, still not done :-("
+    echo
+fi
+
+
+if test -n "$generatePDF"; then
+    cp $rootNameBase.pdf $out
+else
+    cp $rootNameBase.dvi $out
+    if test -n "$generatePS"; then
+        echo "CONVERTING TO POSTSCRIPT..."
+        dvips $rootNameBase.dvi -o $out/$rootNameBase.ps
+        echo
+    fi
+fi
+
+
+echo "WARNINGS:"
+cat $tmpFile | grep "Warning:" | grep -v "Citation.*undefined" || true
+
+echo
+echo "OVERFULL/UNDERFULL:"
+cat $tmpFile | egrep "Overfull|Underfull" || true
+
+echo
+echo "UNDEFINED REFERENCES:"
+cat $tmpFile | grep "Reference.*undefined" || true
+
+echo
+echo "UNDEFINED CITATIONS:"
+cat $tmpFile | grep "Citation.*undefined" || true
+
+echo
+echo "STATS:"
+printf "%5d overfull/underfull h/vboxes\n" $(cat $tmpFile | egrep -c "Overfull|Underfull" || true)
+printf "%5d undefined references\n" $(cat $tmpFile | grep -c "Reference.*undefined" || true)
+printf "%5d undefined citations\n" $(cat $tmpFile | grep -c "Citation.*undefined" || true)
+printf "%5d pages\n" \
+    $(cat $tmpFile | grep "Output written.*(.*pages" | sed "s/.*(\([0-9]*\) pages.*/\1/" || true)
+echo
+
+bzip2 $tmpFile