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 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 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 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 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 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 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 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(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 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 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 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 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 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 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 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
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