diff --git a/wafhelpers/asciidoc.py b/wafhelpers/asciidoc.py index b6aa1f116..a2218bb69 100644 --- a/wafhelpers/asciidoc.py +++ b/wafhelpers/asciidoc.py @@ -1,73 +1,173 @@ -import re - -from waflib import Task -from waflib.TaskGen import extension - -# asciidoc -b html5 -a linkcss -a stylesdir=/mnt/devel/ntp/commit/docs \ -# -o asd driver32.adoc - -# Borrowed from waf/docs/book/wscript in the Waf Project. -re_xi = re.compile('''^(include|image)::(.*?.(adoc|\\{PIC\\}))\[''', re.M) - - -def ascii_doc_scan(self): - p = self.inputs[0].parent - node_lst = [self.inputs[0]] - seen = [] - depnodes = [] - - while node_lst: - nd = node_lst.pop(0) - if nd in seen: - continue - seen.append(nd) - - code = nd.read() - for m in re_xi.finditer(code): - name = m.group(2) - if m.group(3) == '{PIC}': - - ext = '.eps' - if self.generator.rule.rfind('A2X') > 0: - ext = '.png' - - k = p.find_resource(name.replace('{PIC}', ext)) - if k: - depnodes.append(k) - else: - k = self.inputs[0].find_resource(name) - if k: - depnodes.append(k) - node_lst.append(k) - return [depnodes, ()] +'''Most of the functionality for building HTML and man pages from AsciiDoc.''' +import re -# ASCIIDOC_FLAGS are almost always needed and need to be set by the user. -class asciidoc(Task.Task): - color = "BLUE" - run_str = '${BIN_ASCIIDOC} -b html5 -a linkcss ${ASCIIDOC_FLAGS} ' \ - '-o ${TGT[0].name} ${SRC[0].abspath()}' - ext_out = ".html" +from waflib import Task # pylint: disable=import-error +from waflib.TaskGen import extension # pylint: disable=import-error + + +def options(opt): + 'Add command line options for AsciiDoc processing.' + grp = opt.add_option_group('NTP documentation configure options') + grp.add_option('--disable-doc', action='store_true', + default=False, help='Disable HTML document building.') + grp.add_option('--enable-doc', action='store_true', + default=False, help='Enable HTML document building.') + grp.add_option('--disable-manpage', action='store_true', + default=False, help='Disable manpage building.') + grp.add_option('--enable-manpage', action='store_true', + default=False, help='Enable manpage building.') + + +def configure(ctx): + 'Set options from the extended environment and command line arguments.' + + if ctx.options.disable_doc and ctx.options.enable_doc: + ctx.fatal('--disable-doc and --enable-doc conflict.') + if ctx.options.disable_manpage and ctx.options.enable_manpage: + ctx.fatal('--disable-manpage and --enable-manpage conflict.') + + ctx.env.BUILD_DOC = False + ctx.env.BUILD_MAN = False + if ctx.options.disable_doc and ctx.options.disable_manpage: + ctx.msg('AsciiDoc processor', 'unnecessary') + return + + # asciidoctor versions < 1.5.8 throw warnings for manpages and driver_shm. + # asciidoc versions 8.6.5-8.6.7 throw warnings for warp.adoc and versions + # < 8.6.4 have no HTML5 backend. + # asciidoc3 versions < 3.0.2 throw errors. + adoc_list = [['asciidoctor', (1, 5, 8)], + ['asciidoc', (8, 6, 8)], + ['asciidoc3', (3, 0, 2)], + ] + for progname, asciidocminver in adoc_list: + if 'BIN_ASCIIDOC' not in ctx.env or ctx.env.BIN_ASCIIDOC == []: + # used to make man and HTML pages + ctx.find_program(progname, var='BIN_ASCIIDOC', mandatory=False) + # make sure asciidoc is new enough. + # based on check_python_version() from waf + + if ctx.env.BIN_ASCIIDOC: + # https://lists.ntpsec.org/pipermail/devel/2016-July/001778.html + # Get asciidoc version string + cmd = ctx.env.BIN_ASCIIDOC + ['--version'] + # example output: asciidoc 8.6.9 + version_string = ctx.cmd_and_log(cmd).split()[1] + match = re.match(r'^(\d+)\.(\d+)\.(\d+)', version_string) + if match: + version_tuple = tuple(map(int, match.groups())) + if version_tuple >= asciidocminver: + if progname == 'asciidoc': + ctx.find_program('a2x', var='BIN_A2X', mandatory=False) + ctx.find_program('xsltproc', var='BIN_XSLTPROC', + mandatory=False) + elif progname == 'asciidoc3': + ctx.find_program('a2x3', var='BIN_A2X', mandatory=False) + ctx.find_program('xsltproc', var='BIN_XSLTPROC', + mandatory=False) + + if version_tuple >= asciidocminver: + color = 'GREEN' + else: + color = 'YELLOW' + ctx.env.BIN_ASCIIDOC = [] + ctx.msg('Checking for %s version >= %s' % + (progname, '%d.%d.%d' % asciidocminver), + version_string, color=color) + + if not ctx.env.BIN_ASCIIDOC: + if not (ctx.options.enable_doc or ctx.options.enable_manpage): + # The user did not require either, so this is fine. + return + + error = 'no AsciiDoc processor qualified' + if ctx.options.enable_doc: + error += ', remove --enable-doc' + if ctx.options.enable_manpage: + error += ', remove --enable-manpage' + ctx.fatal(error) + + ctx.env.BUILD_DOC = not ctx.options.disable_doc + ctx.env.BUILD_MAN = not ctx.options.disable_manpage + + if 'asciidoctor' in ctx.env.BIN_ASCIIDOC[0]: + ctx.env.ARGS_DOC = [ + ctx.env.BIN_ASCIIDOC[0], + '-a', 'attribute-missing=warn', + # To eliminate compat-mode: + # 'italics' needs to be changed to _italics_ + # +monospace+ needs to be changed to `monospace` + # https://asciidoctor.org/docs/migration/#migration-cheatsheet + '-a', 'compat-mode', + ] + ctx.env.ARGS_MAN = ctx.env.ARGS_DOC + [ + '-b', 'manpage', + ] + ctx.env.ARGS_DOC += [ + '-b', 'xhtml5', '-a', 'linkcss', + '-a', 'stylesheet=asciidoc.css', + ] + elif 'asciidoc' in ctx.env.BIN_ASCIIDOC[0]: + ctx.env.ARGS_DOC = [ + ctx.env.BIN_ASCIIDOC[0], + '-a', 'attribute-missing=warn', + '-b', 'html5', '-a', 'linkcss', + '-a', 'stylesheet=asciidoc.css', + ] + if ctx.env.BIN_A2X and ctx.env.BIN_XSLTPROC: + ctx.env.ARGS_MAN = [ + ctx.env.BIN_A2X[0], + '-a', 'attribute-missing=warn', + '-f', 'manpage', '--no-xmllint', + ] + else: + if ctx.options.enable_manpage: + ctx.fatal('a2x/xsltproc not found, remove --enable-manpage') + ctx.env.BUILD_MAN = False + + +def build(ctx): + 'Set processor noise level and set HTML pages to build.' + from waflib.Logs import verbose # pylint: disable=import-error + if verbose > 1: # Pass verbosity to AsciiDoc toolchain + if ctx.env.ARGS_DOC: + ctx.env.ARGS_DOC += ['-v'] + if ctx.env.ARGS_MAN: + ctx.env.ARGS_MAN += ['-v'] + if ctx.env.BUILD_DOC and ctx.variant == 'main': + ctx.recurse('docs') + + +class html(Task.Task): + 'Define HTML build process.' + # Optional weight to tune the priority for task instances. + # The higher, the earlier. The weight only applies to single task objects. + weight = 3 # set arbitrarily high to be first as to not slow down later tasks + run_str = '${ARGS_DOC} -o ${TGT[0].name} ${SRC[0].abspath()}' + ext_out = '.html' + + +class man(Task.Task): + 'Define manpage build process.' + weight = 2 # set arbitrarily high to be second as to not slow down later tasks (Failed) + run_str = '${ARGS_MAN} ${SRC[0].abspath()}' @extension('.adoc') -def run_asciidoc(self, node): - out = node.change_ext(".html") - tsk = self.create_task("asciidoc", node, [out]) +def run_html(self, node): + 'Add HTML build caller function.' + out = node.change_ext('.html') + tsk = self.create_task('html', node, [out]) tsk.cwd = node.parent.get_bld().abspath() -class a2x(Task.Task): - color = "YELLOW" - shell = True - run_str = '${BIN_A2X} ${A2X_FLAGS} ${SRC[0].abspath()}' - scan = ascii_doc_scan - - @extension('.man-tmp') -def run_a2x(self, node): +def run_manpage(self, node): + 'Add manpage build caller function.' n_file = node.path_from(self.bld.bldnode) - out = "%s.%s" % (n_file.replace("-man.adoc.man-tmp", ""), self.section) + out = '%s.%s' % (n_file.replace('-man.adoc.man-tmp', ''), self.section) out_n = self.bld.path.find_or_declare(out) - self.create_task('a2x', node, out_n) - self.bld.install_files("${MANDIR}/man%s/" % self.section, out_n) + self.create_task('man', node, out_n) + self.bld.install_files('${MANDIR}/man%s/' % self.section, out_n) + weight = 3 diff --git a/wafhelpers/waf.py b/wafhelpers/waf.py index 96f753ecb..4f2d562a4 100644 --- a/wafhelpers/waf.py +++ b/wafhelpers/waf.py @@ -41,10 +41,7 @@ def manpage_subst_fun(self, code): @conf def manpage(ctx, section, source): - # ctx.install_files('${MANDIR}' + "/man%s/" % section, - # source.replace("-man.adoc", ".%s" % section)) - - if not ctx.env.ENABLE_DOC or ctx.env.DISABLE_MANPAGE: + if not ctx.env.BUILD_MAN: return ctx(features="subst", diff --git a/wscript b/wscript index c7c5468b1..601edaacd 100644 --- a/wscript +++ b/wscript @@ -55,10 +55,12 @@ Usage: waf def options(ctx): options_cmd(ctx, config) + ctx.load('asciidoc', tooldir='wafhelpers/') ctx.recurse("pylib") def configure(ctx): + ctx.load('asciidoc', tooldir='wafhelpers/') class oc(Build.BuildContext): cmd = 'oc' @@ -93,7 +95,6 @@ def configure(ctx): ctx.run_build_cls = 'check' ctx.load('waf', tooldir='wafhelpers/') ctx.load('waf_unit_test') - ctx.load('pytest') ctx.load('gnu_dirs') with open("VERSION", "r") as f: @@ -148,55 +149,6 @@ def configure(ctx): ctx.find_program("awk", var="BIN_AWK", mandatory=False) ctx.find_program("sh", var="BIN_SH", mandatory=False) - # used to make man and html pages - ctx.find_program("asciidoc", var="BIN_ASCIIDOC", mandatory=False) - # make sure asciidoc is new enough. - # based on check_python_version() from waf - if ctx.env.BIN_ASCIIDOC: - # https://lists.ntpsec.org/pipermail/devel/2016-July/001778.html - asciidocminver = (8, 6, 0) - # Get asciidoc version string - cmd = ctx.env.BIN_ASCIIDOC + ['--version'] - # example output: asciidoc 8.6.9 - lines = ctx.cmd_and_log(cmd).split()[1].split(".") - assert len(lines) == 3, "found %r lines, expected 3: %r" \ - % (len(lines), lines) - asciidocver_tuple = (int(lines[0]), int(lines[1]), int(lines[2])) - - # Compare asciidoc version with the minimum required - result = (asciidocver_tuple >= asciidocminver) - - asciidocver_full = '.'.join(map(str, asciidocver_tuple[:3])) - asciidocminver_str = '.'.join(map(str, asciidocminver)) - ctx.msg('Checking for asciidoc version >= %s' % (asciidocminver_str,), - asciidocver_full, color=result and 'GREEN' or 'YELLOW') - - if not result: - del ctx.env.BIN_ASCIIDOC - ctx.find_program("a2x", var="BIN_A2X", mandatory=False) - ctx.find_program("xsltproc", var="BIN_XSLTPROC", mandatory=False) - - ctx.env.ENABLE_DOC = False - if ctx.env.BIN_ASCIIDOC and ctx.env.BIN_XSLTPROC and ctx.env.BIN_A2X: - ctx.env.ENABLE_DOC = True - - if ctx.options.enable_doc and not ctx.env.ENABLE_DOC: - ctx.fatal("asciidoc and xsltproc are required in order " - "to build documentation") - elif ctx.options.enable_doc: - ctx.env.ASCIIDOC_FLAGS = [] - ctx.env.ENABLE_DOC_USER = ctx.options.enable_doc - - # XXX: conditionally build this with --disable-man? - # Should it build without docs enabled? - ctx.env.A2X_FLAGS = ["--format", "manpage"] - if not ctx.options.enable_a2x_xmllint: - ctx.env.A2X_FLAGS += ["--no-xmllint"] - - # Disable manpages within build() - if ctx.options.disable_manpage: - ctx.env.DISABLE_MANPAGE = True - ctx.check_cfg( package='systemd', variables=['systemdsystemunitdir'], uselib_store='SYSTEMD', mandatory=False, @@ -662,7 +614,7 @@ int main(int argc, char **argv) { ('strlcat', ["string.h"]) ) for ft in optional_functions: - probe_function(ctx, function=ft[0], prerequisites=ft[1]) + probe_function(ctx, function=ft[0], prerequisites=ft[1]) # This area is still work in progress # Need to disable making symbols @@ -897,8 +848,8 @@ int main(int argc, char **argv) { msg_setting("Droproot Support", droproot_type) msg_setting("Debug Support", yesno(ctx.options.enable_debug)) msg_setting("Refclocks", ", ".join(sorted(ctx.env.REFCLOCK_LIST))) - msg_setting("Build Manpages", - yesno(ctx.env.ENABLE_DOC and not ctx.env.DISABLE_MANPAGE)) + msg_setting("Build Docs", yesno(ctx.env.BUILD_DOC)) + msg_setting("Build Manpages", yesno(ctx.env.BUILD_MAN)) ctx.recurse("pylib") # Convert the Python directories to absolute paths. @@ -1035,14 +986,6 @@ def build(ctx): # the build directory never happens. This is how we foil that. ctx.add_pre_fun(lambda ctx: ctx.exec_command("rm -f pylib/*.py[co]")) - if verbose > 0: # Pass Verbosity to asciidoc and a2x - ctx.env.A2X_FLAGS += ["-v"] - ctx.env.ASCIIDOC_FLAGS += ["-v"] - - if ctx.env.ENABLE_DOC_USER: - if ctx.variant != "main": - ctx.recurse("docs") - if ctx.variant == "host": ctx.recurse("ntpd") return