From 37b5728aca04d2aa94f285ce9a25aff7c2308cd4 Mon Sep 17 00:00:00 2001 From: Sebastian Kuhnert Date: Mon, 25 Aug 2008 08:52:47 +0000 Subject: texall script: finish pty support --- texall | 152 ++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 38 deletions(-) (limited to 'texall') diff --git a/texall b/texall index dcefe73..82516ce 100755 --- a/texall +++ b/texall @@ -4,7 +4,9 @@ from optparse import OptionParser import sys import os import os.path +import pty import re +import select import subprocess parser = OptionParser(usage="%prog [options] DIR/FILE", @@ -28,9 +30,12 @@ parser.add_option("-v", "--verbose", parser.add_option("-q", "--quiet", action="store_const", dest="verbosity", const=0, help="suppress progress reports") +parser.add_option("-o", "--show-output", + action="store_true", dest="showoutput", default=False, + help="show the output of the called programs") parser.add_option("-i", "--interaction", - dest="interactionmode", choices=("batchmode", "nonstopmode", "scrollmode", "errorstopmode"), default="batchmode", - help="control the behaviour of latex (on of batchmode (default), nonstopmode, scrollmode, errorstopmode)") + dest="interactionmode", choices=("batchmode", "nonstopmode", "scrollmode", "errorstopmode"), + help="control the behaviour of latex (on of batchmode (default), nonstopmode (default for -o), scrollmode, errorstopmode)") parser.add_option("-I", "--ignore", action="store", dest="ignorepattern", default=".*vorlage.*|\.\#.*", help="regular expression of filenames to ignore") @@ -45,6 +50,12 @@ parser.add_option("-S", "--single-run", help="stop after the first LaTeX run, no matter if finished") (options, args) = parser.parse_args() +if options.interactionmode == None: + if options.showoutput: + options.interactionmode = "nonstopmode" + else: + options.interactionmode = "batchmode" + re_ignore = None if options.ignorepattern != "": re_ignore = re.compile(options.ignorepattern) @@ -404,28 +415,98 @@ def rmtempfile(filename, dirname): else: error(fullname, "could not be removed (does not exist)", warning=True) -def run(arglist, dirname, reason="", stdin=None, stdout=None, stderr=None, doio=None): - if options.interactionmode == "batchmode": - if not stdout: - stdout=null - if not stderr: - stderr=null +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 options.verbosity: - redir = "" - if hasattr(stdin, "name"): - redir = "%s < %s"%(redir, stdin.name) - if hasattr(stdout, "name") and stdout is not null: - redir = "%s > %s"%(redir, stdout.name) - if hasattr(stderr, "name") and stderr is not null: - redir = "%s 2> %s"%(redir, stderr.name) - print " running %s%s%s..."%(" ".join(arglist), redir, reason) + print " running %s%s..."%(" ".join(arglist), reason) + if options.act: - proc = subprocess.Popen(arglist, stdin=stdin, stdout=stdout, stderr=stderr, cwd=dirname) - if doio: - doio(proc) - ret = proc.wait() - if ret: - error(dirname, "failed command: %s"%(" ".join(arglist))) + master, slave = None, None + + if isinstance(inf, file): + stdin = inf + inf = None + elif options.showoutput and not subprocess.mswindows: + master, slave = pty.openpty() + master = os.fdopen(master, "rw") + stdin=slave + elif inf or options.showoutput: + stdin=subprocess.PIPE + else: + stdin=null + + if isinstance(outf, file): + stdout = outf + outf = None + elif options.showoutput and not subprocess.mswindows: + if slave == None: + master, slave = pty.openpty() + master = os.fdopen(master, "rw") + stdout=slave + elif outf or options.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 preparermligs(texname, dirname, tmplist): jobname=texname[:-4] @@ -458,10 +539,10 @@ def preparermligs(texname, dirname, tmplist): else: error(os.path.join(dirnam, texname), "%s: File could not be located. Not using rmligs."%name, warning=True) return "\\%s{%s}"%(m.group(1), name[:-4]) - def doio(p): - for line in p.stdout: - rmligsfile.write(re_inputinclude.sub(rewriteinputrmligs, line)) - run([rmligs_name, "-f"], dirname, stdin=texfile, stdout=subprocess.PIPE, doio=doio) + def filteroutput(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: @@ -469,21 +550,16 @@ def preparermligs(texname, dirname, tmplist): return rmligsname re_rmligsfile = re.compile("\\.([^/ ]+)\\.rmligs\\.tex") -def rmligscleanoutput(p): # filter tex output to make emacs jump to the right source positions - for l in p.stdout: - sys.stdout.write(re_rmligsfile.sub("\\1.tex", l)) - sys.stdout.flush() def runtex(tex, texname, realname, dirname, reason=""): + if not options.showoutput: + outf = None + else: + def outf(d): + return re_rmligsfile.sub("\\1.tex", d) if texname != realname: - if options.interactionmode == "batchmode": - stdout = None - doio = None - else: - stdout = subprocess.PIPE - doio = rmligscleanoutput - run([tex, "-interaction", options.interactionmode, "-jobname", texname[:-4], realname], dirname, stdout=stdout, doio=doio, reason=reason) + run([tex, "-interaction", options.interactionmode, "-jobname", texname[:-4], realname], dirname, outf=outf, reason=reason) else: - run([tex, "-interaction", options.interactionmode, texname], dirname, reason=reason) + run([tex, "-interaction", options.interactionmode, texname], dirname, outf=outf, reason=reason) # main program: try: -- cgit v1.2.3