diff options
Diffstat (limited to 'source-builder/sb/asciidoc/a2x.py')
-rwxr-xr-x | source-builder/sb/asciidoc/a2x.py | 960 |
1 files changed, 0 insertions, 960 deletions
diff --git a/source-builder/sb/asciidoc/a2x.py b/source-builder/sb/asciidoc/a2x.py deleted file mode 100755 index 1b192a2..0000000 --- a/source-builder/sb/asciidoc/a2x.py +++ /dev/null @@ -1,960 +0,0 @@ -#!/usr/bin/env python -''' -a2x - A toolchain manager for AsciiDoc (converts Asciidoc text files to other - file formats) - -Copyright: Stuart Rackham (c) 2009 -License: MIT -Email: srackham@gmail.com - -''' - -import os -import fnmatch -import HTMLParser -import re -import shutil -import subprocess -import sys -import traceback -import urlparse -import zipfile -import xml.dom.minidom -import mimetypes - -PROG = os.path.basename(os.path.splitext(__file__)[0]) -VERSION = '8.6.8' - -# AsciiDoc global configuration file directory. -# NOTE: CONF_DIR is "fixed up" by Makefile -- don't rename or change syntax. -CONF_DIR = '/etc/asciidoc' - - -###################################################################### -# Default configuration file parameters. -###################################################################### - -# Optional environment variable dictionary passed to -# executing programs. If set to None the existing -# environment is used. -ENV = None - -# External executables. -ASCIIDOC = 'asciidoc' -XSLTPROC = 'xsltproc' -DBLATEX = 'dblatex' # pdf generation. -FOP = 'fop' # pdf generation (--fop option). -W3M = 'w3m' # text generation. -LYNX = 'lynx' # text generation (if no w3m). -XMLLINT = 'xmllint' # Set to '' to disable. -EPUBCHECK = 'epubcheck' # Set to '' to disable. -# External executable default options. -ASCIIDOC_OPTS = '' -DBLATEX_OPTS = '' -FOP_OPTS = '' -XSLTPROC_OPTS = '' -BACKEND_OPTS = '' - -###################################################################### -# End of configuration file parameters. -###################################################################### - - -##################################################################### -# Utility functions -##################################################################### - -OPTIONS = None # These functions read verbose and dry_run command options. - -def errmsg(msg): - sys.stderr.write('%s: %s\n' % (PROG,msg)) - -def warning(msg): - errmsg('WARNING: %s' % msg) - -def infomsg(msg): - print '%s: %s' % (PROG,msg) - -def die(msg, exit_code=1): - errmsg('ERROR: %s' % msg) - sys.exit(exit_code) - -def trace(): - """Print traceback to stderr.""" - errmsg('-'*60) - traceback.print_exc(file=sys.stderr) - errmsg('-'*60) - -def verbose(msg): - if OPTIONS.verbose or OPTIONS.dry_run: - infomsg(msg) - -class AttrDict(dict): - """ - Like a dictionary except values can be accessed as attributes i.e. obj.foo - can be used in addition to obj['foo']. - If self._default has been set then it will be returned if a non-existant - attribute is accessed (instead of raising an AttributeError). - """ - def __getattr__(self, key): - try: - return self[key] - except KeyError, k: - if self.has_key('_default'): - return self['_default'] - else: - raise AttributeError, k - def __setattr__(self, key, value): - self[key] = value - def __delattr__(self, key): - try: del self[key] - except KeyError, k: raise AttributeError, k - def __repr__(self): - return '<AttrDict ' + dict.__repr__(self) + '>' - def __getstate__(self): - return dict(self) - def __setstate__(self,value): - for k,v in value.items(): self[k]=v - -def isexecutable(file_name): - return os.path.isfile(file_name) and os.access(file_name, os.X_OK) - -def find_executable(file_name): - ''' - Search for executable file_name in the system PATH. - Return full path name or None if not found. - ''' - def _find_executable(file_name): - if os.path.split(file_name)[0] != '': - # file_name includes directory so don't search path. - if not isexecutable(file_name): - return None - else: - return file_name - for p in os.environ.get('PATH', os.defpath).split(os.pathsep): - f = os.path.join(p, file_name) - if isexecutable(f): - return os.path.realpath(f) - return None - if os.name == 'nt' and os.path.splitext(file_name)[1] == '': - for ext in ('.cmd','.bat','.exe'): - result = _find_executable(file_name + ext) - if result: break - else: - result = _find_executable(file_name) - return result - -def write_file(filename, data, mode='w'): - f = open(filename, mode) - try: - f.write(data) - finally: - f.close() - -def read_file(filename, mode='r'): - f = open(filename, mode) - try: - return f.read() - finally: - f.close() - -def shell_cd(path): - verbose('chdir %s' % path) - if not OPTIONS.dry_run: - os.chdir(path) - -def shell_makedirs(path): - if os.path.isdir(path): - return - verbose('creating %s' % path) - if not OPTIONS.dry_run: - os.makedirs(path) - -def shell_copy(src, dst): - verbose('copying "%s" to "%s"' % (src,dst)) - if not OPTIONS.dry_run: - shutil.copy(src, dst) - -def shell_rm(path): - if not os.path.exists(path): - return - verbose('deleting %s' % path) - if not OPTIONS.dry_run: - os.unlink(path) - -def shell_rmtree(path): - if not os.path.isdir(path): - return - verbose('deleting %s' % path) - if not OPTIONS.dry_run: - shutil.rmtree(path) - -def shell(cmd, raise_error=True): - ''' - Execute command cmd in shell and return tuple - (stdoutdata, stderrdata, returncode). - If raise_error is True then a non-zero return terminates the application. - ''' - if os.name == 'nt': - # TODO: this is probably unnecessary, see: - # http://groups.google.com/group/asciidoc/browse_frm/thread/9442ee0c419f1242 - # Windows doesn't like running scripts directly so explicitly - # specify python interpreter. - # Extract first (quoted or unquoted) argument. - mo = re.match(r'^\s*"\s*(?P<arg0>[^"]+)\s*"', cmd) - if not mo: - mo = re.match(r'^\s*(?P<arg0>[^ ]+)', cmd) - if mo.group('arg0').endswith('.py'): - cmd = 'python ' + cmd - # Remove redundant quoting -- this is not just cosmetic, - # quoting seems to dramatically decrease the allowed command - # length in Windows XP. - cmd = re.sub(r'"([^ ]+?)"', r'\1', cmd) - verbose('executing: %s' % cmd) - if OPTIONS.dry_run: - return - stdout = stderr = subprocess.PIPE - try: - popen = subprocess.Popen(cmd, stdout=stdout, stderr=stderr, - shell=True, env=ENV) - except OSError, e: - die('failed: %s: %s' % (cmd, e)) - stdoutdata, stderrdata = popen.communicate() - if OPTIONS.verbose: - print stdoutdata - print stderrdata - if popen.returncode != 0 and raise_error: - die('%s returned non-zero exit status %d' % (cmd, popen.returncode)) - return (stdoutdata, stderrdata, popen.returncode) - -def find_resources(files, tagname, attrname, filter=None): - ''' - Search all files and return a list of local URIs from attrname attribute - values in tagname tags. - Handles HTML open and XHTML closed tags. - Non-local URIs are skipped. - files can be a file name or a list of file names. - The filter function takes a dictionary of tag attributes and returns True if - the URI is to be included. - ''' - class FindResources(HTMLParser.HTMLParser): - # Nested parser class shares locals with enclosing function. - def handle_startendtag(self, tag, attrs): - self.handle_starttag(tag, attrs) - def handle_starttag(self, tag, attrs): - attrs = dict(attrs) - if tag == tagname and (filter is None or filter(attrs)): - # Accept only local URIs. - uri = urlparse.urlparse(attrs[attrname]) - if uri[0] in ('','file') and not uri[1] and uri[2]: - result.append(uri[2]) - if isinstance(files, str): - files = [files] - result = [] - for filename in files: - verbose('finding resources in: %s' % filename) - if OPTIONS.dry_run: - continue - parser = FindResources() - # HTMLParser has problems with non-ASCII strings. - # See http://bugs.python.org/issue3932 - contents = read_file(filename) - mo = re.search(r'\A<\?xml.* encoding="(.*?)"', contents) - if mo: - encoding = mo.group(1) - parser.feed(contents.decode(encoding)) - else: - parser.feed(contents) - parser.close() - result = list(set(result)) # Drop duplicate values. - result.sort() - return result - -# NOT USED. -def copy_files(files, src_dir, dst_dir): - ''' - Copy list of relative file names from src_dir to dst_dir. - ''' - for filename in files: - filename = os.path.normpath(filename) - if os.path.isabs(filename): - continue - src = os.path.join(src_dir, filename) - dst = os.path.join(dst_dir, filename) - if not os.path.exists(dst): - if not os.path.isfile(src): - warning('missing file: %s' % src) - continue - dstdir = os.path.dirname(dst) - shell_makedirs(dstdir) - shell_copy(src, dst) - -def find_files(path, pattern): - ''' - Return list of file names matching pattern in directory path. - ''' - result = [] - for (p,dirs,files) in os.walk(path): - for f in files: - if fnmatch.fnmatch(f, pattern): - result.append(os.path.normpath(os.path.join(p,f))) - return result - -def exec_xsltproc(xsl_file, xml_file, dst_dir, opts = ''): - cwd = os.getcwd() - shell_cd(dst_dir) - try: - shell('"%s" %s "%s" "%s"' % (XSLTPROC, opts, xsl_file, xml_file)) - finally: - shell_cd(cwd) - -def get_source_options(asciidoc_file): - ''' - Look for a2x command options in AsciiDoc source file. - Limitation: options cannot contain double-quote characters. - ''' - def parse_options(): - # Parse options to result sequence. - inquotes = False - opt = '' - for c in options: - if c == '"': - if inquotes: - result.append(opt) - opt = '' - inquotes = False - else: - inquotes = True - elif c == ' ': - if inquotes: - opt += c - elif opt: - result.append(opt) - opt = '' - else: - opt += c - if opt: - result.append(opt) - - result = [] - if os.path.isfile(asciidoc_file): - options = '' - f = open(asciidoc_file) - try: - for line in f: - mo = re.search(r'^//\s*a2x:', line) - if mo: - options += ' ' + line[mo.end():].strip() - finally: - f.close() - parse_options() - return result - - -##################################################################### -# Application class -##################################################################### - -class A2X(AttrDict): - ''' - a2x options and conversion functions. - ''' - - def execute(self): - ''' - Process a2x command. - ''' - self.process_options() - # Append configuration file options. - self.asciidoc_opts += ' ' + ASCIIDOC_OPTS - self.dblatex_opts += ' ' + DBLATEX_OPTS - self.fop_opts += ' ' + FOP_OPTS - self.xsltproc_opts += ' ' + XSLTPROC_OPTS - self.backend_opts += ' ' + BACKEND_OPTS - # Execute to_* functions. - if self.backend: - self.to_backend() - else: - self.__getattribute__('to_'+self.format)() - if not (self.keep_artifacts or self.format == 'docbook' or self.skip_asciidoc): - shell_rm(self.dst_path('.xml')) - - def load_conf(self): - ''' - Load a2x configuration file from default locations and --conf-file - option. - ''' - global ASCIIDOC - CONF_FILE = 'a2x.conf' - a2xdir = os.path.dirname(os.path.realpath(__file__)) - conf_files = [] - # From a2x.py directory. - conf_files.append(os.path.join(a2xdir, CONF_FILE)) - # If the asciidoc executable and conf files are in the a2x directory - # then use the local copy of asciidoc and skip the global a2x conf. - asciidoc = os.path.join(a2xdir, 'asciidoc.py') - asciidoc_conf = os.path.join(a2xdir, 'asciidoc.conf') - if os.path.isfile(asciidoc) and os.path.isfile(asciidoc_conf): - self.asciidoc = asciidoc - else: - self.asciidoc = None - # From global conf directory. - conf_files.append(os.path.join(CONF_DIR, CONF_FILE)) - # From $HOME directory. - home_dir = os.environ.get('HOME') - if home_dir is not None: - conf_files.append(os.path.join(home_dir, '.asciidoc', CONF_FILE)) - # If asciidoc is not local to a2x then search the PATH. - if not self.asciidoc: - self.asciidoc = find_executable(ASCIIDOC) - if not self.asciidoc: - die('unable to find asciidoc: %s' % ASCIIDOC) - # From backend plugin directory. - if self.backend is not None: - stdout = shell(self.asciidoc + ' --backend list')[0] - backends = [(i, os.path.split(i)[1]) for i in stdout.splitlines()] - backend_dir = [i[0] for i in backends if i[1] == self.backend] - if len(backend_dir) == 0: - die('missing %s backend' % self.backend) - if len(backend_dir) > 1: - die('more than one %s backend' % self.backend) - verbose('found %s backend directory: %s' % - (self.backend, backend_dir[0])) - conf_files.append(os.path.join(backend_dir[0], 'a2x-backend.py')) - # From --conf-file option. - if self.conf_file is not None: - if not os.path.isfile(self.conf_file): - die('missing configuration file: %s' % self.conf_file) - conf_files.append(self.conf_file) - # From --xsl-file option. - if self.xsl_file is not None: - if not os.path.isfile(self.xsl_file): - die('missing XSL file: %s' % self.xsl_file) - self.xsl_file = os.path.abspath(self.xsl_file) - # Load ordered files. - for f in conf_files: - if os.path.isfile(f): - verbose('loading configuration file: %s' % f) - execfile(f, globals()) - - def process_options(self): - ''' - Validate and command options and set defaults. - ''' - if not os.path.isfile(self.asciidoc_file): - die('missing SOURCE_FILE: %s' % self.asciidoc_file) - self.asciidoc_file = os.path.abspath(self.asciidoc_file) - if not self.destination_dir: - self.destination_dir = os.path.dirname(self.asciidoc_file) - else: - if not os.path.isdir(self.destination_dir): - die('missing --destination-dir: %s' % self.destination_dir) - self.destination_dir = os.path.abspath(self.destination_dir) - self.resource_dirs = [] - self.resource_files = [] - if self.resource_manifest: - if not os.path.isfile(self.resource_manifest): - die('missing --resource-manifest: %s' % self.resource_manifest) - f = open(self.resource_manifest) - try: - for r in f: - self.resources.append(r.strip()) - finally: - f.close() - for r in self.resources: - r = os.path.expanduser(r) - r = os.path.expandvars(r) - if r.endswith('/') or r.endswith('\\'): - if os.path.isdir(r): - self.resource_dirs.append(r) - else: - die('missing resource directory: %s' % r) - elif os.path.isdir(r): - self.resource_dirs.append(r) - elif r.startswith('.') and '=' in r: - ext, mimetype = r.split('=') - mimetypes.add_type(mimetype, ext) - else: - self.resource_files.append(r) - for p in (os.path.dirname(self.asciidoc), CONF_DIR): - for d in ('images','stylesheets'): - d = os.path.join(p,d) - if os.path.isdir(d): - self.resource_dirs.append(d) - verbose('resource files: %s' % self.resource_files) - verbose('resource directories: %s' % self.resource_dirs) - if not self.doctype and self.format == 'manpage': - self.doctype = 'manpage' - if self.doctype: - self.asciidoc_opts += ' --doctype %s' % self.doctype - for attr in self.attributes: - self.asciidoc_opts += ' --attribute "%s"' % attr -# self.xsltproc_opts += ' --nonet' - if self.verbose: - self.asciidoc_opts += ' --verbose' - self.dblatex_opts += ' -V' - if self.icons or self.icons_dir: - params = [ - 'callout.graphics 1', - 'navig.graphics 1', - 'admon.textlabel 0', - 'admon.graphics 1', - ] - if self.icons_dir: - params += [ - 'admon.graphics.path "%s/"' % self.icons_dir, - 'callout.graphics.path "%s/callouts/"' % self.icons_dir, - 'navig.graphics.path "%s/"' % self.icons_dir, - ] - else: - params = [ - 'callout.graphics 0', - 'navig.graphics 0', - 'admon.textlabel 1', - 'admon.graphics 0', - ] - if self.stylesheet: - params += ['html.stylesheet "%s"' % self.stylesheet] - if self.format == 'htmlhelp': - params += ['htmlhelp.chm "%s"' % self.basename('.chm'), - 'htmlhelp.hhp "%s"' % self.basename('.hhp'), - 'htmlhelp.hhk "%s"' % self.basename('.hhk'), - 'htmlhelp.hhc "%s"' % self.basename('.hhc')] - if self.doctype == 'book': - params += ['toc.section.depth 1'] - # Books are chunked at chapter level. - params += ['chunk.section.depth 0'] - for o in params: - if o.split()[0]+' ' not in self.xsltproc_opts: - self.xsltproc_opts += ' --stringparam ' + o - if self.fop_opts: - self.fop = True - if os.path.splitext(self.asciidoc_file)[1].lower() == '.xml': - self.skip_asciidoc = True - else: - self.skip_asciidoc = False - - def dst_path(self, ext): - ''' - Return name of file or directory in the destination directory with - the same name as the asciidoc source file but with extension ext. - ''' - return os.path.join(self.destination_dir, self.basename(ext)) - - def basename(self, ext): - ''' - Return the base name of the asciidoc source file but with extension - ext. - ''' - return os.path.basename(os.path.splitext(self.asciidoc_file)[0]) + ext - - def asciidoc_conf_file(self, path): - ''' - Return full path name of file in asciidoc configuration files directory. - Search first the directory containing the asciidoc executable then - the global configuration file directory. - ''' - f = os.path.join(os.path.dirname(self.asciidoc), path) - if not os.path.isfile(f): - f = os.path.join(CONF_DIR, path) - if not os.path.isfile(f): - die('missing configuration file: %s' % f) - return os.path.normpath(f) - - def xsl_stylesheet(self, file_name=None): - ''' - Return full path name of file in asciidoc docbook-xsl configuration - directory. - If an XSL file was specified with the --xsl-file option then it is - returned. - ''' - if self.xsl_file is not None: - return self.xsl_file - if not file_name: - file_name = self.format + '.xsl' - return self.asciidoc_conf_file(os.path.join('docbook-xsl', file_name)) - - def copy_resources(self, html_files, src_dir, dst_dir, resources=[]): - ''' - Search html_files for images and CSS resource URIs (html_files can be a - list of file names or a single file name). - Copy them from the src_dir to the dst_dir. - If not found in src_dir then recursively search all specified - resource directories. - Optional additional resources files can be passed in the resources list. - ''' - resources = resources[:] - resources += find_resources(html_files, 'link', 'href', - lambda attrs: attrs.get('type') == 'text/css') - resources += find_resources(html_files, 'img', 'src') - resources += self.resource_files - resources = list(set(resources)) # Drop duplicates. - resources.sort() - for f in resources: - if '=' in f: - src, dst = f.split('=') - if not dst: - dst = src - else: - src = dst = f - src = os.path.normpath(src) - dst = os.path.normpath(dst) - if os.path.isabs(dst): - die('absolute resource file name: %s' % dst) - if dst.startswith(os.pardir): - die('resource file outside destination directory: %s' % dst) - src = os.path.join(src_dir, src) - dst = os.path.join(dst_dir, dst) - if not os.path.isfile(src): - for d in self.resource_dirs: - d = os.path.join(src_dir, d) - found = find_files(d, os.path.basename(src)) - if found: - src = found[0] - break - else: - if not os.path.isfile(dst): - die('missing resource: %s' % src) - continue - # Arrive here if resource file has been found. - if os.path.normpath(src) != os.path.normpath(dst): - dstdir = os.path.dirname(dst) - shell_makedirs(dstdir) - shell_copy(src, dst) - - def to_backend(self): - ''' - Convert AsciiDoc source file to a backend output file using the global - 'to_<backend name>' function (loaded from backend plugin a2x-backend.py - file). - Executes the global function in an A2X class instance context. - ''' - eval('to_%s(self)' % self.backend) - - def to_docbook(self): - ''' - Use asciidoc to convert asciidoc_file to DocBook. - args is a string containing additional asciidoc arguments. - ''' - docbook_file = self.dst_path('.xml') - if self.skip_asciidoc: - if not os.path.isfile(docbook_file): - die('missing docbook file: %s' % docbook_file) - return - shell('"%s" --backend docbook -a "a2x-format=%s" %s --out-file "%s" "%s"' % - (self.asciidoc, self.format, self.asciidoc_opts, docbook_file, self.asciidoc_file)) - if not self.no_xmllint and XMLLINT: - shell('"%s" --nonet --noout --valid "%s"' % (XMLLINT, docbook_file)) - - def to_xhtml(self): - self.to_docbook() - docbook_file = self.dst_path('.xml') - xhtml_file = self.dst_path('.html') - opts = '%s --output "%s"' % (self.xsltproc_opts, xhtml_file) - exec_xsltproc(self.xsl_stylesheet(), docbook_file, self.destination_dir, opts) - src_dir = os.path.dirname(self.asciidoc_file) - self.copy_resources(xhtml_file, src_dir, self.destination_dir) - - def to_manpage(self): - self.to_docbook() - docbook_file = self.dst_path('.xml') - opts = self.xsltproc_opts - exec_xsltproc(self.xsl_stylesheet(), docbook_file, self.destination_dir, opts) - - def to_pdf(self): - if self.fop: - self.exec_fop() - else: - self.exec_dblatex() - - def exec_fop(self): - self.to_docbook() - docbook_file = self.dst_path('.xml') - xsl = self.xsl_stylesheet('fo.xsl') - fo = self.dst_path('.fo') - pdf = self.dst_path('.pdf') - opts = '%s --output "%s"' % (self.xsltproc_opts, fo) - exec_xsltproc(xsl, docbook_file, self.destination_dir, opts) - shell('"%s" %s -fo "%s" -pdf "%s"' % (FOP, self.fop_opts, fo, pdf)) - if not self.keep_artifacts: - shell_rm(fo) - - def exec_dblatex(self): - self.to_docbook() - docbook_file = self.dst_path('.xml') - xsl = self.asciidoc_conf_file(os.path.join('dblatex','asciidoc-dblatex.xsl')) - sty = self.asciidoc_conf_file(os.path.join('dblatex','asciidoc-dblatex.sty')) - shell('"%s" -t %s -p "%s" -s "%s" %s "%s"' % - (DBLATEX, self.format, xsl, sty, self.dblatex_opts, docbook_file)) - - def to_dvi(self): - self.exec_dblatex() - - def to_ps(self): - self.exec_dblatex() - - def to_tex(self): - self.exec_dblatex() - - def to_htmlhelp(self): - self.to_chunked() - - def to_chunked(self): - self.to_docbook() - docbook_file = self.dst_path('.xml') - opts = self.xsltproc_opts - xsl_file = self.xsl_stylesheet() - if self.format == 'chunked': - dst_dir = self.dst_path('.chunked') - elif self.format == 'htmlhelp': - dst_dir = self.dst_path('.htmlhelp') - if not 'base.dir ' in opts: - opts += ' --stringparam base.dir "%s/"' % os.path.basename(dst_dir) - # Create content. - shell_rmtree(dst_dir) - shell_makedirs(dst_dir) - exec_xsltproc(xsl_file, docbook_file, self.destination_dir, opts) - html_files = find_files(dst_dir, '*.html') - src_dir = os.path.dirname(self.asciidoc_file) - self.copy_resources(html_files, src_dir, dst_dir) - - def update_epub_manifest(self, opf_file): - ''' - Scan the OEBPS directory for any files that have not been registered in - the OPF manifest then add them to the manifest. - ''' - opf_dir = os.path.dirname(opf_file) - resource_files = [] - for (p,dirs,files) in os.walk(os.path.dirname(opf_file)): - for f in files: - f = os.path.join(p,f) - if os.path.isfile(f): - assert f.startswith(opf_dir) - f = '.' + f[len(opf_dir):] - f = os.path.normpath(f) - if f not in ['content.opf']: - resource_files.append(f) - opf = xml.dom.minidom.parseString(read_file(opf_file)) - manifest_files = [] - manifest = opf.getElementsByTagName('manifest')[0] - for el in manifest.getElementsByTagName('item'): - f = el.getAttribute('href') - f = os.path.normpath(f) - manifest_files.append(f) - count = 0 - for f in resource_files: - if f not in manifest_files: - count += 1 - verbose('adding to manifest: %s' % f) - item = opf.createElement('item') - item.setAttribute('href', f.replace(os.path.sep, '/')) - item.setAttribute('id', 'a2x-%d' % count) - mimetype = mimetypes.guess_type(f)[0] - if mimetype is None: - die('unknown mimetype: %s' % f) - item.setAttribute('media-type', mimetype) - manifest.appendChild(item) - if count > 0: - write_file(opf_file, opf.toxml()) - - def to_epub(self): - self.to_docbook() - xsl_file = self.xsl_stylesheet() - docbook_file = self.dst_path('.xml') - epub_file = self.dst_path('.epub') - build_dir = epub_file + '.d' - shell_rmtree(build_dir) - shell_makedirs(build_dir) - # Create content. - exec_xsltproc(xsl_file, docbook_file, build_dir, self.xsltproc_opts) - # Copy resources referenced in the OPF and resources referenced by the - # generated HTML (in theory DocBook XSL should ensure they are - # identical but this is not always the case). - src_dir = os.path.dirname(self.asciidoc_file) - dst_dir = os.path.join(build_dir, 'OEBPS') - opf_file = os.path.join(dst_dir, 'content.opf') - opf_resources = find_resources(opf_file, 'item', 'href') - html_files = find_files(dst_dir, '*.html') - self.copy_resources(html_files, src_dir, dst_dir, opf_resources) - # Register any unregistered resources. - self.update_epub_manifest(opf_file) - # Build epub archive. - cwd = os.getcwd() - shell_cd(build_dir) - try: - if not self.dry_run: - zip = zipfile.ZipFile(epub_file, 'w') - try: - # Create and add uncompressed mimetype file. - verbose('archiving: mimetype') - write_file('mimetype', 'application/epub+zip') - zip.write('mimetype', compress_type=zipfile.ZIP_STORED) - # Compress all remaining files. - for (p,dirs,files) in os.walk('.'): - for f in files: - f = os.path.normpath(os.path.join(p,f)) - if f != 'mimetype': - verbose('archiving: %s' % f) - zip.write(f, compress_type=zipfile.ZIP_DEFLATED) - finally: - zip.close() - verbose('created archive: %s' % epub_file) - finally: - shell_cd(cwd) - if not self.keep_artifacts: - shell_rmtree(build_dir) - if self.epubcheck and EPUBCHECK: - if not find_executable(EPUBCHECK): - warning('epubcheck skipped: unable to find executable: %s' % EPUBCHECK) - else: - shell('"%s" "%s"' % (EPUBCHECK, epub_file)) - - def to_text(self): - text_file = self.dst_path('.text') - html_file = self.dst_path('.text.html') - if self.lynx: - shell('"%s" %s --conf-file "%s" -b html4 -a "a2x-format=%s" -o "%s" "%s"' % - (self.asciidoc, self.asciidoc_opts, self.asciidoc_conf_file('text.conf'), - self.format, html_file, self.asciidoc_file)) - shell('"%s" -dump "%s" > "%s"' % - (LYNX, html_file, text_file)) - else: - # Use w3m(1). - self.to_docbook() - docbook_file = self.dst_path('.xml') - opts = '%s --output "%s"' % (self.xsltproc_opts, html_file) - exec_xsltproc(self.xsl_stylesheet(), docbook_file, - self.destination_dir, opts) - shell('"%s" -cols 70 -dump -T text/html -no-graph "%s" > "%s"' % - (W3M, html_file, text_file)) - if not self.keep_artifacts: - shell_rm(html_file) - - -##################################################################### -# Script main line. -##################################################################### - -if __name__ == '__main__': - description = '''A toolchain manager for AsciiDoc (converts Asciidoc text files to other file formats)''' - from optparse import OptionParser - parser = OptionParser(usage='usage: %prog [OPTIONS] SOURCE_FILE', - version='%s %s' % (PROG,VERSION), - description=description) - parser.add_option('-a', '--attribute', - action='append', dest='attributes', default=[], metavar='ATTRIBUTE', - help='set asciidoc attribute value') - parser.add_option('--asciidoc-opts', - action='append', dest='asciidoc_opts', default=[], - metavar='ASCIIDOC_OPTS', help='asciidoc options') - #DEPRECATED - parser.add_option('--copy', - action='store_true', dest='copy', default=False, - help='DEPRECATED: does nothing') - parser.add_option('--conf-file', - dest='conf_file', default=None, metavar='CONF_FILE', - help='configuration file') - parser.add_option('-D', '--destination-dir', - action='store', dest='destination_dir', default=None, metavar='PATH', - help='output directory (defaults to SOURCE_FILE directory)') - parser.add_option('-d','--doctype', - action='store', dest='doctype', metavar='DOCTYPE', - choices=('article','manpage','book'), - help='article, manpage, book') - parser.add_option('-b','--backend', - action='store', dest='backend', metavar='BACKEND', - help='name of backend plugin') - parser.add_option('--epubcheck', - action='store_true', dest='epubcheck', default=False, - help='check EPUB output with epubcheck') - parser.add_option('-f','--format', - action='store', dest='format', metavar='FORMAT', default = 'pdf', - choices=('chunked','epub','htmlhelp','manpage','pdf', 'text', - 'xhtml','dvi','ps','tex','docbook'), - help='chunked, epub, htmlhelp, manpage, pdf, text, xhtml, dvi, ps, tex, docbook') - parser.add_option('--icons', - action='store_true', dest='icons', default=False, - help='use admonition, callout and navigation icons') - parser.add_option('--icons-dir', - action='store', dest='icons_dir', - default=None, metavar='PATH', - help='admonition and navigation icon directory') - parser.add_option('-k', '--keep-artifacts', - action='store_true', dest='keep_artifacts', default=False, - help='do not delete temporary build files') - parser.add_option('--lynx', - action='store_true', dest='lynx', default=False, - help='use lynx to generate text files') - parser.add_option('-L', '--no-xmllint', - action='store_true', dest='no_xmllint', default=False, - help='do not check asciidoc output with xmllint') - parser.add_option('-n','--dry-run', - action='store_true', dest='dry_run', default=False, - help='just print the commands that would have been executed') - parser.add_option('-r','--resource', - action='append', dest='resources', default=[], - metavar='PATH', - help='resource file or directory containing resource files') - parser.add_option('-m', '--resource-manifest', - action='store', dest='resource_manifest', default=None, metavar='FILE', - help='read resources from FILE') - #DEPRECATED - parser.add_option('--resource-dir', - action='append', dest='resources', default=[], - metavar='PATH', - help='DEPRECATED: use --resource') - #DEPRECATED - parser.add_option('-s','--skip-asciidoc', - action='store_true', dest='skip_asciidoc', default=False, - help='DEPRECATED: redundant') - parser.add_option('--stylesheet', - action='store', dest='stylesheet', default=None, - metavar='STYLESHEET', - help='HTML CSS stylesheet file name') - #DEPRECATED - parser.add_option('--safe', - action='store_true', dest='safe', default=False, - help='DEPRECATED: does nothing') - parser.add_option('--dblatex-opts', - action='append', dest='dblatex_opts', default=[], - metavar='DBLATEX_OPTS', help='dblatex options') - parser.add_option('--backend-opts', - action='append', dest='backend_opts', default=[], - metavar='BACKEND_OPTS', help='backend plugin options') - parser.add_option('--fop', - action='store_true', dest='fop', default=False, - help='use FOP to generate PDF files') - parser.add_option('--fop-opts', - action='append', dest='fop_opts', default=[], - metavar='FOP_OPTS', help='options for FOP pdf generation') - parser.add_option('--xsltproc-opts', - action='append', dest='xsltproc_opts', default=[], - metavar='XSLTPROC_OPTS', help='xsltproc options for XSL stylesheets') - parser.add_option('--xsl-file', - action='store', dest='xsl_file', metavar='XSL_FILE', - help='custom XSL stylesheet') - parser.add_option('-v', '--verbose', - action='count', dest='verbose', default=0, - help='increase verbosity') - if len(sys.argv) == 1: - parser.parse_args(['--help']) - source_options = get_source_options(sys.argv[-1]) - argv = source_options + sys.argv[1:] - opts, args = parser.parse_args(argv) - if len(args) != 1: - parser.error('incorrect number of arguments') - opts.asciidoc_opts = ' '.join(opts.asciidoc_opts) - opts.dblatex_opts = ' '.join(opts.dblatex_opts) - opts.fop_opts = ' '.join(opts.fop_opts) - opts.xsltproc_opts = ' '.join(opts.xsltproc_opts) - opts.backend_opts = ' '.join(opts.backend_opts) - opts = eval(str(opts)) # Convert optparse.Values to dict. - a2x = A2X(opts) - OPTIONS = a2x # verbose and dry_run used by utility functions. - verbose('args: %r' % argv) - a2x.asciidoc_file = args[0] - try: - a2x.load_conf() - a2x.execute() - except KeyboardInterrupt: - exit(1) |