def first_run_needed (self): """ The condition is only on the database files' modification dates, but it would be more clever to check if the results have changed. BibTeXing is also needed when the last run of BibTeX failed, and in the very particular case when the style has changed since last compilation. """ if not exists(self.auxfile): return 0 if not exists(self.blgfile): return 1 dtime = getmtime(self.blgfile) for db in self.db.values(): if getmtime(db) > dtime: msg.log(_("bibliography database %s was modified") % db, pkg="bibtex") return 1 blg = open(self.blgfile) for line in blg.readlines(): if re_error.search(line): blg.close() msg.log(_("last BibTeXing failed"), pkg="bibtex") return 1 blg.close() if self.style_changed(): return 1 if self.bst_file and getmtime(self.bst_file) > dtime: msg.log(_("the bibliography style file was modified"), pkg="bibtex") return 1 return 0
def externaldocument (self, dict): # .aux document needed to cross-ref with xr auxfile = dict["arg"] + ".aux" texfile = dict["arg"] + ".tex" # Ignore the dependency if no tex source found if not(os.path.isfile(texfile)): msg.log(_("file %s is required by xr package but not found")\ % texfile, pkg="xr") return # Ask to compile the related .tex file to have the .aux texdep = Latex(self.env) texdep.set_source(texfile) texdep.batch = self.doc.batch texdep.encoding = self.doc.encoding texdep.draft_only = True # Final output not required here for m in self.texmodules: texdep.modules.register(m) # Load other modules from source, except xr to avoid loops texdep.prepare(exclude_mods=["xr-hyper"]) # Add the .aux as an expected input for compiling the doc self.doc.sources[auxfile] = texdep msg.log(_( "dependency %s added for external references") % auxfile, pkg="xr")
def first_run_needed(self): """ The condition is only on the database files' modification dates, but it would be more clever to check if the results have changed. BibTeXing is also needed when the last run of BibTeX failed, and in the very particular case when the style has changed since last compilation. """ if not exists(self.auxfile): return 0 if not exists(self.blgfile): return 1 dtime = getmtime(self.blgfile) for db in self.db.values(): if getmtime(db) > dtime: msg.log(_("bibliography database %s was modified") % db, pkg="bibtex") return 1 blg = open(self.blgfile) for line in blg.readlines(): if re_error.search(line): blg.close() msg.log(_("last BibTeXing failed"), pkg="bibtex") return 1 blg.close() if self.style_changed(): return 1 if self.bst_file and getmtime(self.bst_file) > dtime: msg.log(_("the bibliography style file was modified"), pkg="bibtex") return 1 return 0
def run (self): # FIXME if len(self.prods) == 1: msg.error(_("%r does not exist") % self.prods[0], **self.loc) else: msg.error(_("one of %r does not exist") % self.prods, **self.loc) return 1
def run (self): msg.progress(_("running %s") % self.cmd[0]) rc = subprocess.call(self.cmd, stdout=msg.stdout) if rc != 0: msg.error(_("execution of %s failed") % self.cmd[0]) return 1 return 0
def run(self): cmd = [self.cmdexec] msg.progress(_("running %s on %s") % (cmd[0], self.source)) for opt in self.doc.paper.split(): cmd.extend(["-t", opt]) cmd.extend(self.options + ["-o", self.target, self.source]) msg.debug(" ".join(cmd)) rc = subprocess.call(cmd, stdout=msg.stdout) if rc != 0: msg.error(_("%s failed on %s") % (cmd[0], self.source)) return 1 return 0
def run (self): cmd = [self.cmdexec] msg.progress(_("running %s on %s") % (cmd[0], self.source)) for opt in self.doc.paper.split(): cmd.extend(["-t", opt]) cmd.extend(self.options + ["-o", self.target, self.source]) msg.debug(" ".join(cmd)) rc = subprocess.call(cmd, stdout=msg.stdout) if rc != 0: msg.error(_("%s failed on %s") % (cmd[0], self.source)) return 1 return 0
def compile(self): self.must_compile = 0 cmd = [self.program] + self.opts + [os.path.basename(self.srcfile)] msg.log(" ".join(cmd)) rc = subprocess.call(cmd, stdout=msg.stdout) if rc != 0: msg.error(_("%s failed") % self.program) # Whatever the result is, read the log file if self.log.read(self.logfile): msg.error(_("Could not run %s.") % self.program) return 1 if self.log.errors(): return 1 return rc
def do_order (self, *args): for opt in args: if opt == "standard": self.opts = [] elif opt == "german": self.opts.append("-g") elif opt == "letter": self.opts.append("-l") else: msg.warn( _("unknown option '%s' for 'makeidx.order'") % opt)
def clean (self): """ Remove all generated files related to the index. """ for file in self.source, self.target, self.transcript: if exists(file): msg.log(_("removing %s") % file, pkg="index") os.unlink(file)
def recompile_needed (self): """ Returns true if another compilation is needed. This method is used when a compilation has already been done. """ changed = self.watcher.update() if self.must_compile: return 1 if self.log.errors(): msg.debug(_("last compilation failed")) return 1 # if self.deps_modified(os.path.getmtime(self.outfile)): # msg.debug(_("dependencies were modified")) # return 1 if changed and (len(changed) > 1 or changed[0] != self.auxfile): msg.debug(_("the %s file has changed") % changed[0]) return 1 if self.log.run_needed(): msg.debug(_("LaTeX asks to run again")) if (not(changed)): msg.debug(_("but the aux files are unchanged")) return 0 return 1 if changed: msg.debug(_("the %s file has changed but no re-run required?") \ % changed[0]) if self.program == "xelatex": msg.debug(_("force recompilation (XeTeX engine)")) return 1 msg.debug(_("no new compilation is needed")) return 0
def recompile_needed(self): """ Returns true if another compilation is needed. This method is used when a compilation has already been done. """ changed = self.watcher.update() if self.must_compile: return 1 if self.log.errors(): msg.debug(_("last compilation failed")) return 1 # if self.deps_modified(os.path.getmtime(self.outfile)): # msg.debug(_("dependencies were modified")) # return 1 if changed and (len(changed) > 1 or changed[0] != self.auxfile): msg.debug(_("the %s file has changed") % changed[0]) return 1 if self.log.run_needed(): msg.debug(_("LaTeX asks to run again")) if (not (changed)): msg.debug(_("but the aux files are unchanged")) return 0 return 1 if changed: msg.debug(_("the %s file has changed but no re-run required?") \ % changed[0]) if self.program == "xelatex": msg.debug(_("force recompilation (XeTeX engine)")) return 1 msg.debug(_("no new compilation is needed")) return 0
def post_compile (self): """ This method runs BibTeX if needed to solve undefined citations. If it was run, then force a new LaTeX compilation. """ if not self.bibtex_needed(): msg.log(_("no BibTeXing needed"), pkg="bibtex") return 0 return self.run()
def post_compile(self): """ This method runs BibTeX if needed to solve undefined citations. If it was run, then force a new LaTeX compilation. """ if not self.bibtex_needed(): msg.log(_("no BibTeXing needed"), pkg="bibtex") return 0 return self.run()
def remove_suffixes(self, list): """ Remove all files derived from the main source with one of the specified suffixes. """ for suffix in list: file = self.src_base + suffix if os.path.exists(file): msg.log(_("removing %s") % file) os.unlink(file)
def remove_suffixes (self, list): """ Remove all files derived from the main source with one of the specified suffixes. """ for suffix in list: file = self.src_base + suffix if os.path.exists(file): msg.log(_("removing %s") % file) os.unlink(file)
def run(self): """ This method actually runs BibTeX with the appropriate environment variables set. """ msg.progress(_("running BibTeX on %s") % self.base) doc = {} if len(self.bib_path) != 1: os.environ["BIBINPUTS"] = string.join( self.bib_path + [os.getenv("BIBINPUTS", "")], ":") if len(self.bst_path) != 1: os.environ["BSTINPUTS"] = string.join( self.bst_path + [os.getenv("BSTINPUTS", "")], ":") rc = subprocess.call(["bibtex", self.base], stdout=msg.stdout) if rc != 0: msg.error(_("There were errors making the bibliography.")) return 1 self.run_needed = 0 self.doc.must_compile = 1 return 0
def newindex (self, dict): """ Register a new index. """ m = re_newindex.match(dict["line"]) if not m: return index = dict["arg"] d = m.groupdict() self.register(index, d["idx"], d["ind"], "ilg") msg.log(_("index %s registered") % index, pkg="index")
def __init__(self, doc, dict): self.doc = doc lastdep = doc.env.dep_last() dvi = lastdep.prods[0] root, ext = os.path.splitext(dvi) if ext != ".dvi": msg.error(_("I can't use dvips when not producing a DVI")) sys.exit(2) ps = root + ".ps" self.dep = Dep(doc, ps, dvi, lastdep) doc.env.dep_append(self.dep)
def run (self): """ This method actually runs BibTeX with the appropriate environment variables set. """ msg.progress(_("running BibTeX on %s") % self.base) doc = {} if len(self.bib_path) != 1: os.environ["BIBINPUTS"] = string.join(self.bib_path + [os.getenv("BIBINPUTS", "")], ":") if len(self.bst_path) != 1: os.environ["BSTINPUTS"] = string.join(self.bst_path + [os.getenv("BSTINPUTS", "")], ":") rc = subprocess.call(["bibtex", self.base], stdout=msg.stdout) if rc != 0: msg.error(_("There were errors making the bibliography.")) return 1 self.run_needed = 0 self.doc.must_compile = 1 return 0
def __init__ (self, doc, dict): self.doc = doc lastdep = doc.env.dep_last() dvi = lastdep.prods[0] root, ext = os.path.splitext(dvi) if ext != ".dvi": msg.error(_("I can't use dvips when not producing a DVI")) sys.exit(2) ps = root + ".ps" self.dep = Dep(doc, ps, dvi, lastdep) doc.env.dep_append(self.dep)
def last_compile(self): """ Run the module-specific operations that are to be performed after the last compilation of the main source. Returns true on failure. """ msg.log(_("running last-compilation scripts...")) for mod in self.modules.objects.values(): if mod.last_compile(): self.failed_module = mod return 1 return 0
def clean (self): """ Remove the files produced by this rule and recursively clean all dependencies. """ for file in self.prods: if os.path.exists(file): msg.log(_("removing %s") % file) os.unlink(file) for src in self.sources.values(): src.clean() self.date = None
def clean(self): """ Remove all files that are produced by compilation. """ self.remove_suffixes([".log", ".aux", ".toc", ".lof", ".lot", ".out", ".glo", ".cb"]) msg.log(_("cleaning additional files...")) # for dep in self.sources.values(): # dep.clean() for mod in self.modules.objects.values(): mod.clean()
def run_needed (self): """ Check if makeindex has to be run. This is the case either if the target file does not exist or if the source file has changed. """ if os.path.getsize(self.source) == 0: msg.log(_("the index file %s is empty") % self.source, pkg="index") return 0 new = md5_file(self.source) if not os.path.exists(self.target): self.md5 = new return 1 if not self.md5: self.md5 = new msg.log(_("the index file %s is new") % self.source, pkg="index") return 1 if self.md5 == new: msg.log(_("the index %s did not change") % self.source, pkg="index") return 0 self.md5 = new msg.log(_("the index %s has changed") % self.source, pkg="index") return 1
def clean(self): """ Remove all files that are produced by compilation. """ self.remove_suffixes( [".log", ".aux", ".toc", ".lof", ".lot", ".out", ".glo", ".cb"]) msg.log(_("cleaning additional files...")) # for dep in self.sources.values(): # dep.clean() for mod in self.modules.objects.values(): mod.clean()
def compile_needed(self): """ Returns true if a first compilation is needed. This method supposes that no compilation was done (by the script) yet. """ if self.must_compile: return 1 msg.log(_("checking if compiling is necessary...")) if not self.draft_support and not os.path.exists(self.outfile): msg.debug(_("the output file doesn't exist")) return 1 if not os.path.exists(self.logfile): msg.debug(_("the log file does not exist")) return 1 if (not self.draft_support and (os.path.getmtime(self.outfile) < os.path.getmtime(self.srcfile))): msg.debug(_("the source is younger than the output file")) return 1 if self.log.read(self.logfile): msg.debug(_("the log file is not produced by TeX")) return 1 return self.recompile_needed()
def compile_needed (self): """ Returns true if a first compilation is needed. This method supposes that no compilation was done (by the script) yet. """ if self.must_compile: return 1 msg.log(_("checking if compiling is necessary...")) if not self.draft_support and not os.path.exists(self.outfile): msg.debug(_("the output file doesn't exist")) return 1 if not os.path.exists(self.logfile): msg.debug(_("the log file does not exist")) return 1 if (not self.draft_support and (os.path.getmtime(self.outfile) < os.path.getmtime(self.srcfile))): msg.debug(_("the source is younger than the output file")) return 1 if self.log.read(self.logfile): msg.debug(_("the log file is not produced by TeX")) return 1 return self.recompile_needed()
def __init__ (self, doc, dict): env = doc.env ps = env.dep_last().prods[0] root, ext = os.path.splitext(ps) if ext != ".ps": msg.error(_("I can't use ps2pdf when not producing a PS")) sys.exit(2) pdf = root + ".pdf" cmd = ["ps2pdf"] for opt in doc.paper.split(): cmd.append("-sPAPERSIZE=" + opt) cmd.extend([ps, pdf]) dep = DependShell(env, cmd, prods=[pdf], sources={ ps: env.dep_last() }) env.dep_append(dep)
def update(self): """ Update the MD5 sums of all files watched, and return the name of one of the files that changed, or None of they didn't change. """ changed = [] for file in self.files.keys(): if os.path.exists(file): new = md5_file(file) if self.files[file] != new: msg.debug(_("%s MD5 checksum changed") % \ os.path.basename(file)) changed.append(file) self.files[file] = new return changed
def pre_compile(self, force): """ Prepare the source for compilation using package-specific functions. This function must return true on failure. This function sets `must_compile' to 1 if we already know that a compilation is needed, because it may avoid some unnecessary preprocessing (e.g. BibTeXing). """ # Watch for the changes of these working files for ext in ("aux", "toc", "lot", "lof"): self.watcher.watch(self.srcbase + "." + ext) msg.log(_("building additional files...")) for mod in self.modules.objects.values(): if mod.pre_compile(): self.failed_module = mod return 1 return 0
def style_changed (self): """ Read the log file if it exists and check if the style used is the one specified in the source. This supposes that the style is mentioned on a line with the form 'The style file: foo.bst'. """ if not exists(self.blgfile): return 0 log = open(self.blgfile) line = log.readline() while line != "": if line.startswith("The style file: "): if line.rstrip()[16:-4] != self.style: msg.log(_("the bibliography style was changed"), pkg="bibtex") log.close() return 1 line = log.readline() log.close() return 0
def style_changed(self): """ Read the log file if it exists and check if the style used is the one specified in the source. This supposes that the style is mentioned on a line with the form 'The style file: foo.bst'. """ if not exists(self.blgfile): return 0 log = open(self.blgfile) line = log.readline() while line != "": if line.startswith("The style file: "): if line.rstrip()[16:-4] != self.style: msg.log(_("the bibliography style was changed"), pkg="bibtex") log.close() return 1 line = log.readline() log.close() return 0
def register(self, name, dict={}): """ Attempt to register a package with the specified name. If a module is found, create an object from the module's class called `Module', passing it the environment and `dict' as arguments, and execute all delayed commands for this module. The dictionary describes the command that caused the registration. """ if self.has_key(name): msg.debug(_("module %s already registered") % name) return 2 # First look for a script moddir = "" mod = None for path in "", join(moddir, "modules"): file = join(path, name + ".rub") if exists(file): mod = ScriptModule(self.env, file) msg.log(_("script module %s registered") % name) break # Then look for a Python module if not mod: if Plugins.register(self, name) == 0: msg.debug(_("no support found for %s") % name) return 0 mod = self.modules[name].Module(self.env, dict) msg.log(_("built-in module %s registered") % name) # Run any delayed commands. if self.commands.has_key(name): for (cmd, args, vars) in self.commands[name]: msg.push_pos(vars) try: mod.command(cmd, args) except AttributeError: msg.warn(_("unknown directive '%s.%s'") % (name, cmd)) except TypeError: msg.warn(_("wrong syntax for '%s.%s'") % (name, cmd)) msg.pop_pos() del self.commands[name] self.objects[name] = mod return 1
def register (self, name, dict={}): """ Attempt to register a package with the specified name. If a module is found, create an object from the module's class called `Module', passing it the environment and `dict' as arguments, and execute all delayed commands for this module. The dictionary describes the command that caused the registration. """ if self.has_key(name): msg.debug(_("module %s already registered") % name) return 2 # First look for a script moddir = "" mod = None for path in "", join(moddir, "modules"): file = join(path, name + ".rub") if exists(file): mod = ScriptModule(self.env, file) msg.log(_("script module %s registered") % name) break # Then look for a Python module if not mod: if Plugins.register(self, name) == 0: msg.debug(_("no support found for %s") % name) return 0 mod = self.modules[name].Module(self.env, dict) msg.log(_("built-in module %s registered") % name) # Run any delayed commands. if self.commands.has_key(name): for (cmd, args, vars) in self.commands[name]: msg.push_pos(vars) try: mod.command(cmd, args) except AttributeError: msg.warn(_("unknown directive '%s.%s'") % (name, cmd)) except TypeError: msg.warn(_("wrong syntax for '%s.%s'") % (name, cmd)) msg.pop_pos() del self.commands[name] self.objects[name] = mod return 1
def do_tool (self, tool): if tool not in ("makeindex", "xindy"): msg.error(_("unknown indexing tool '%s'") % tool) self.tool = tool
def bibtex_needed (self): """ Return true if BibTeX must be run. """ if self.run_needed: return 1 msg.log(_("checking if BibTeX must be run..."), pkg="bibtex") newcites, dbs = self.parse_aux() # If there was a list of used citations, we check if it has # changed. If it has, we have to rerun. if self.prev_dbs is not None and self.prev_dbs != dbs: msg.log(_("the set of databases changed"), pkg="bibtex") self.prev_dbs = dbs self.used_cites = newcites self.undef_cites = self.list_undefs() return 1 self.prev_dbs = dbs # If there was a list of used citations, we check if it has # changed. If it has, we have to rerun. if self.used_cites and newcites != self.used_cites: msg.log(_("the list of citations changed"), pkg="bibtex") self.used_cites = newcites self.undef_cites = self.list_undefs() return 1 self.used_cites = newcites # If there was a list of undefined citations, we check if it has # changed. If it has and it is not empty, we have to rerun. if self.undef_cites: new = self.list_undefs() if new == []: msg.log(_("no more undefined citations"), pkg="bibtex") self.undef_cites = new else: for cite in new: if cite in self.undef_cites: continue msg.log(_("there are new undefined citations"), pkg="bibtex") self.undef_cites = new return 1 msg.log(_("there is no new undefined citation"), pkg="bibtex") self.undef_cites = new return 0 else: self.undef_cites = self.list_undefs() # At this point we don't know if undefined citations changed. If # BibTeX has not been run before (i.e. there is no log file) we know # that it has to be run now. if not exists(self.blgfile): msg.log(_("no BibTeX log file"), pkg="bibtex") return 1 # Here, BibTeX has been run before but we don't know if undefined # citations changed. if self.undef_cites == []: msg.log(_("no undefined citations"), pkg="bibtex") return 0 if getmtime(self.blgfile) < getmtime(self.doc.logfile): msg.log(_("BibTeX's log is older than the main log"), pkg="bibtex") return 1 return 0
def parse (self, errors=0, boxes=0, refs=0, warnings=0): """ Parse the log file for relevant information. The named arguments are booleans that indicate which information should be extracted: - errors: all errors - boxes: bad boxes - refs: warnings about references - warnings: all other warnings The function returns a generator. Each generated item is a dictionary that contains (some of) the following entries: - kind: the kind of information ("error", "box", "ref", "warning") - text: the text of the error or warning - code: the piece of code that caused an error - file, line, last, pkg: as used by Message.format_pos. """ if not self.lines: return last_file = None pos = [last_file] page = 1 parsing = 0 # 1 if we are parsing an error's text skipping = 0 # 1 if we are skipping text until an empty line something = 0 # 1 if some error was found prefix = None # the prefix for warning messages from packages accu = "" # accumulated text from the previous line for line in self.lines: line = line[:-1] # remove the line feed # TeX breaks messages at 79 characters, just to make parsing # trickier... if self.continued(line): accu += line continue line = accu + line accu = "" # Text that should be skipped (from bad box messages) if prefix is None and line == "": skipping = 0 continue if skipping: continue # Errors (including aborted compilation) if parsing: if error == "Undefined control sequence.": # This is a special case in order to report which control # sequence is undefined. m = self.re_cseq.match(line) if m: error = "Undefined control sequence %s." % m.group("seq") m = self.re_line.match(line) if m: parsing = 0 skipping = 1 pdfTeX = error.find("pdfTeX warning") != -1 if (pdfTeX and warnings) or (errors and not pdfTeX): if pdfTeX: d = { "kind": "warning", "pkg": "pdfTeX", "text": error[error.find(":")+2:] } else: d = { "kind": "error", "text": error } d.update( m.groupdict() ) m = self.re_ignored.search(error) if m: d["file"] = last_file if d.has_key("code"): del d["code"] d.update( m.groupdict() ) elif pos[-1] is None: d["file"] = last_file else: d["file"] = pos[-1] yield d elif line[0] == "!": error = line[2:] elif line[0:3] == "***": parsing = 0 skipping = 1 if errors: yield { "kind": "abort", "text": error, "why" : line[4:], "file": last_file } elif line[0:15] == "Type X to quit ": parsing = 0 skipping = 0 if errors: yield { "kind": "error", "text": error, "file": pos[-1] } continue if len(line) > 0 and line[0] == "!": error = line[2:] parsing = 1 continue if line == "Runaway argument?": error = line parsing = 1 continue # Long warnings if prefix is not None: if line[:len(prefix)] == prefix: text.append(line[len(prefix):].strip()) else: text = " ".join(text) m = self.re_online.search(text) if m: info["line"] = m.group("line") text = text[:m.start()] + text[m.end():] if warnings: info["text"] = text d = { "kind": "warning" } d.update( info ) yield d prefix = None continue # Undefined references m = self.re_reference.match(line) if m: if refs: d = { "kind": "warning", "text": _("Reference `%s' undefined.") % m.group("ref"), "file": pos[-1] } d.update( m.groupdict() ) yield d continue m = self.re_label.match(line) if m: if refs: d = { "kind": "warning", "file": pos[-1] } d.update( m.groupdict() ) yield d continue # Other warnings if line.find("Warning") != -1: m = self.re_warning.match(line) if m: info = m.groupdict() info["file"] = pos[-1] info["page"] = page if info["pkg"] is None: del info["pkg"] prefix = "" else: prefix = ("(%s)" % info["pkg"]) prefix = prefix.ljust(m.start("text")) text = [info["text"]] continue # Bad box messages m = self.re_badbox.match(line) if m: if boxes: mpos = { "file": pos[-1], "page": page } m = self.re_atline.search(line) if m: md = m.groupdict() for key in "line", "last": if md[key]: mpos[key] = md[key] line = line[:m.start()] d = { "kind": "warning", "text": line } d.update( mpos ) yield d skipping = 1 continue # If there is no message, track source names and page numbers. last_file = self.update_file(line, pos, last_file) page = self.update_page(line, page)
def parse(self, errors=0, boxes=0, refs=0, warnings=0, misschars=0): """ Parse the log file for relevant information. The named arguments are booleans that indicate which information should be extracted: - errors: all errors - boxes: bad boxes - refs: warnings about references - warnings: all other warnings The function returns a generator. Each generated item is a dictionary that contains (some of) the following entries: - kind: the kind of information ("error", "box", "ref", "warning") - text: the text of the error or warning - code: the piece of code that caused an error - file, line, last, pkg: as used by Message.format_pos. """ if not self.lines: return last_file = None pos = [last_file] page = 1 parsing = 0 # 1 if we are parsing an error's text skipping = 0 # 1 if we are skipping text until an empty line something = 0 # 1 if some error was found prefix = None # the prefix for warning messages from packages accu = "" # accumulated text from the previous line for line in self.lines: line = line[:-1] # remove the line feed # TeX breaks messages at 79 characters, just to make parsing # trickier... if self.continued(line): accu += line continue line = accu + line accu = "" # Text that should be skipped (from bad box messages) if prefix is None and line == "": skipping = 0 continue if skipping: continue # Errors (including aborted compilation) if parsing: if error == "Undefined control sequence.": # This is a special case in order to report which control # sequence is undefined. m = self.re_cseq.match(line) if m: error = "Undefined control sequence %s." % m.group( "seq") m = self.re_line.match(line) if m: parsing = 0 skipping = 1 pdfTeX = error.find("pdfTeX warning") != -1 if (pdfTeX and warnings) or (errors and not pdfTeX): if pdfTeX: d = { "kind": "warning", "pkg": "pdfTeX", "text": error[error.find(":") + 2:] } else: d = {"kind": "error", "text": error} d.update(m.groupdict()) m = self.re_ignored.search(error) if m: d["file"] = last_file if d.has_key("code"): del d["code"] d.update(m.groupdict()) elif pos[-1] is None: d["file"] = last_file else: d["file"] = pos[-1] yield d elif line[0] == "!": error = line[2:] elif line[0:3] == "***": parsing = 0 skipping = 1 if errors: yield { "kind": "abort", "text": error, "why": line[4:], "file": last_file } elif line[0:15] == "Type X to quit ": parsing = 0 skipping = 0 if errors: yield {"kind": "error", "text": error, "file": pos[-1]} continue if len(line) > 0 and line[0] == "!": error = line[2:] parsing = 1 continue if line == "Runaway argument?": error = line parsing = 1 continue # Long warnings if prefix is not None: if line[:len(prefix)] == prefix: text.append(line[len(prefix):].strip()) else: text = " ".join(text) m = self.re_online.search(text) if m: info["line"] = m.group("line") text = text[:m.start()] + text[m.end():] if warnings: info["text"] = text d = {"kind": "warning"} d.update(info) yield d prefix = None continue # Undefined references m = self.re_reference.match(line) if m: if refs: d = { "kind": "warning", "text": _("Reference `%s' undefined.") % m.group("ref"), "file": pos[-1] } d.update(m.groupdict()) yield d continue m = self.re_label.match(line) if m: if refs: d = {"kind": "warning", "file": pos[-1]} d.update(m.groupdict()) yield d continue # Other warnings if line.find("Warning") != -1: m = self.re_warning.match(line) if m: info = m.groupdict() info["file"] = pos[-1] info["page"] = page if info["pkg"] is None: del info["pkg"] prefix = "" else: prefix = ("(%s)" % info["pkg"]) prefix = prefix.ljust(m.start("text")) text = [info["text"]] continue # Bad box messages m = self.re_badbox.match(line) if m: if boxes: mpos = {"file": pos[-1], "page": page} m = self.re_atline.search(line) if m: md = m.groupdict() for key in "line", "last": if md[key]: mpos[key] = md[key] line = line[:m.start()] d = {"kind": "warning", "text": line} d.update(mpos) yield d skipping = 1 continue # Missing characters in a font if misschars: m = self.re_misschar.match(line) if m: d = { "kind": "warning", "uchar": m.group("uchar"), "font": m.group("font"), } yield d continue # If there is no message, track source names and page numbers. last_file = self.update_file(line, pos, last_file) page = self.update_page(line, page)
def post_compile (self): """ Run makeindex if needed, with appropriate options and environment. """ if not os.path.exists(self.source): msg.log(_("strange, there is no %s") % self.source, pkg="index") return 0 if not self.run_needed(): return 0 msg.progress(_("processing index %s") % self.source) if self.tool == "makeindex": cmd = ["makeindex", "-o", self.target] + self.opts cmd.extend(["-t", self.transcript]) if self.style: cmd.extend(["-s", self.style]) cmd.append(self.source) path_var = "INDEXSTYLE" elif self.tool == "xindy": cmd = ["texindy", "--quiet"] for opt in self.opts: if opt == "-g": if self.lang != "": msg.warn(_("'language' overrides 'order german'"), pkg="index") else: self.lang = "german-din" elif opt == "-l": self.modules.append("letter-ordering") msg.warn(_("use 'module letter-ordering' instead of 'order letter'"), pkg="index") else: msg.error("unknown option to xindy: %s" % opt, pkg="index") for mod in self.modules: cmd.extend(["--module", mod]) if self.lang: cmd.extend(["--language", self.lang]) cmd.append(self.source) path_var = "XINDY_SEARCHPATH" if self.path != []: env = { path_var: string.join(self.path + [os.getenv(path_var, "")], ":") } else: env = {} msg.debug(" ".join(cmd)) # Makeindex outputs everything to stderr, even progress messages rc = subprocess.call(cmd, stderr=msg.stdout) if (rc != 0): msg.error(_("could not make index %s") % self.target) return 1 # Beware with UTF-8 encoding, makeindex with headings can be messy if self.doc.encoding == "utf8" and self.style: f = file(self.target, "r") error = 0 for line in f: try: line.decode("utf8") except: error = 1 break f.close() if error: print "here" # Retry without style msg.log(_("%s on UTF8 failed. Retry...") % self.tool) self.style = "" self.md5 = None return self.post_compile() self.doc.must_compile = 1 return 0
def bibtex_needed(self): """ Return true if BibTeX must be run. """ if self.run_needed: return 1 msg.log(_("checking if BibTeX must be run..."), pkg="bibtex") newcites, dbs = self.parse_aux() # If there was a list of used citations, we check if it has # changed. If it has, we have to rerun. if self.prev_dbs is not None and self.prev_dbs != dbs: msg.log(_("the set of databases changed"), pkg="bibtex") self.prev_dbs = dbs self.used_cites = newcites self.undef_cites = self.list_undefs() return 1 self.prev_dbs = dbs # If there was a list of used citations, we check if it has # changed. If it has, we have to rerun. if self.used_cites and newcites != self.used_cites: msg.log(_("the list of citations changed"), pkg="bibtex") self.used_cites = newcites self.undef_cites = self.list_undefs() return 1 self.used_cites = newcites # If there was a list of undefined citations, we check if it has # changed. If it has and it is not empty, we have to rerun. if self.undef_cites: new = self.list_undefs() if new == []: msg.log(_("no more undefined citations"), pkg="bibtex") self.undef_cites = new else: for cite in new: if cite in self.undef_cites: continue msg.log(_("there are new undefined citations"), pkg="bibtex") self.undef_cites = new return 1 msg.log(_("there is no new undefined citation"), pkg="bibtex") self.undef_cites = new return 0 else: self.undef_cites = self.list_undefs() # At this point we don't know if undefined citations changed. If # BibTeX has not been run before (i.e. there is no log file) we know # that it has to be run now. if not exists(self.blgfile): msg.log(_("no BibTeX log file"), pkg="bibtex") return 1 # Here, BibTeX has been run before but we don't know if undefined # citations changed. if self.undef_cites == []: msg.log(_("no undefined citations"), pkg="bibtex") return 0 if getmtime(self.blgfile) < getmtime(self.doc.logfile): msg.log(_("BibTeX's log is older than the main log"), pkg="bibtex") return 1 return 0