diff options
| author | Sebastian Kuhnert | 2009-10-13 13:36:17 +0000 |
|---|---|---|
| committer | Sebastian Kuhnert | 2009-10-13 13:36:17 +0000 |
| commit | 4123f6cc94167ccad7a91dc77cad07b52d0101f7 (patch) | |
| tree | 8f9653c93a3bba8d8404a157c922fc49089fb698 /texall | |
| parent | 6affa2159dea7c1a2292f197f3c27bdcc6ab2f68 (diff) | |
| download | exercisesheets-4123f6cc94167ccad7a91dc77cad07b52d0101f7.tar.gz exercisesheets-4123f6cc94167ccad7a91dc77cad07b52d0101f7.tar.bz2 exercisesheets-4123f6cc94167ccad7a91dc77cad07b52d0101f7.zip | |
Diffstat (limited to 'texall')
| -rwxr-xr-x | texall | 955 |
1 files changed, 0 insertions, 955 deletions
@@ -1,955 +0,0 @@ -#!/usr/bin/env python - -from optparse import OptionParser -import sys -import os -import os.path -import pty -import re -import select -import subprocess -import fnmatch -import dircache -import termios -import signal - -class TexallOptionParser(OptionParser): - def __init__(self): - OptionParser.__init__(self, - usage="%prog [options] DIR/FILE", - version="%prog $Id$", - description="Call LaTeX and friends to typeset all tex files in DIR/FILE. By default up-to-date files are skipped. Care is taken to run all required commands until the result is stable. By default, pdflatex is used, but use of pstricks forces dvi->ps->pdf. The utility program rmligs ist used to improve output for german language texts. Use \"texall -Sqfi batchmode file.tex\" to simulate the behaviour of (pdf)latex in non-interactive mode (useful for emacs).") - self.add_option("-n", "--dry-run", - action="store_false", dest="act", default=True, - help="do not run any program") - self.add_option("-f", "--force", - action="store_true", dest="force", default=False, - help="regenerate up-to-date files") - self.add_option("-N", "--non-recursive", - action="store_false", dest="recurse", default=True, - help="disable recursion into subdirectories") - self.add_option("-s", "--summary", dest="summary", - help="summarise failures and processed files at the end of the run (one of failures (default), files, both, no)", - choices=("no","files","failures","both"), default="failures") - self.add_option("-v", "--verbose", - action="count", dest="verbosity", default=1, - help="explain what is going on") - self.add_option("-q", "--quiet", - action="store_const", dest="verbosity", const=0, - help="suppress progress reports") - self.add_option("-o", "--show-output", - action="store_true", dest="showoutput", default=False, - help="show the output of the called programs") - self.add_option("-i", "--interaction", - dest="interactionmode", choices=("batchmode", "nonstopmode", "scrollmode", "errorstopmode"), - help="control the behaviour of latex (on of batchmode (default), nonstopmode (default for -o), scrollmode, errorstopmode)") - self.add_option("-I", "--ignore", - action="store", dest="ignorepattern", default=".*vorlage|\\.\\#|.*-rmligs\\.tex$", - help="regular expression of filenames to ignore") - self.add_option("-P", "--required-pattern", - action="store", dest="requiredpattern", default='^\\\\documentclass|^%%% TeX-master: t', - help="regular expression that must match the file content") - self.add_option("-T", "--preserve-tempfiles", - action="store_false", dest="deletetempfiles", default=True, - help="preserve temporary files (default: delete)") - self.add_option("-K", "--no-kpathsea", - action="store_true", dest="nokpse", default=False, - help="do not call kpsewhich (might be faster)") - self.add_option("-S", "--single-run", - action="store_true", dest="singlerun", default=False, - help="stop after the first LaTeX run, no matter if finished") - - def parse_args(self, args=None, values=None): - options, arguments = OptionParser.parse_args(self, args, values) - - # provide default for interactionmode: - if options.interactionmode == None: - if options.showoutput: - options.interactionmode = "nonstopmode" - else: - options.interactionmode = "batchmode" - - return options, arguments - -class AnalyserData: - def __init__(self, name, filetype): - self.name = name - self.filetype = filetype - -class Analyser: - """Abstract class for analysing of program output and file content""" - - def __init__(self, d): - """Instance creation. - - d -- dictionary to store data in""" - self.d = d - - def parse(self, text): - """parse text and change own state accordingly. - - text -- the filecontent or line to analyse""" - raise NotImplementedError - - def merge(self, d): - """merge information gathered from an included file. - - d -- dictionary with information gathered from the included file""" - raise NotImplementedError - - def finish(self, dirname): - """final steps after all dependecy file information hat been merged. - - Only executed if this data object belongs to a main .tex file. - - dirname -- directory of current job""" - pass - -class AnalyseTexRequired(Analyser): - def __init__(self, d): - d.required = False - Analyser.__init__(self,d) - def parse(self, text): - if re_required.search(text): - self.d.required = True - def merge(self, d): - self.d.required |= d.required - -class AnalyseTexDependencies(Analyser): - def __init__(self, d): - d.deps = [] - d.grfdeps = [] - Analyser.__init__(self, d) - def parse(self, text): - for m in re_inputinclude.finditer(text): - self.d.deps.append((m.group(2), (".tex", ""))) - m = re_documentclass.search(text) - if m: - cls = m.group(2) - self.d.deps.append((cls, (".cls", ""))) - for m in re_usepackage.finditer(text): - stys = m.group(2) - for sty in re_commawhitespace.split(stys): - self.d.deps.append((sty, (".sty", ""))) - for m in re_usetheme.finditer(text): - themes = m.group(3) - ttype = m.group(1) - for theme in re_commawhitespace.split(themes): - self.d.deps.append(("beamer%stheme%s"%(ttype, theme), (".sty",))) - for m in re_graphics.finditer(text): - self.d.grfdeps.append(m.group(2)) - def merge(self, d): - self.d.deps.extend(d.deps) - self.d.grfdeps.extend(d.grfdeps) - def finish(self, dirname): - if hasattr(self.d, "needsPS"): - if self.d.needsPS: - for f in self.d.grfdeps: - self.d.deps.append((f, (".eps", ".jpg", ".png", ""))) - else: - for f in self.d.grfdeps: - self.d.deps.append((f, (".pdf", ".jpg", ".png", ""))) - expandeddeps = [] - for dep, extlist in self.d.deps: - if extlist == None: - expandeddeps.append((dep, extlist)) - else: - try: - expandeddeps.append((texpath(dirname, dep, extlist=extlist), None)) - except ValueError, e: - if opts.verbosity > 2: - error(self.d.name, "ignoring dependency: %s"%e, warning=True) - self.d.deps = expandeddeps - -class AnalyseTexBibfiles(Analyser): - def __init__(self, d): - d.bibfiles = [] - Analyser.__init__(self, d) - def parse(self, text): - for m in re_bibliography.finditer(text): - bibs = m.group(1) - for bib in re_commawhitespace.split(bibs): - if bib[-8:] != "-blx.bib" and bib[-4:] != "-blx": - self.d.bibfiles.append(bib) - def merge(self, d): - self.d.bibfiles.extend(d.bibfiles) - def finish(self, dirname): - bibpaths = [] - for bib in self.d.bibfiles: - try: - bibpath = texpath(dirname, bib, pathtype="bib",progname="bibtex") - bibpath = strippath(bibpath, dirname) - self.d.deps.append((bibpath, None)) - bibpaths.append(bibpath) - except ValueError, e: - error(self.d.name, str(e), warning=True) - bibpaths.append(bib) - pass - self.d.bibfiles = bibpaths - -class AnalyseTexNeedsPs(Analyser): - def __init__(self, d): - d.needsPS = False - Analyser.__init__(self, d) - def parse(self, text): - if re_needsps.search(text): - self.d.needsPS = True - def merge(self, d): - self.d.needsPS |= d.needsPS - -class AnalyseTexRmligs(Analyser): - def __init__(self, d): - d.rmligs = False - Analyser.__init__(self, d) - def parse(self, text): - if re_rmligs.search(text): - self.d.rmligs = True - def merge(self, d): - self.d.rmligs |= d.rmligs - -class AnalyseTexDatatool(Analyser): - def __init__(self, d): - d.DTLdeps = [] - Analyser.__init__(self, d) - def parse(self, text): - for m in re_DTLdep.finditer(text): - self.d.DTLdeps.append((m.group(2), None)) - def merge(self, d): - self.d.DTLdeps.extend(d.DTLdeps) - def finish(self, _): - self.d.deps.extend(self.d.DTLdeps) - -texanalysers = (AnalyseTexRequired, AnalyseTexDependencies, AnalyseTexBibfiles, AnalyseTexNeedsPs, AnalyseTexRmligs, AnalyseTexDatatool) - -class AnalyseLogErrors(Analyser): - def __init__(self, d): - d.errors = False - Analyser.__init__(self, d) - def parse(self, text): - if re_error.search(text): - self.d.errors = True - -class Request(): - def __init__(self, progname, priority=0, invocation=None, reason=None): - self.progname = progname - self.priority = priority - self.invocation = invocation - self.reason = reason - -class AnalyseLogRequests(Analyser): - def __init__(self, d): - d.requests = {} - Analyser.__init__(self, d) - def addrequest(self, name, priority, invocation=None, reason=None): - if self.d.requests.has_key(name): - oldreq = self.d.requests[name] - if oldreq.priority < priority: - oldreq.priority = priority - if reason: - oldreq.reason = reason - if invocation: - oldreq.invocation = invocation - else: - if not oldreq.reason: - oldreq.reason = reason - if not oldreq.invocation: - oldreq.invocation = invocation - else: - self.d.requests[name] = Request(name, priority, invocation, reason) - def parse(self, text): - for m in re_logmatcher.finditer(text): - if m.group() == 'LaTeX Warning: There were undefined references.': - self.addrequest("latex", 0, reason=" (because of undefined references)") - elif m.group() == 'LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.': - self.addrequest("latex", 0, reason=" (because of changed labels)") - elif m.group()[-5:] == ".bbl.": - self.addrequest("bibtex", 1, reason=" (because of missing .bbl)") - self.addrequest("latex", 0, reason=" (because of updated .bbl)") - elif m.group(1)!=None: - self.addrequest(m.group(2), int(m.group(1))) - elif m.group(3)!=None: - pri = int(m.group(3)) - progname = m.group(4) - binary = None - options = [] - infile = None - for l in re_longreq.finditer(m.group(5)): - if l.group(1) == "infile": - infile = l.group(2) - elif l.group(1) == "option": - options.extend(l.group(2).split(" ")) - elif l.group(1) == "binary": - binary = l.group(2) - if binary not in ("bibtex", "bibtex8"): - error(self.d.name, "ignoring request to run %s for security reasons"%binary, warning=True) - continue - options[:0] = [binary] - if binary == "bibtex8": - options[1:1] = [ "--wolfgang" ] - if infile != None: - options.append(infile) - self.addrequest(progname, pri, invocation=tuple(options)) - def finish(self, _): - if self.d.errors: - self.addrequest("latex", 0, reason=" (because of errors in .log file)") - reqdict=self.d.requests - maxpri=0 - for req in reqdict.itervalues(): - if req.priority > maxpri: - maxpri = req.priority - reqlist = [] - for pri in range(maxpri, -1 , -1): - for req in reqdict.itervalues(): - if req.priority == pri: - reqlist.append(req) - self.d.requests = reqlist - -loganalysers = (AnalyseLogErrors, AnalyseLogRequests) - -analysecachedir = None -analysecache = {} - -def analyseFile(dirname, filename, analyserclasses, parsetype, fulltext=False, cache=False, recurse=None, recursesystemfiles=False): - global analysecachedir, analysecache - if dirname != analysecachedir: - analysecachedir = dirname - analysecache = {} - pathname = os.path.join(dirname, filename) - if cache and (parsetype, pathname) in analysecache: - return analysecache[(parsetype, pathname)] - data = AnalyserData(pathname, parsetype) - analysers = [] - for analyser in analyserclasses: - analysers.append(analyser(data)) - try: - f = open(pathname, "r") - if fulltext: - text = f.read() - if parsetype == "tex": - text = re_texcomment.sub("", text) - for a in analysers: - a.parse(text) - else: - for line in f: - for a in analysers: - a.parse(line) - except IOError, e: - error(pathname, "could not be analysed: %s"%e) - else: - f.close() - if hasattr(data, "deps") and (recurse - or (recurse==None - and hasattr(data, "required") - and data.required)): - # recurse: - for dep, extlist in data.deps: - try: - deppath = texpath(dirname, dep, extlist=extlist) - except ValueError, e: - continue - if (not recursesystemfiles) and re_systemfile.search(deppath): # skip system files - continue - depname = strippath(deppath, dirname) - depdata = analyseFile(dirname, depname, analyserclasses, parsetype, fulltext, cache, True, recursesystemfiles) - for a in analysers: - a.merge(depdata) - if (hasattr(data, "required") and data.required) or parsetype == "log": - for a in analysers: - a.finish(dirname) - if cache: - analysecache[(parsetype, pathname)] = data - return data - -def analyseTex(dirname, filename): - return analyseFile(dirname, filename, texanalysers, "tex", fulltext=True, cache=True) - -def analyseLog(dirname, filename): - return analyseFile(dirname, filename, loganalysers, "log", fulltext=True, cache=False) - -binpath = os.path.expandvars("$PATH") -if binpath == "$PATH": - binpath = os.path.defpath -binpath = binpath.split(os.path.pathsep) -def isinpath(name): - for p in binpath: - if os.path.exists(os.path.join(p, name)): - return True - return False - -if isinpath("rmligs"): - rmligs_name = "rmligs" -elif isinpath("rmligs-german"): - rmligs_name = "rmligs-german" -else: - rmligs_name = "" - error("rmligs", "Command not found. Please install rmligs (or rmligs-german) for optimal results", warning=True) - -kpsecache = {} -kpseproc = {} -haskpseinter = isinpath("kpseinter") -def kpselookup(lookupname, pathtype, progname): - if not kpsecache.has_key((pathtype,progname)): - kpsecache[(pathtype,progname)] = {} - cache = kpsecache[(pathtype,progname)] - if cache.has_key(lookupname): - if cache[lookupname]: - return cache[lookupname] - else: - raise ValueError("not found by kpathsea: %s"%lookupname) - if not haskpseinter: - kpse=subprocess.Popen(["kpsewhich", "-format", pathtype, "-progname", progname, lookupname], - stdout=subprocess.PIPE, - cwd="/") - (out,err)=kpse.communicate() - if kpse.wait() == 0: - pathname = out[:-1] - cache[lookupname] = pathname - return pathname - else: - cache[lookupname] = None - raise ValueError("not found by kpathsea: %s"%lookupname) - else: - if kpseproc.has_key((pathtype, progname)): - proc, master = kpseproc[(pathtype, progname)] - os.write(master, lookupname + "\n") - else: - master, slave = pty.openpty() - - #turn off echo - attr = termios.tcgetattr(slave) - attr[3] = attr[3] & ~termios.ECHO - termios.tcsetattr(slave, termios.TCSANOW, attr) - - proc = subprocess.Popen(["kpseinter", "--interactive", - "-format", pathtype, - "-progname", progname, - lookupname], - stdout=slave, - stdin=slave, - cwd="/") - kpseproc[(pathtype, progname)] = proc, master - answer = os.read(master, 1024) - while answer and answer[-1] in ("\n", "\r"): - answer = answer[:-2] - if answer != "": - cache[lookupname] = answer - return answer - else: - cache[lookupname] = None - raise ValueError("not found by kpathsea: %s"%lookupname) - -def texpath(dirname,filename,pathtype="tex",progname="latex",extlist=("",)): - if extlist == None: - return filename - filename = os.path.expanduser(filename) - # first try files in current directory - if pathtype=="bib" and extlist==("",): - extlist=(".bib", "") - for ext in extlist: - if os.path.exists(os.path.join(dirname,filename+ext)): - return filename+ext - if opts.nokpse: - raise ValueError("file not found, not using kpsewhich: %s (extensions: %r)"%(filename, extlist)) - # call kpsewhich to locate the file - for ext in extlist: - try: - path = kpselookup(filename + ext, pathtype, progname) - return path - except ValueError: - pass - raise ValueError("not found by kpathsea: %s (extensions: %r)"%(filename,extlist)) - -errors = [] -procfiles = [] - -errstr = {False: "ERROR", True: "WARNING"} -def error(file, desc, warning=False): - msg = "%s: %s: %s"%(errstr[warning], os.path.normpath(file), desc) - if opts.verbosity: - print msg - errors.append(msg) - -null = file(os.path.devnull, "wb") - -# platform checking: -iswindows = (sys.platform == "win32") - -# provide a (modified) copy of os.path.relpath from python 2.6 -def relpath(pathname, start=os.path.curdir): - """Return a relative version of a path""" - - if not iswindows: - pathname = os.path.expanduser(pathname) - start_list = os.path.abspath(start).split(os.path.sep) - path_list = os.path.abspath(pathname).split(os.path.sep) - - # Work out how much of the filepath is shared by start and path. - i = len(os.path.commonprefix([start_list, path_list])) - - rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] - return os.path.join(*rel_list) - else: - start_list = os.path.abspath(start).split(os.path.sep) - path_list = os.path.abspath(pathname).split(os.path.sep) - if start_list[0].lower() != path_list[0].lower(): - unc_path, rest = os.path.splitunc(pathname) - unc_start, rest = os.path.splitunc(start) - if bool(unc_path) ^ bool(unc_start): - raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" - % (pathname, start)) - else: - raise ValueError("path is on drive %s, start on drive %s" - % (path_list[0], start_list[0])) - # Work out how much of the filepath is shared by start and path. - for i in range(min(len(start_list), len(path_list))): - if start_list[i].lower() != path_list[i].lower(): - break - else: - i += 1 - - rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:] - return os.path.join(*rel_list) - -def strippath(pathname, start): - pathname = os.path.expanduser(pathname) - pathname = os.path.abspath(os.path.join(start, pathname)) - start = os.path.abspath(start) - if pathname[:len(start)] == start: - return pathname[len(start)+1:] - else: - return pathname - -def alltexfiles(arglist): - """iterate over all .tex files that are not ignored by -I""" - for a in arglist: - if os.path.isdir(a): - for directory, subdirs, files in os.walk(a): - if not opts.recurse: - subdirs[:] = [] - else: - for skipdir in (".svn", ".bzr"): - if skipdir in subdirs: - subdirs.remove(skipdir) - for name in files: - if re_texfile.match(name): - if re_ignore.match(name): - if opts.verbosity > 2: - print "%s: skipped because of ignored name"%os.path.normpath(os.path.join(directory,name)) - else: - yield (directory, name) - elif os.path.exists(a): - if re_texfile.match(a): - (dirname, filename) = os.path.split(a) - if dirname == "": - dirname = "." - yield (dirname, filename) - else: - error(a, "is no .tex file; skipped") - elif os.path.exists(a+".tex"): - (dirname, filename) = os.path.split(a+".tex") - if dirname == "": - dirname = "." - yield(dirname, filename) - else: - error(a, "file not found") - -def needsupdate(dirname, texname, data=None): - jobname = texname[:-4] - - if data == None: - data = analyseTex(dirname, texname) - - # skip non-main files - if not data.required: - if opts.verbosity > 2: - print "%s: skipped because no main latex file"%os.path.normpath(os.path.join(dirname,texname)) - return False - - # silent force - if opts.force and not opts.verbosity: - return True - - # check for nonexistant output file - outname = jobname + ".pdf" - outpath = os.path.join(dirname, outname) - if not os.path.exists(outpath): - return " (because .pdf does not exist)" - - # check for updated source and dependency files - outdate = os.path.getmtime(outpath) - if outdate < os.path.getmtime(os.path.join(dirname, texname)): - return " (because .tex is newer than .pdf)" - for deppath, extlist in data.deps: - assert extlist == None - if outdate < os.path.getmtime(os.path.join(dirname, deppath)): - return " (because %s is newer than .pdf)"%deppath - - # check for errors and requests - logname = jobname + ".log" - if os.path.exists(os.path.join(dirname, logname)): - logdata = analyseLog(dirname, jobname + ".log") - if logdata.errors: - return " (because of error(s) in .log file)" - if logdata.requests: - return " (because of request(s) in .log file)" - - # verbose force - if opts.force: - return " (because of --force)" - - # up to date - if opts.verbosity > 2: - print "%s: skipped because up-to-date"%os.path.normpath(os.path.join(dirname, texname)) - return False - -MAXRUNS=5 -def processTex(dirname, texname, data=None, reason=""): - #strip .tex extension - jobname=texname[:-4] - jobpath = os.path.join(dirname,jobname) - texpath = jobpath + ".tex" - procfiles.append(os.path.normpath(texpath)) - - if data == None: - data = analyseTex(dirname, texname) - - if opts.verbosity: - print "processing %s%s..."%(os.path.normpath(texpath),reason) - - # list of temporary files to be removed later - tmplist = [] - - # support for pstricks/plain latex: - if data.needsPS: - tex = "latex" - else: - tex = "pdflatex" - - # detect usage of german/ngerman and generate temporary files with rmlig - realname = texname - - if data.rmligs: - realname = preparermligs(texname, dirname, texpath, tmplist) - - # remove all outdated .bbl files (will be recreated by requests) - bbls = bblfiles(dirname, jobname) - for bib in data.bibfiles: - bibpath = os.path.join(dirname, bib) - bibtime = 0 - if os.path.exists(bibpath): - bibtime = os.path.getmtime(bibpath) - nextbbls = bbls[:] - for bbl in bbls: - bblpath = os.path.normpath(os.path.join(dirname, bbl)) - bbltime = os.path.getmtime(bblpath) - if (opts.force and not opts.singlerun) or bbltime < bibtime: - reason = "" - if opts.verbosity: - if bbltime < bibtime: - reason = " (because %s is newer than %s)"%(bib,bbl) - else: - reason = " (because of --force)" - rmtempfile(bblpath, force=True, reason=reason) - nextbbls.remove(bbl) - bbls = nextbbls - - runtex(tex, texname, realname, dirname) - - if not opts.singlerun: - # check for undefined references and run requests - numrun=0 - reqs=opts.act # ignore requests if programs are not run - logname = jobname + ".log" - while reqs: - logdata = analyseLog(dirname, logname) - reqs = logdata.requests - for req in reqs: - reason = "" - if opts.verbosity: - if req.reason: - reason = req.reason - else: - reason = " (because of request in .log file, priority %d)"%req.priority - if req.invocation: - run(req.invocation, dirname, reason) - elif req.progname == "latex": - runtex(tex, texname, realname, dirname, reason=reason) - elif req.progname == "bibtex": - run( ("bibtex", jobname), dirname, reason) - else: - error(jobpath+".log", "unsupported request: %s"%req) - numrun+=1 - if numrun==MAXRUNS: - error(texpath, "does not stabilise after %i runs"%MAXRUNS) - break - - # update index if it exists - no way of knowing if it was updated - if os.path.exists(jobpath + ".idx"): - run(["makeindex", jobname], dirname, reason=" (because .idx file might have changed)") - runtex(tex, texname, realname, dirname, reason=" (because .ind file might have changed)") - - if data.needsPS: - run(["dvips", jobname+".dvi"], dirname, stderr=subprocess.STDOUT) - run(["ps2pdf", jobname+".ps"], dirname) - - rmtempfile(tmplist) - -def bblfiles(dirname, jobname): - files = dircache.listdir(dirname) - return fnmatch.filter(files, "%s*.bbl"%jobname) - -def rmtempfile(filenames, force=False, reason=""): - if (opts.deletetempfiles or force) and filenames: - if not isinstance(filenames, list): - filenames = [filenames] - if opts.verbosity > 1: - print " removing %s%s"%(", ".join(filenames), reason) - if opts.act: - for f in filenames: - if os.path.exists(f): - os.remove(f) - else: - error(f, "could not be removed (does not exist)", warning=True) - -def run(arglist, dirname, reason="", inf=None, outf=None, stderr=None): - """Run a command with optional io redirections. - - arglist -- list of progam name and arguments - dirname -- the directory the command will be executed in - reason -- reason for running this command, used in progress output - inf -- file to be used as stdin, or alternativly a filter function for user input - outf -- file to be used as stdout, or alternativly a filter function for program output - stderr -- file to be used as stderr - """ - if opts.verbosity: - redir ="" - if hasattr(inf, "name") and inf.name != "" and inf.name[0] != "<": - name = relpath(inf.name, dirname) - redir = " < %s"%name - print " running %s%s%s..."%(" ".join(arglist), redir, reason) - - if opts.act: - master, slave = None, None - - if isinstance(inf, file): - stdin = inf - inf = None - elif opts.showoutput and not iswindows: - master, slave = pty.openpty() - master = os.fdopen(master, "rw") - stdin=slave - elif inf or opts.showoutput: - stdin=subprocess.PIPE - else: - stdin=null - - if isinstance(outf, file): - stdout = outf - outf = None - elif opts.showoutput and not iswindows: - if slave == None: - master, slave = pty.openpty() - master = os.fdopen(master, "rw") - stdout=slave - elif outf or opts.showoutput: - stdout=subprocess.PIPE - else: - stdout=null - - try: - proc = subprocess.Popen(arglist, stdin=stdin, stdout=stdout, stderr=stderr, cwd=dirname) - - if stdin == slave and stdin != None: - childin = master - else: - childin = proc.stdin - if stdout == slave and stdout != None: - childout = master - else: - childout = proc.stdout - - selectlist = [] - outlist = [] - if childin != None: - selectlist.append(sys.stdin) - if childout != None: - selectlist.append(childout) - outlist.append(childout) - - while proc.poll() == None or select.select(outlist, [], [], 0)[0]: - ready = select.select(selectlist, [], [], 0.1)[0] - for f in ready: - if f == childout: - data = os.read(childout.fileno(), 1024) - if data == "": # EOF - outlist.remove(childout) - selectlist.remove(childout) - continue - if outf: data = outf(data) - if data != None: - sys.stdout.write(data) - sys.stdout.flush() - if f == sys.stdin: - if proc.poll() != None: - # process terminated, does not take input anymore - selectlist.remove(sys.stdin) - continue - data = os.read(sys.stdin.fileno(), 1024) - if data == "": # EOF - selectlist.remove(sys.stdin) - continue - if inf: data = inf(data) - if data != None: - childin.write(data) - childin.flush() - ret = proc.wait() - if ret: - error(dirname, "failed command: %s returned %i"%(" ".join(arglist), ret)) - except (OSError, IOError), e: - error(dirname, "failed command: %s: %s"%(" ".join(arglist),str(e))) - -def runtex(tex, texname, realname, dirname, reason=""): - if not opts.showoutput: - outf = None - else: - def outf(d): - d = re_fixemacserrorshowing.sub("", d) - return re_rmligsfile.sub("\\1.tex", d) - if texname != realname: - run([tex, "-interaction", opts.interactionmode, "-jobname", texname[:-4], realname], dirname, outf=outf, reason=reason) - else: - run([tex, "-interaction", opts.interactionmode, texname], dirname, outf=outf, reason=reason) - -def preparermligs(texname, dirname, texpath, tmplist): - try: - texfile = open(texpath) - except IOError, (errno, strerror): - error(texpath, "could not be read: %s. Not using rmligs."%strerror) - return texname - else: - try: - (subdir, texbasename) = os.path.split(texname) - rmligsbasename = "%s-rmligs.tex"%texbasename[:-4] - rmligsname = os.path.join(subdir, rmligsbasename) - rmligspath = os.path.join(dirname, rmligsname) - if opts.act: - rmligsfile = open(rmligspath, "w") - else: - rmligsfile = null - except IOError, (errno, strerror): - error(rmligspath, "could not be written: %s. Not using rmligs."%strerror) - return texname - else: - tmplist.append(rmligspath) - def rewriteinputrmligs(m): - name = m.group(2) - if not os.path.exists(os.path.join(dirname,name)): - name+=".tex" - path = os.path.join(dirname, name) - if os.path.exists(path): - name = preparermligs(name, dirname, path, tmplist) - else: - error(texpath, "%s: File could not be located. Not using rmligs."%name, warning=True) - return "\\%s{%s}"%(m.group(1), name[:-4]) - def filteroutput(d): - d = re_commentinclude.sub("", d) - rmligsfile.write(re_inputinclude.sub(rewriteinputrmligs, d)) - return None - run([rmligs_name, "-f"], dirname, inf=texfile, outf=filteroutput) - - texfile.close() - if rmligsfile is not null: - rmligsfile.close() - return rmligsname - -# main program: -def main(arguments): - if not arguments: - arguments = (".",) - - for dirname, texname in alltexfiles(arguments): - data = analyseTex(dirname, texname) - reason = needsupdate(dirname, texname, data) - if reason: - processTex(dirname, texname, data, reason) - - - if opts.summary in [ "files", "both" ] : - if procfiles: - print "Processed the following files:" - for f in procfiles: - print " %s"%f - else: - print "Processed no files." - if opts.summary in [ "failures", "both" ] : - if errors: - print "The following problems occured:" - lasterr="" - for f in errors: - if f != lasterr: - print " %s"%f - lasterr = f - - if errors: - sys.exit(1) - -try: - if __name__ == "__main__": - # setup global variables - opts, programargs = TexallOptionParser().parse_args() - else: - opts, programargs = TexallOptionParser().parse_args([]) - - re_ignore = None - if opts.ignorepattern != "": - re_ignore = re.compile(opts.ignorepattern) - - re_texfile = re.compile(".*\.tex$", re.I) - if iswindows: - re_systemfile = re.compile("^?:\\\\Program|\\.(sty|cls)$", re.I) - re_nonlocal = re.compile("^?:\\\\") - else: - re_systemfile = re.compile("^/usr/|\\.(sty|cls)$") - re_nonlocal = re.compile("^/") - - re_texcomment = re.compile("(?<!\\\\)%.*?$", re.M) - - re_required = re.compile(opts.requiredpattern, re.M) - - re_inputinclude = re.compile('\\\\(input|include|@input)\\{([^}]*)\\}') - re_commentinclude = re.compile('(?<!\\\\)%[^%\n\r]*\\\\(input|include|@input)\\{([^}]*)\\}[^%\n\r]*?$', re.M) - re_documentclass = re.compile('\\\\documentclass(\\[[^]]*\\])?\\{([^}]*)\\}') - re_usepackage = re.compile('\\\\usepackage(\\[[^]]*\\])?\\{([^}]*)\\}') - re_usetheme = re.compile('\\\\use(|color|font|inner|outer)theme(\\[[^]]*\\])?\\{([^}]*)\\}') - re_graphics = re.compile('\\\\includegraphics(\\[[^]]*\\])?\\{([^}]*)\\}') - re_DTLdep = re.compile('\\\\DTLload(rawdb|db)\\{[^}]*\\}\\{([^}]*)\\}') - - re_bibliography = re.compile('^[^%\n\r]*\\\\bibliography\\{([^}]*)\\}', re.M) - - re_commawhitespace = re.compile('\\s*,\\s*') - - re_needsps = re.compile('\\\\usepackage(\\[[^]]*\\])?\\{[^}]*pstricks[^}]*\\}') - re_rmligs = re.compile('\\\usepackage((\\[[^]]*\\])?\\{n?german\\}|\\[[^]]*?german[^]]*\\]\\{babel\\})') - - re_logmatcher = re.compile("^LaTeX Warning: There were undefined references\.$|^LaTeX Warning: Label\(s\) may have changed\. Rerun to get cross-references right\.$|^REQ:(\d+):(\w+):REQ|^REQ:(\d+):(\w+):(.*?):REQ$|^No file [^\n]+\.bbl\.$", re.M | re.S) - re_longreq = re.compile("^(binary|option|infile)=(.*?)$", re.M) - - re_error = re.compile('^! ', re.M) - re_rmligsfile = re.compile("([^/ ]+)-rmligs\\.tex") - re_fixemacserrorshowing = re.compile(" \(Web2C [0-9.]*\)") - - if __name__ == "__main__": - #import cProfile - #import pstats - #cProfile.run("main(programargs)", "mystats") - #p = pstats.Stats("mystats") - #p.sort_stats('time').print_stats() - - main(programargs) - -except KeyboardInterrupt: - sys.exit(2) -else: - for proc, master in kpseproc.values(): - os.close(master) - os.kill(proc.pid, signal.SIGHUP) |
