#!/usr/bin/env python3 # vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: # Copyright 2014-2015 Florian Bruhin (The Compiler) # This file is part of qutebrowser. # # qutebrowser is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # qutebrowser is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . """Generate the html documentation based on the asciidoc files.""" import re import os import os.path import sys import subprocess import glob import shutil import tempfile import argparse sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir)) from scripts import utils class AsciiDoc: """Abstraction of an asciidoc subprocess.""" FILES = [ ('FAQ.asciidoc', 'qutebrowser/html/doc/FAQ.html'), ('CHANGELOG.asciidoc', 'qutebrowser/html/doc/CHANGELOG.html'), ('doc/quickstart.asciidoc', 'qutebrowser/html/doc/quickstart.html'), ('doc/userscripts.asciidoc', 'qutebrowser/html/doc/userscripts.html'), ] def __init__(self, args): self._cmd = None self._args = args self._homedir = None self._themedir = None self._tempdir = None self._failed = False def prepare(self): """Get the asciidoc command and create the homedir to use.""" self._cmd = self._get_asciidoc_cmd() self._homedir = tempfile.mkdtemp() self._themedir = os.path.join( self._homedir, '.asciidoc', 'themes', 'qute') self._tempdir = os.path.join(self._homedir, 'tmp') os.makedirs(self._tempdir) os.makedirs(self._themedir) def cleanup(self): """Clean up the temporary home directory for asciidoc.""" if self._homedir is not None and not self._failed: shutil.rmtree(self._homedir) def build(self): if self._args.website: self._build_website() else: self._build_docs() def _build_docs(self): files = self.FILES[:] for src in glob.glob('doc/help/*.asciidoc'): name, _ext = os.path.splitext(os.path.basename(src)) dst = 'qutebrowser/html/doc/{}.html'.format(name) files.append((src, dst)) for src, dst in files: self.call(src, dst) def _build_website(self): theme_file = os.path.abspath(os.path.join('www', 'qute.css')) shutil.copy(theme_file, self._themedir) outdir = self._args.website[0] for root, _dirs, files in os.walk(os.getcwd()): for filename in files: if os.path.splitext(filename)[1] != '.asciidoc': continue src = os.path.join(root, filename) src_basename = os.path.basename(src) parts = [outdir] dirname = os.path.dirname(src) if dirname: parts.append(os.path.relpath(os.path.dirname(src))) parts.append( os.extsep.join((os.path.splitext(src_basename)[0], 'html'))) dst = os.path.join(*parts) os.makedirs(os.path.dirname(dst), exist_ok=True) modified_src = os.path.join(self._tempdir, src_basename) shutil.copy('www/header.asciidoc', modified_src) with open(modified_src, 'a', encoding='utf-8') as outfp: with open(src, 'r', encoding='utf-8') as infp: outfp.write('\n') hidden = False for line in infp: if line.strip() == '// QUTE_WEB_HIDE': assert not hidden hidden = True elif line.strip() == '// QUTE_WEB_HIDE_END': assert hidden hidden = False # Let's see if this looks good everywhere... if re.match(r'^=+$', line): line = line.replace('=', '-') elif re.match(r'^= .+', line): line = '==' + line[1:] if not hidden: outfp.write(line) self.call(modified_src, dst, '--theme=qute') for path in ['icons', 'doc/img']: shutil.copytree(path, os.path.join(outdir, path)) os.symlink('README.html', os.path.join(outdir, 'index.html')) def _get_asciidoc_cmd(self): """Try to find out what commandline to use to invoke asciidoc.""" if self._args.asciidoc is not None: return self._args.asciidoc try: subprocess.call(['asciidoc'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except OSError: pass else: return ['asciidoc'] try: subprocess.call(['asciidoc.py'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except OSError: pass else: return ['asciidoc.py'] raise FileNotFoundError def call(self, src, dst, *args): """Call asciidoc for the given files. Args: src: The source .asciidoc file. dst: The destination .html file, or None to auto-guess. *args: Additional arguments passed to asciidoc. """ print("Calling asciidoc for {}...".format(os.path.basename(src))) cmdline = self._cmd[:] if dst is not None: cmdline += ['--out-file', dst] cmdline += args cmdline.append(src) try: subprocess.check_call(cmdline, env={'HOME': self._homedir}) except (subprocess.CalledProcessError, OSError) as e: self._failed = True utils.print_col(str(e), 'red') print("Keeping modified sources in {}.".format(self._homedir)) sys.exit(1) def main(colors=False): """Generate html files for the online documentation.""" utils.change_cwd() utils.use_color = colors parser = argparse.ArgumentParser() parser.add_argument('--website', help="Build website into a given " "directory.", nargs=1) parser.add_argument('--asciidoc', help="Full path to python and " "asciidoc.py. If not given, it's searched in PATH.", nargs=2, required=False, metavar=('PYTHON', 'ASCIIDOC')) args = parser.parse_args() try: os.mkdir('qutebrowser/html/doc') except FileExistsError: pass asciidoc = AsciiDoc(args) try: asciidoc.prepare() except FileNotFoundError: utils.print_col("Could not find asciidoc! Please install it, or use " "the --asciidoc argument to point this script to the " "correct python/asciidoc.py location!", 'red') sys.exit(1) try: asciidoc.build() finally: asciidoc.cleanup() if __name__ == '__main__': main(colors=True)