/desktop/core/ext-py/lxml/doc/mklatex.py
Python | 318 lines | 301 code | 10 blank | 7 comment | 2 complexity | 302f9b0af3b74cd755071097d714fcca MD5 | raw file
- # The script builds the LaTeX documentation.
- # Testing:
- # python mklatex.py latex .. 1.0
- from docstructure import SITE_STRUCTURE, BASENAME_MAP
- import os, shutil, re, sys, datetime
- try:
- set
- except NameError:
- # Python 2.3
- from sets import Set as set
- TARGET_FILE = "lxmldoc.tex"
- RST2LATEX_OPTIONS = " ".join([
- # "--no-toc-backlinks",
- "--strip-comments",
- "--language en",
- # "--date",
- "--use-latex-footnotes",
- "--use-latex-citations",
- "--use-latex-toc",
- "--font-encoding=T1",
- "--output-encoding=utf-8",
- "--input-encoding=utf-8",
- "--graphicx-option=pdftex",
- ])
- htmlnsmap = {"h" : "http://www.w3.org/1999/xhtml"}
- replace_invalid = re.compile(r'[-_/.\s\\]').sub
- replace_content = re.compile("\{[^\}]*\}").sub
- replace_epydoc_macros = re.compile(r'(,\s*amssymb|dvips\s*,\s*)').sub
- replace_rst_macros = re.compile(r'(\\usepackage\{color}|\\usepackage\[[^]]*]\{hyperref})').sub
- BASENAME_MAP = BASENAME_MAP.copy()
- BASENAME_MAP.update({'api' : 'lxmlapi'})
- # LaTeX snippets
- DOCUMENT_CLASS = r"""
- \documentclass[10pt,english]{report}
- \usepackage[a4paper]{geometry}
- \parindent0pt
- \parskip1ex
- """
- PYGMENTS_IMPORT = r"""
- \usepackage{fancyvrb}
- \input{_part_pygments.tex}
- """
- EPYDOC_IMPORT = r"""
- \input{_part_epydoc.tex}
- """
- def write_chapter(master, title, filename):
- filename = os.path.join(os.path.dirname(filename),
- "_part_%s" % os.path.basename(filename))
- master.write(r"""
- \chapter{%s}
- \label{%s}
- \input{%s}
- """ % (title, filename, filename))
- # the program ----
- def rest2latex(script, source_path, dest_path):
- command = ('%s %s %s %s > %s' %
- (sys.executable, script, RST2LATEX_OPTIONS,
- source_path, dest_path))
- os.system(command)
- def build_pygments_macros(filename):
- from pygments.formatters import LatexFormatter
- text = LatexFormatter().get_style_defs()
- f = file(filename, "w")
- f.write(text)
- f.write('\n')
- f.close()
- def copy_epydoc_macros(src, dest, existing_header_lines):
- doc = file(src, 'r')
- out = file(dest, "w")
- for line in doc:
- if line.startswith('%% generator') or line.startswith('% generated by '):
- break
- if line.startswith('%') or \
- r'\documentclass' in line or \
- r'\makeindex' in line or \
- r'{inputenc}' in line:
- continue
- if line.startswith(r'\usepackage'):
- if line in existing_header_lines:
- continue
- if '{hyperref}' in line:
- line = line.replace('black', 'blue')
- out.write( replace_epydoc_macros('', line) )
- out.close()
- doc.close()
- def noop(input):
- return input
- counter_no = 0
- def tex_postprocess(src, dest, want_header = False, process_line=noop):
- """
- Postprocessing of the LaTeX file generated from ReST.
- Reads file src and saves to dest only the true content
- (without the document header and final) - so it is suitable
- to be used as part of the longer document.
- Returns the title of document
- If want_header is set, returns also the document header (as
- the list of lines).
- """
- title = ''
- header = []
- add_header_line = header.append
- global counter_no
- counter_no = counter_no + 1
- counter_text = "listcnt%d" % counter_no
- search_title = re.compile(r'\\title{([^}]*)}').search
- skipping = re.compile(r'(\\end{document}|\\tableofcontents)').search
- src = file(src)
- dest = file(dest, "w")
- iter_lines = iter(src.readlines())
- for l in iter_lines:
- l = process_line(l)
- if not l:
- continue
- if want_header:
- add_header_line(replace_rst_macros('', l))
- m = search_title(l)
- if m:
- title = m.group(0)
- if l.startswith("\\maketitle"):
- break
- for l in iter_lines:
- l = process_line(l)
- if skipping(l):
- # To-Do minitoc instead of tableofcontents
- continue
- elif "\hypertarget{old-versions}" in l:
- break
- elif "listcnt0" in l:
- l = l.replace("listcnt0", counter_text)
- dest.write(l)
- if not title:
- raise Exception("Bueee, no title")
- return title, header
- def publish(dirname, lxml_path, release):
- if not os.path.exists(dirname):
- os.mkdir(dirname)
- book_title = "lxml %s" % release
- doc_dir = os.path.join(lxml_path, 'doc')
- script = os.path.join(doc_dir, 'rest2latex.py')
- pubkey = os.path.join(doc_dir, 'pubkey.asc')
- shutil.copy(pubkey, dirname)
- # build pygments macros
- build_pygments_macros(os.path.join(dirname, '_part_pygments.tex'))
- # Used in postprocessing of generated LaTeX files
- header = []
- titles = {}
- replace_interdoc_hyperrefs = re.compile(
- r'\\href\{([^/}]+)[.]([^./}]+)\}').sub
- replace_docinternal_hyperrefs = re.compile(
- r'\\href\{\\#([^}]+)\}').sub
- replace_image_paths = re.compile(
- r'^(\\includegraphics{)').sub
- def build_hyperref(match):
- basename, extension = match.groups()
- outname = BASENAME_MAP.get(basename, basename)
- if '#' in extension:
- anchor = extension.split('#')[-1]
- return r"\hyperref[%s]" % anchor
- elif extension != 'html':
- return r'\href{http://codespeak.net/lxml/%s.%s}' % (
- outname, extension)
- else:
- return r"\hyperref[_part_%s.tex]" % outname
- def fix_relative_hyperrefs(line):
- line = replace_image_paths(r'\1../html/', line)
- if r'\href' not in line:
- return line
- line = replace_interdoc_hyperrefs(build_hyperref, line)
- return replace_docinternal_hyperrefs(r'\hyperref[\1]', line)
- # Building pages
- have_epydoc_macros = False
- for section, text_files in SITE_STRUCTURE:
- for filename in text_files:
- if filename.startswith('@'):
- continue
- #page_title = filename[1:]
- #url = href_map[page_title]
- #build_menu_entry(page_title, url, section_head)
- basename = os.path.splitext(os.path.basename(filename))[0]
- basename = BASENAME_MAP.get(basename, basename)
- outname = basename + '.tex'
- outpath = os.path.join(dirname, outname)
- path = os.path.join(doc_dir, filename)
- print "Creating %s" % outname
- rest2latex(script, path, outpath)
- final_name = os.path.join(dirname, os.path.dirname(outname),
- "_part_%s" % os.path.basename(outname))
- title, hd = tex_postprocess(outpath, final_name,
- want_header = not header,
- process_line=fix_relative_hyperrefs)
- if not header:
- header = hd
- titles[outname] = title
- # integrate generated API docs
- print "Integrating API docs"
- apidocsname = 'api.tex'
- apipath = os.path.join(dirname, apidocsname)
- tex_postprocess(apipath, os.path.join(dirname, "_part_%s" % apidocsname),
- process_line=fix_relative_hyperrefs)
- copy_epydoc_macros(apipath, os.path.join(dirname, '_part_epydoc.tex'),
- set(header))
- # convert CHANGES.txt
- print "Integrating ChangeLog"
- find_version_title = re.compile(
- r'(.*\\section\{)([0-9][^\} ]*)\s+\(([^)]+)\)(\}.*)').search
- def fix_changelog(line):
- m = find_version_title(line)
- if m:
- line = "%sChanges in version %s, released %s%s" % m.groups()
- else:
- line = line.replace(r'\subsection{', r'\subsection*{')
- return line
- chgname = 'changes-%s.tex' % release
- chgpath = os.path.join(dirname, chgname)
- rest2latex(script,
- os.path.join(lxml_path, 'CHANGES.txt'),
- chgpath)
- tex_postprocess(chgpath, os.path.join(dirname, "_part_%s" % chgname),
- process_line=fix_changelog)
- # Writing a master file
- print "Building %s\n" % TARGET_FILE
- master = file( os.path.join(dirname, TARGET_FILE), "w")
- for hln in header:
- if hln.startswith(r"\documentclass"):
- #hln = hln.replace('article', 'book')
- hln = DOCUMENT_CLASS
- elif hln.startswith("%% generator ") or hln.startswith("% generated "):
- master.write(EPYDOC_IMPORT)
- elif hln.startswith(r"\begin{document}"):
- # pygments and epydoc support
- master.write(PYGMENTS_IMPORT)
- elif hln.startswith(r"\title{"):
- hln = replace_content(
- r'{%s\\\\\\vspace{1cm}\\includegraphics[width=2.5cm]{../html/tagpython-big.png}}' % book_title, hln)
- elif hln.startswith(r"\date{"):
- hln = replace_content(
- r'{%s}' % datetime.date.today().isoformat(), hln)
- elif hln.startswith("pdftitle"):
- hln = replace_content(
- r'{%s}' % book_title, hln)
- master.write(hln)
- master.write("\\setcounter{page}{2}\n")
- master.write("\\tableofcontents\n")
- for section, text_files in SITE_STRUCTURE:
- master.write("\n\n\\part{%s}\n" % section)
- for filename in text_files:
- if filename.startswith('@'):
- continue
- #print "Not yet implemented: %s" % filename[1:]
- #page_title = filename[1:]
- #url = href_map[page_title]
- #build_menu_entry(page_title, url, section_head)
- else:
- basename = os.path.splitext(os.path.basename(filename))[0]
- basename = BASENAME_MAP.get(basename, basename)
- outname = basename + '.tex'
- write_chapter(master, titles[outname], outname)
- master.write("\\appendix\n")
- master.write("\\begin{appendix}\n")
- write_chapter(master, "Changes", chgname)
- write_chapter(master, "Generated API documentation", apidocsname)
- master.write("\\end{appendix}\n")
- master.write("\\end{document}\n")
-
- if __name__ == '__main__':
- publish(sys.argv[1], sys.argv[2], sys.argv[3])