Changeset 0bc9c6d in rtems-docs


Ignore:
Timestamp:
Nov 3, 2016, 3:30:47 AM (4 years ago)
Author:
Chris Johns <chrisj@…>
Branches:
4.11, 5, am, master
Children:
040b703
Parents:
3d055ec
Message:

waf: Have configure set building pdf and/or singlehtml.

Move selecting pdf and singlehtml to the configure stage so it
is sticky for all builds. This means a top level build will always
build all formats that have been configured.

Do not complete the configure stage if tools are missing for the
configured output.

Add singlehtml support using the inliner tool. It is nice.

Remove the groups as waf can track the dependences. This lets the
manuals build in parallel.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • common/waf.py

    r3d055ec r0bc9c6d  
    22from waflib.Build import BuildContext
    33
    4 sphinx_min_version = (1,3)
    5 
     4sphinx_min_version = (1, 3)
    65
    76def cmd_spell(ctx):
    8         from waflib import Options
    9         from sys import argv
    10         from subprocess import call
    11 
    12         Options.commands = None # stop warnings about knowing commands.
    13 
    14         if not ctx.env.BIN_ASPELL:
    15                 ctx.fatal("'aspell' is required please add binary to your path and re-run configure.")
    16 
    17         if len(argv) < 3:
    18                 ctx.fatal("Please supply at least one file name")
    19 
    20         files = argv[2:]
    21 
    22         path = ctx.path.parent.abspath()
    23 
    24         # XXX: add error checking eg check if file exists.
    25         for file in files:
    26                 cmd = ctx.env.BIN_ASPELL + ["-c", "--personal=%s/common/spell/dict/rtems" % path, "--extra-dicts=%s/common/spell/en_GB-ise-w_accents.multi" % path, file]
    27 
    28                 print("running:", cmd)
    29                 call(cmd)
     7    from waflib import Options
     8    from sys import argv
     9    from subprocess import call
     10
     11    Options.commands = None # stop warnings about knowing commands.
     12
     13    if not ctx.env.BIN_ASPELL:
     14        ctx.fatal("'aspell' is required please install and re-run configure.")
     15
     16    if len(argv) < 3:
     17        ctx.fatal("Please supply at least one file name")
     18
     19    files = argv[2:]
     20
     21    path = ctx.path.parent.abspath()
     22
     23    # XXX: add error checking eg check if file exists.
     24    for file in files:
     25        cmd = ctx.env.BIN_ASPELL + \
     26              ["-c",
     27               "--personal=%s/common/spell/dict/rtems" % path,
     28               "--extra-dicts=%s/common/spell/en_GB-ise-w_accents.multi" % path,
     29               file]
     30        print("running:", cmd)
     31        call(cmd)
    3032
    3133
    3234def cmd_linkcheck(ctx, conf_dir=".", source_dir="."):
    33         ctx(
    34                 rule    = "${BIN_SPHINX_BUILD} -b linkcheck -c %s -j %d -d build/doctrees %s build/linkcheck" % (conf_dir, ctx.options.jobs, source_dir),
    35                 cwd             = ctx.path.abspath(),
    36                 source  = ctx.path.ant_glob('**/*.rst'),
    37                 target  = "linkcheck/output.txt"
    38         )
    39 
     35    ctx_rule = "${BIN_SPHINX_BUILD} -b linkcheck -c %s -j %d " + \
     36               "-d build/doctrees %s build/linkcheck" % (conf_dir,
     37                                                         ctx.options.jobs,
     38                                                             source_dir)
     39    ctx(
     40        rule   = ctx_rule,
     41        cwd    = ctx.path.abspath(),
     42        source = ctx.path.ant_glob('**/*.rst'),
     43        target = "linkcheck/output.txt"
     44    )
    4045
    4146class spell(BuildContext):
    42         __doc__ = "Check spelling.  Supply a list of files or a glob (*.rst)"
    43         cmd = 'spell'
    44         fun = 'cmd_spell'
    45 
     47    __doc__ = "Check spelling.  Supply a list of files or a glob (*.rst)"
     48    cmd = 'spell'
     49    fun = 'cmd_spell'
    4650
    4751class linkcheck(BuildContext):
    48         __doc__ = "Check all external URL references."
    49         cmd = 'linkcheck'
    50         fun = 'cmd_linkcheck'
    51 
     52    __doc__ = "Check all external URL references."
     53    cmd = 'linkcheck'
     54    fun = 'cmd_linkcheck'
    5255
    5356def check_sphinx_version(ctx, minver):
    54         version = ctx.cmd_and_log(ctx.env.BIN_SPHINX_BUILD + ['--version']).split(" ")[-1:][0].strip()
    55         try:
    56                 ver = tuple(map(int, re.split('[\D]', version)))
    57         except:
    58                 ctx.fatal("Sphinx version cannot be checked: %s" % version)
    59         if ver < minver:
    60                 ctx.fatal("Sphinx version is too old: %s" % ".".join(map(str, ver)))
    61 
    62         return ver
     57    version = ctx.cmd_and_log(ctx.env.BIN_SPHINX_BUILD +
     58                              ['--version']).split(" ")[-1:][0].strip()
     59    try:
     60        ver = tuple(map(int, re.split('[\D]', version)))
     61    except:
     62        ctx.fatal("Sphinx version cannot be checked: %s" % version)
     63    if ver < minver:
     64        ctx.fatal("Sphinx version is too old: %s" % ".".join(map(str, ver)))
     65    return ver
    6366
    6467def sphinx_verbose(ctx):
    65         return ' '.join(ctx.env.SPHINX_VERBOSE)
     68    return ' '.join(ctx.env.SPHINX_VERBOSE)
     69
     70def is_top_build(ctx):
     71    from_top = False
     72    if ctx.env['BUILD_FROM_TOP'] and ctx.env['BUILD_FROM_TOP'] == 'yes':
     73        from_top = True
     74    return from_top
     75
     76def build_dir_setup(ctx, buildtype):
     77    where = buildtype
     78    if is_top_build(ctx):
     79        where = os.path.join(ctx.path.name, where)
     80        bnode = ctx.bldnode.find_node(where)
     81    if bnode is None:
     82        ctx.bldnode.make_node(where).mkdir()
     83    build_dir = ctx.path.get_bld().relpath()
     84    output_node = ctx.path.get_bld().make_node(buildtype)
     85    output_dir = output_node.abspath()
     86    return build_dir, output_node, output_dir
     87
     88def html_resources(ctx, buildtype):
     89    for dir_name in ["_static", "_templates"]:
     90        files = ctx.path.parent.find_node("common").ant_glob("%s/*" % dir_name)
     91        fnode = ctx.path.get_bld().make_node(os.path.join(buildtype, dir_name))
     92        fnode.mkdir() # dirs
     93        ctx(
     94            features = "subst",
     95            is_copy  = True,
     96            source   = files,
     97            target   = [fnode.make_node(x.name) for x in files]
     98        )
     99
     100    # copy images
     101#    ctx.path.get_bld().make_node("images").mkdir()
     102#    files = ctx.path.parent.ant_glob("images/**")
     103#    ctx(
     104#        features    = "subst",
     105#        is_copy     = True,
     106#        source      = files,
     107#        target      = [x.srcpath().replace("../", "") for x in files]
     108#    )
    66109
    67110def cmd_configure(ctx):
    68         ctx.load('tex')
    69 
    70         ctx.env.append_value('PDFLATEXFLAGS', '-shell-escape')
    71 
    72         ctx.find_program("sphinx-build", var="BIN_SPHINX_BUILD", mandatory=True)
    73         ctx.find_program("aspell", var="BIN_ASPELL", mandatory=False)
    74         ctx.find_program("inliner", var="BIN_INLINER", mandatory=False)
    75 
    76         ctx.start_msg("Checking if Sphinx is at least %s.%s" % sphinx_min_version)
    77         ver = check_sphinx_version(ctx, sphinx_min_version)
    78         ctx.end_msg("yes (%s)" % ".".join(map(str, ver)))
    79 
    80         ctx.start_msg("Sphinx Verbose: ")
    81         if 'SPHINX_VERBOSE' not in ctx.env:
    82                 ctx.env.append_value('SPHINX_VERBOSE', ctx.options.sphinx_verbose)
    83         level = sphinx_verbose(ctx)
    84         if level == '-Q':
    85                 level = 'quiet'
    86         ctx.end_msg(level)
    87 
    88 def html_resources(ctx):
    89         for dir_name in ["_static", "_templates"]:
    90                 files = ctx.path.parent.find_node("common").ant_glob("%s/*" % dir_name)
    91                 fnode = ctx.path.get_bld().make_node(os.path.join('html', dir_name))
    92                 fnode.mkdir() # dirs
    93                 ctx(
    94                         features = "subst",
    95                         is_copy  = True,
    96                         source   = files,
    97                         target   = [fnode.make_node(x.name) for x in files]
    98                 )
    99 
    100         # copy images
    101 #       ctx.path.get_bld().make_node("images").mkdir()
    102 #       files = ctx.path.parent.ant_glob("images/**")
    103 #       ctx(
    104 #               features    = "subst",
    105 #               is_copy     = True,
    106 #               source      = files,
    107 #               target      = [x.srcpath().replace("../", "") for x in files]
    108 #       )
     111    ctx.find_program("sphinx-build", var="BIN_SPHINX_BUILD", mandatory = True)
     112    ctx.find_program("aspell", var = "BIN_ASPELL", mandatory = False)
     113
     114    ctx.start_msg("Checking if Sphinx is at least %s.%s" % sphinx_min_version)
     115    ver = check_sphinx_version(ctx, sphinx_min_version)
     116    ctx.end_msg("yes (%s)" % ".".join(map(str, ver)))
     117
     118    ctx.start_msg("Sphinx Verbose: ")
     119    if 'SPHINX_VERBOSE' not in ctx.env:
     120        ctx.env.append_value('SPHINX_VERBOSE', ctx.options.sphinx_verbose)
     121    level = sphinx_verbose(ctx)
     122    if level == '-Q':
     123        level = 'quiet'
     124    ctx.end_msg(level)
     125
     126    #
     127    # Optional builds.
     128    #
     129    ctx.env.BUILD_PDF = 'no'
     130    if ctx.options.pdf:
     131        ctx.env.BUILD_PDF = 'yes'
     132        ctx.load('tex')
     133        if not ctx.env.PDFLATEX or not ctx.env.MAKEINDEX:
     134            ctx.fatal('The programs pdflatex and makeindex are required for PDF output')
     135        if 'PDFLATEXFLAGS' not in ctx.env or \
     136           '-shell-escape' not in ctx.env['PDFLATEXFLAGS']:
     137            ctx.env.append_value('PDFLATEXFLAGS', '-shell-escape')
     138
     139    ctx.envBUILD_SINGLEHTML = 'no'
     140    if ctx.options.singlehtml:
     141        ctx.env.BUILD_SINGLEHTML = 'yes'
     142        ctx.find_program("inliner", var = "BIN_INLINER", mandatory = False)
     143        if not ctx.env.BIN_INLINER:
     144            ctx.fatal("Node inliner is required install with 'npm install -g inliner' " +
     145                      "(https://github.com/remy/inliner)")
    109146
    110147def doc_pdf(ctx, source_dir, conf_dir):
    111         if not ctx.env.PDFLATEX or not ctx.env.MAKEINDEX:
    112                 ctx.fatal('The programs pdflatex and makeindex are required')
    113 
    114         build_dir = ctx.path.get_bld().relpath()
    115         output_node = ctx.path.get_bld().make_node('latex')
    116         output_dir = output_node.abspath()
    117 
    118         ctx(
    119                 rule         = "${BIN_SPHINX_BUILD} %s -b latex -c %s -d build/%s/doctrees %s %s" % (sphinx_verbose(ctx), conf_dir, build_dir, source_dir, output_dir),
    120                 cwd          = ctx.path,
    121                 source       = ctx.path.ant_glob('**/*.rst'),
    122                 target       = ctx.path.find_or_declare("latex/%s.tex" % (ctx.path.name))
    123         )
    124 
    125         ctx.add_group()
    126 
    127         ctx(
    128                 features     = 'tex',
    129                 cwd          = output_dir,
    130                 type         = 'pdflatex',
    131                 source       = "latex/%s.tex" % ctx.path.name,
    132                 prompt       = 0
    133         )
    134 
    135         ctx.install_files('${PREFIX}/%s' % (ctx.path.name),
    136                           'latex/%s.pdf' % (ctx.path.name),
    137                           cwd = output_node,
    138                           quiet = True)
     148    buildtype = 'latex'
     149    build_dir, output_node, output_dir = build_dir_setup(ctx, buildtype)
     150    rule = "${BIN_SPHINX_BUILD} %s -b %s -c %s -d build/%s/doctrees %s %s" % \
     151           (sphinx_verbose(ctx), buildtype, conf_dir,
     152            build_dir, source_dir, output_dir)
     153    ctx(
     154        rule         = rule,
     155        cwd          = ctx.path,
     156        source       = ctx.path.ant_glob('**/*.rst'),
     157        target       = ctx.path.find_or_declare("%s/%s.tex" % (buildtype,
     158                                                               ctx.path.name))
     159    )
     160    ctx(
     161        features     = 'tex',
     162        cwd          = output_dir,
     163        type         = 'pdflatex',
     164        source       = "%s/%s.tex" % (buildtype, ctx.path.name),
     165        prompt       = 0
     166    )
     167    ctx.install_files('${PREFIX}',
     168                      '%s/%s.pdf' % (buildtype, ctx.path.name),
     169                      cwd = output_node,
     170                      quiet = True)
    139171
    140172def doc_singlehtml(ctx, source_dir, conf_dir):
    141         if not ctx.env.BIN_INLINER:
    142                 ctx.fatal("Node inliner is required install with 'npm install -g inliner' (https://github.com/remy/inliner)")
    143 
    144         html_resources(ctx)
    145 
    146         ctx(
    147                 rule    = "${BIN_SPHINX_BUILD} -b singlehtml -c %s -j %d -d build/doctrees %s build/singlehtml" % (conf_dir, ctx.options.jobs, source_dir),
    148                 cwd             = ctx.path.abspath(),
    149                 source  = ctx.path.ant_glob('**/*.rst'),
    150                 target  = "singlehtml/index.html",
    151                 install_path = None
    152         )
    153 
    154         ctx.add_group()
    155 
    156         ctx(
    157                 rule    = "${BIN_INLINER} ${SRC} > ${TGT}",
    158                 source  = "singlehtml/index.html",
    159                 target  = "singlehtml/%s.html" % ctx.path.name,
    160                 install_path = None
    161         )
     173
     174    #
     175    # Use a run command to handle stdout and stderr output from inliner. Using
     176    # a standard rule in the build context locks up.
     177    #
     178    def run(task):
     179        src = task.inputs[0].abspath()
     180        tgt = task.outputs[0].abspath()
     181        cmd = '%s %s' % (task.env.BIN_INLINER[0], src)
     182        so = open(tgt, 'w')
     183        se = open(tgt + '.err', 'w')
     184        r = task.exec_command(cmd, stdout = so, stderr = se)
     185        so.close()
     186        se.close()
     187        #
     188        # The inliner does not handle internal href's correctly and places the
     189        # input's file name in the href. Strip these.
     190        #
     191        with open(tgt, 'r') as i:
     192            before = i.read()
     193            after = before.replace('index.html', '')
     194        i.close()
     195        with open(tgt, 'w') as o:
     196            o.write(after)
     197        o.close()
     198        return r
     199
     200    buildtype = 'singlehtml'
     201    build_dir, output_node, output_dir = build_dir_setup(ctx, buildtype)
     202    html_resources(ctx, buildtype)
     203    rule = "${BIN_SPHINX_BUILD} %s -b %s -c %s -d build/%s/doctrees %s %s" % \
     204           (sphinx_verbose(ctx), buildtype, conf_dir,
     205            build_dir, source_dir, output_dir)
     206    ctx(
     207        rule         = rule,
     208        cwd          = ctx.path,
     209        source       = ctx.path.ant_glob('**/*.rst'),
     210        target       = ctx.path.find_or_declare("%s/index.html" % (buildtype)),
     211        install_path = None
     212    )
     213    ctx(
     214        rule         = run,
     215        inliner      = ctx.env.BIN_INLINER,
     216        source       = "%s/index.html" % buildtype,
     217        target       = "%s/%s.html" % (buildtype, ctx.path.name),
     218        install_path = '${PREFIX}'
     219    )
    162220
    163221def doc_html(ctx, conf_dir, source_dir):
    164 
    165         html_resources(ctx)
    166 
    167         build_dir = ctx.path.get_bld().relpath()
    168         output_node = ctx.path.get_bld().make_node('html')
    169         output_dir = output_node.abspath()
    170 
    171         ctx(
    172                 rule         = "${BIN_SPHINX_BUILD} %s -b html -c %s -d build/%s/doctrees %s %s" % (sphinx_verbose(ctx), conf_dir, build_dir, source_dir, output_dir),
    173                 cwd          = ctx.path,
    174                 source       =  ctx.path.ant_glob('**/*.rst'),# + ctx.path.ant_glob('conf.py'),
    175                 target       = ctx.path.find_or_declare('html/index.html'),
    176                 install_path = None
    177         )
    178 
    179         ctx.install_files('${PREFIX}/%s' % (ctx.path.name),
    180                           output_node.ant_glob('**/*'),
    181                           cwd = output_node,
    182                           relative_trick = True,
    183                           quiet = True)
    184 
    185 def is_top_build(ctx):
    186         from_top = False
    187         if ctx.env['BUILD_FROM_TOP'] and ctx.env['BUILD_FROM_TOP'] == 'yes':
    188                 from_top = True
    189         return from_top
    190 
    191 def build_type(ctx):
    192         build_type = 'html'
    193         if ctx.options.pdf:
    194                 build_type = 'pdf'
    195         return build_type
    196 
    197 def build_dir_setup(ctx):
    198         btype = build_type(ctx)
    199         where = btype
    200         if is_top_build(ctx):
    201                 where = os.path.join(ctx.path.name, where)
    202         bnode = ctx.bldnode.find_node(where)
    203         if bnode is None:
    204                 ctx.bldnode.make_node(where).mkdir()
    205         return where
     222    buildtype = 'html'
     223    build_dir, output_node, output_dir = build_dir_setup(ctx, buildtype)
     224    html_resources(ctx, buildtype)
     225    rule = "${BIN_SPHINX_BUILD} %s -b %s -c %s -d build/%s/doctrees %s %s" % \
     226           (sphinx_verbose(ctx), buildtype, conf_dir,
     227            build_dir, source_dir, output_dir)
     228    ctx(
     229        rule         = rule,
     230        cwd          = ctx.path,
     231        source       = ctx.path.ant_glob('**/*.rst'),
     232        target       = ctx.path.find_or_declare('%s/index.html' % buildtype),
     233        install_path = None
     234    )
     235    ctx.install_files('${PREFIX}/%s' % (ctx.path.name),
     236                      output_node.ant_glob('**/*', quiet = True),
     237                      cwd = output_node,
     238                      relative_trick = True,
     239                      quiet = True)
    206240
    207241def cmd_build(ctx, conf_dir = ".", source_dir = "."):
    208         build_dir_setup(ctx)
    209 
    210         srcnode = ctx.srcnode.abspath()
    211 
    212         if ctx.options.pdf:
    213                 doc_pdf(ctx, source_dir, conf_dir)
    214         elif ctx.options.singlehtml:
    215                 html_resources(ctx)
    216                 doc_singlehtml(ctx, source_dir, conf_dir)
    217         else:
    218                 doc_html(ctx, source_dir, conf_dir)
     242    srcnode = ctx.srcnode.abspath()
     243
     244    if ctx.env.BUILD_PDF == 'yes':
     245        doc_pdf(ctx, source_dir, conf_dir)
     246
     247    if ctx.env.BUILD_SINGLEHTML == 'yes':
     248        doc_singlehtml(ctx, source_dir, conf_dir)
     249
     250    doc_html(ctx, source_dir, conf_dir)
    219251
    220252def cmd_options(ctx):
    221         ctx.add_option('--sphinx-verbose', action='store', default="-Q", help="Sphinx verbose.")
    222         ctx.add_option('--pdf', action='store_true', default=False, help="Build PDF.")
    223         ctx.add_option('--singlehtml', action='store_true', default=False, help="Build Single HTML file, requires Node Inliner")
    224 
     253    ctx.add_option('--sphinx-verbose',
     254                   action = 'store',
     255                   default = "-Q",
     256                   help = "Sphinx verbose.")
     257    ctx.add_option('--pdf',
     258                   action='store_true',
     259                   default = False,
     260                   help = "Build PDF.")
     261    ctx.add_option('--singlehtml',
     262                   action='store_true',
     263                   default = False,
     264                   help = "Build Single HTML file, requires Node Inliner")
    225265
    226266def cmd_options_path(ctx):
    227         cmd_options(ctx)
    228         ctx.add_option('--rtems-path-py', type='string', help="Full path to py/ in RTEMS source repository.")
    229 
     267    cmd_options(ctx)
     268    ctx.add_option('--rtems-path-py',
     269                   type = 'string',
     270                   help = "Full path to py/ in RTEMS source repository.")
    230271
    231272def cmd_configure_path(ctx):
    232         if not ctx.options.rtems_path_py:
    233                 ctx.fatal("--rtems-path-py is required")
    234 
    235         ctx.env.RTEMS_PATH = ctx.options.rtems_path_py
    236 
    237         cmd_configure(ctx)
     273    if not ctx.options.rtems_path_py:
     274        ctx.fatal("--rtems-path-py is required")
     275
     276    ctx.env.RTEMS_PATH = ctx.options.rtems_path_py
     277
     278    cmd_configure(ctx)
    238279
    239280
     
    245286"""
    246287
    247 
    248288# XXX: fix this ugly hack.  No time to waste on it.
    249289def cmd_build_path(ctx):
    250         def run(task):
    251 
    252                 with open("conf.py") as fp:
    253                         conf = "import sys, os\nsys.path.append(os.path.abspath('../../common/'))\n"
    254                         conf += fp.read()
    255 
    256                 task.inputs[0].abspath()
    257                 task.outputs[0].write(conf + (CONF_FRAG % ctx.env.RTEMS_PATH))
    258 
    259         ctx(
    260                 rule   = run,
    261                 source = [ctx.path.parent.find_node("common/conf.py"), ctx.path.find_node("./conf.py")],
    262                 target = ctx.path.get_bld().make_node('conf.py')
    263     )
    264 
    265         cmd_build(ctx, conf_dir="build", source_dir="build")
     290    def run(task):
     291
     292        with open("conf.py") as fp:
     293            conf = "import sys, os\nsys.path.append(os.path.abspath('../../common/'))\n"
     294            conf += fp.read()
     295
     296        task.inputs[0].abspath()
     297        task.outputs[0].write(conf + (CONF_FRAG % ctx.env.RTEMS_PATH))
     298
     299    ctx(
     300        rule   = run,
     301        source = [ctx.path.parent.find_node("common/conf.py"),
     302                  ctx.path.find_node("./conf.py")],
     303        target = ctx.path.get_bld().make_node('conf.py')
     304    )
     305
     306    cmd_build(ctx, conf_dir = "build", source_dir = "build")
Note: See TracChangeset for help on using the changeset viewer.