diff options
Diffstat (limited to 'doc/SConscript')
-rw-r--r-- | doc/SConscript | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/doc/SConscript b/doc/SConscript new file mode 100644 index 0000000..fd18ef4 --- /dev/null +++ b/doc/SConscript @@ -0,0 +1,530 @@ +# +# SConscript file for building SCons documentation. +# + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +import os.path +import re +import string + +Import('build_dir', 'env', 'whereis') + +env = env.Clone() + +build = os.path.join(build_dir, 'doc') + +# +# +# +dist_doc_tar_gz = '$DISTDIR/scons-doc-${VERSION}.tar.gz' + +# +# We'll only try to build text files (for some documents) +# if lynx is available to do the dump. +# +fig2dev = whereis('fig2dev') +epydoc = whereis('epydoc') +groff = whereis('groff') +lynx = whereis('lynx') +man2html = whereis('man2html') +jade_original = whereis('jade') +jade = whereis('openjade') or jade_original +jadetex = whereis('jadetex') +pdfjadetex = whereis('pdfjadetex') +jw = whereis('jw') +tidy = whereis('tidy') + +tar_deps = [] +tar_list = [] + +entity_re = re.compile(r'<!entity\s+(?:%\s+)?(?:\S+)\s+SYSTEM\s+"([^"]*)">', re.I) +format_re = re.compile(r'<(?:graphic|imagedata)\s+fileref="([^"]*)"(?:\s+format="([^"]*)")?') + +# +# Find internal dependencies in .xml files: +# +# <!entity bground SYSTEM "bground.xml"> +# <graphic fileref="file.jpg"> +# <imagedata fileref="file.jpg"> +# +# This only finds one per line, and assumes that anything +# defined as a SYSTEM entity is, in fact, a file included +# somewhere in the document. +# +def scanxml(node, env, target): + includes = [] + + contents = node.get_text_contents() + + includes.extend(entity_re.findall(contents)) + + matches = format_re.findall(contents) + for m in matches: + file, format = m + if format and file[-len(format):] != format: + file = file + '.' + format + if not os.path.isabs(file): + a = [] + f = file + while f: + f, tail = os.path.split(f) + if tail == 'doc': + break + a = [tail] + a + file = apply(os.path.join, a, {}) + includes.append(file) + + return includes + +s = Scanner(name = 'xml', function = scanxml, skeys = ['.xml', '.mod']) + +orig_env = env +env = orig_env.Clone(SCANNERS = [s], + SCONS_PROC_PY = File('#bin/scons-proc.py').rfile(), + SCONSOUTPUT_PY = File('#bin/sconsoutput.py').rfile()) + +# Fetch the list of files in the build engine that contain +# SCons documentation XML for processing. +def chop(s): return s[:-1] + +# If we ever read doc from __scons_doc__ strings in *.py files again, +# here's how it's done: +#manifest_in = File('#src/engine/MANIFEST.in').rstr() +#manifest_xml_in = File('#src/engine/MANIFEST-xml.in').rstr() +#scons_doc_files = map(chop, open(manifest_in).readlines() +\ +# open(manifest_xml_in).readlines()) +#scons_doc_files = map(lambda x: '#src/engine/'+x, scons_doc_files) +#manifest_in = File('#src/engine/MANIFEST.in').rstr() + +manifest_xml_in = File('#src/engine/MANIFEST-xml.in').rstr() +scons_doc_files = map(chop, open(manifest_xml_in).readlines()) +scons_doc_files = map(lambda x: File('#src/engine/'+x).rstr(), scons_doc_files) + +if not jw: + print "jw not found, skipping building User Guide." +else: + # + # Always create a version.xml file containing the version information + # for this run. Ignore it for dependency purposes so we don't + # rebuild all the docs every time just because the date changes. + # + date, ver, rev = env.Dictionary('DATE', 'VERSION', 'REVISION') + version_xml = File(os.path.join(build, "version.xml")) + #version_xml = File("version.xml") + verfile = str(version_xml) + try: + os.unlink(verfile) + except OSError: + pass # okay if the file didn't exist + dir, f = os.path.split(verfile) + try: + os.makedirs(dir) + except OSError: + pass # okay if the directory already exists + open(verfile, "w").write("""<!-- +THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT. +--> +<!ENTITY builddate "%s"> +<!ENTITY buildversion "%s"> +<!ENTITY buildrevision "%s"> +""" % (date, ver, rev)) + + builders_gen = os.path.join(build, 'user', 'builders.gen') + builders_mod = os.path.join(build, 'user', 'builders.mod') + tools_gen = os.path.join(build, 'user', 'tools.gen') + tools_mod = os.path.join(build, 'user', 'tools.mod') + variables_gen = os.path.join(build, 'user', 'variables.gen') + variables_mod = os.path.join(build, 'user', 'variables.mod') + + # We put $( - $) around $SOURCES in the command line below because + # the path names will change when a given input file is found in + # a repository one run and locally the next, and we don't want + # to rebuild documentation just because it's found in one location + # vs. the other. The *.gen and *.mod targets will still be dependent + # on the list of the files themselves. + doc_output_files = [builders_gen, builders_mod, + tools_gen, tools_mod, + variables_gen, variables_mod] + b = env.Command(doc_output_files, + scons_doc_files, + "$PYTHON $SCONS_PROC_PY --xml -b ${TARGETS[0]},${TARGETS[1]} -t ${TARGETS[2]},${TARGETS[3]} -v ${TARGETS[4]},${TARGETS[5]} $( $SOURCES $)") + env.Depends(b, "$SCONS_PROC_PY") + + env.Local(b) + + # + # Each document will live in its own subdirectory. List them here + # as hash keys, with a hash of the info to control its build. + # + docs = { + 'design' : { + 'htmlindex' : 'book1.html', + 'ps' : 1, + 'pdf' : 1, + 'text' : 0, + }, + # This doesn't build on all systems, and the document is old + # enough that there's reallyno need to build it every time any + # more, so just comment it out for now. + #'python10' : { + # 'htmlindex' : 't1.html', + # 'html' : 1, + # 'ps' : 1, + # 'pdf' : 0, + # 'text' : 0, + # 'graphics' : [ + # 'arch.fig', + # 'builder.fig', + # 'job-task.fig', + # 'node.fig', + # 'scanner.fig', + # 'sig.fig' + # ], + #}, + 'reference' : { + 'htmlindex' : 'book1.html', + 'html' : 1, + 'ps' : 1, + 'pdf' : 1, + 'text' : 0, + }, + # For whenever (if ever?) we start putting developer guide + # information in a printable document instead of the wiki. + #'developer' : { + # 'htmlindex' : 'book1.html', + # 'html' : 1, + # 'ps' : 1, + # 'pdf' : 1, + # 'text' : 0, + #}, + 'user' : { + 'htmlindex' : 'book1.html', + 'html' : 1, + 'ps' : 1, + 'pdf' : 1, + 'text' : 1, + 'graphics' : [ + 'SCons-win32-install-1.jpg', + 'SCons-win32-install-2.jpg', + 'SCons-win32-install-3.jpg', + 'SCons-win32-install-4.jpg', + ], + 'sconsoutput' : 1, + }, + } + + # + # We have to tell SCons to scan the top-level XML files which + # get included by the document XML files in the subdirectories. + # + manifest = File('MANIFEST').rstr() + src_files = map(lambda x: x[:-1], open(manifest).readlines()) + for s in src_files: + base, ext = os.path.splitext(s) + if ext in ['.fig', '.jpg']: + orig_env.Install(build, s) + else: + orig_env.SCons_revision(os.path.join(build, s), s) + Local(os.path.join(build, s)) + + # + # For each document, build the document itself in HTML, Postscript, + # and PDF formats. + # + for doc in docs.keys(): + manifest = File(os.path.join(doc, 'MANIFEST')).rstr() + src_files = map(lambda x: x[:-1], + open(manifest).readlines()) + build_doc = docs[doc].get('sconsoutput') and int(ARGUMENTS.get('BUILDDOC', 0)) + for s in src_files: + doc_s = os.path.join(doc, s) + build_s = os.path.join(build, doc, s) + base, ext = os.path.splitext(doc_s) + if ext in ['.fig', '.jpg']: + orig_env.InstallAs(build_s, doc_s) + else: + if build_doc and ext == '.xml': + env.Command(doc_s, + base + '.in', + "$PYTHON $SCONSOUTPUT_PY $SOURCE > $TARGET") + orig_env.SCons_revision(build_s, doc_s) + Local(build_s) + + main = os.path.join(build, doc, 'main.xml') + out = 'main.out' + + # Hard-coding the scons-src path is a bit of a hack. This can + # be reworked when a better solution presents itself. + scons_src_main = os.path.join(build_dir, 'scons-src', 'doc', main) + env.Ignore(scons_src_main, version_xml) + + htmldir = os.path.join(build, 'HTML', 'scons-%s' % doc) + htmlindex = os.path.join(htmldir, docs[doc]['htmlindex']) + html = os.path.join(build, 'HTML', 'scons-%s.html' % doc) + ps = os.path.join(build, 'PS', 'scons-%s.ps' % doc) + pdf = os.path.join(build, 'PDF', 'scons-%s.pdf' % doc) + text = os.path.join(build, 'TEXT', 'scons-%s.txt' % doc) + + if docs[doc].get('html') and jade: + def copy_index_html(target, source, env): + # Older versions of DocBook|jw|jade|whatever would + # create a book1.html file, while newer versions create + # an index.html file (logically enough). The scons.org + # web site links expect book1.html, so we're going to + # leave the target as is, and run this post-processing + # action function to check that the target really did + # get created, and if it didn't, copy it from index.html. + t = str(target[0]) + if not os.path.exists(t): + i = os.path.join(os.path.split(t)[0], 'index.html') + open(t, 'w').write(open(i, 'r').read()) + return None + + cmds = [ + Delete("${TARGET.dir}/*.html"), + "jw -b html -o ${TARGET.dir} $SOURCES", + ] + if tidy: + cmds.append("tidy -m -q $TARGET || true") + cmds.append(Action(copy_index_html)) + env.Command(htmlindex, File(main), cmds) + Local(htmlindex) + + cmds = [ + Delete("${TARGET.dir}/main.html"), + "jw -u -b html -o ${TARGET.dir} $SOURCES", + Move("$TARGET", "${TARGET.dir}/main.html"), + ] + if tidy: + cmds.append("tidy -m -q $TARGET || true") + env.Command(html, File(main), cmds) + Local(html) + + env.Ignore([html, htmlindex], version_xml) + + tar_deps.extend([html, htmlindex]) + tar_list.extend([html, htmldir]) + + for g in docs[doc].get('graphics', []): + base, ext = os.path.splitext(g) + if ext == '.fig': + jpg = base + '.jpg' + htmldir_jpg = os.path.join(htmldir, jpg) + if fig2dev: + fig = os.path.join(build, doc, g) + env.Command(htmldir_jpg, fig, + "%s -L jpeg -q 100 $SOURCES $TARGET" % fig2dev) + else: + env.InstallAs(htmldir_jpg, jpg) + env.Depends(html, htmldir_jpg) + Local(htmldir_jpg) + else: + src = os.path.join(build, doc, g) + Local(env.Install(htmldir, src)) + + if docs[doc].get('ps') and jadetex and jade_original: + env.Command(ps, main, [ + Delete("${TARGET.dir}/%s" % out), + "jw -b ps -o ${TARGET.dir} -p %s $SOURCES" % jade_original, + "mv ${TARGET.dir}/main.ps $TARGET", + Delete("${TARGET.dir}/%s" % out), + ]) + Local(ps) + + env.Ignore(ps, version_xml) + + tar_deps.append(ps) + tar_list.append(ps) + + for g in docs[doc].get('graphics', []): + base, ext = os.path.splitext(g) + if ext == '.fig': + eps = base + '.eps' + build_eps = os.path.join(build, 'PS', eps) + if fig2dev: + fig = os.path.join(build, doc, g) + env.Command(build_eps, fig, "%s -L eps $SOURCES $TARGET" % fig2dev) + else: + env.InstallAs(build_eps, eps) + env.Depends(ps, build_eps) + Local(build_eps) + else: + src = os.path.join(build, doc, g) + Local(env.Install(htmldir, src)) + + if docs[doc].get('pdf') and pdfjadetex and jade_original: + env.Command(pdf, main, [ + Delete("${TARGET.dir}/%s" % out), + "jw -b pdf -o ${TARGET.dir} -p %s $SOURCES" % jade_original, + "mv ${TARGET.dir}/main.pdf $TARGET", + Delete("${TARGET.dir}/out"), + ]) + Local(pdf) + + env.Ignore(pdf, version_xml) + + tar_deps.append(pdf) + tar_list.append(pdf) + + if docs[doc].get('text') and jade and lynx: + env.Command(text, html, "lynx -dump ${SOURCE.abspath} > $TARGET") + Local(text) + + env.Ignore(text, version_xml) + + tar_deps.append(text) + tar_list.append(text) + +# +# Man page(s), in good ol' troff format. +# +man_page_list = ['scons.1', 'sconsign.1', 'scons-time.1'] + +for m in man_page_list: + x = orig_env.SCons_revision(os.path.join(build, 'man', m), + os.path.join('man', m)) + +man_i_files = ['builders.man', 'tools.man', 'variables.man'] + +man_intermediate_files = map(lambda x: os.path.join(build, 'man', x), + man_i_files) + +cmd = "$PYTHON $SCONS_PROC_PY --man -b ${TARGETS[0]} -t ${TARGETS[1]} -v ${TARGETS[2]} $( $SOURCES $)" +man_intermediate_files = env.Command(man_intermediate_files, + scons_doc_files, + cmd) +env.Depends(man_intermediate_files, "$SCONS_PROC_PY") +Local(man_intermediate_files) + +for man_1 in man_page_list: + man, _1 = os.path.splitext(man_1) + + man_1 = os.path.join(build, 'man', man_1) + + if groff: + ps = os.path.join(build, 'PS', '%s-man.ps' % man) + text = os.path.join(build, 'TEXT', '%s-man.txt' % man) + + b = env.Command(ps, man_1, "( cd ${SOURCES.dir} && groff -man -Tps ${SOURCES.file} ) > $TARGET") + Local(ps) + env.Depends(b, man_intermediate_files) + + b = env.Command(text, man_1, "( cd ${SOURCES.dir} && groff -man -Tascii ${SOURCES.file} ) > $TARGET") + Local(text) + env.Depends(b, man_intermediate_files) + + tar_deps.extend([ps, text]) + tar_list.extend([ps, text]) + + if man2html: + html = os.path.join(build, 'HTML' , '%s-man.html' % man) + + def strip_to_first_html_tag(target, source, env): + t = str(target[0]) + contents = open(t).read() + contents = contents[string.find(contents, '<HTML>'):] + open(t, 'w').write(contents) + return 0 + + cmds = [ + "( cd %s/man && cp %s .. )" % (build, string.join(man_i_files)), + "( cd ${SOURCE.dir} && man2html ${SOURCE.file} ) > $TARGET", + Action(strip_to_first_html_tag), + ] + if tidy: + cmds.append("tidy -m -q $TARGET || true") + b = env.Command(html, man_1, cmds) + Local(html) + env.Depends(b, man_intermediate_files) + + tar_deps.append(html) + tar_list.append(html) + +if not epydoc: + print "epydoc not found, skipping building API documentation." +else: + # XXX Should be in common with reading the same thing in + # the SConstruct file. + e = os.path.join('#src', 'engine') + manifest_in = File(os.path.join(e, 'MANIFEST.in')).rstr() + sources = map(lambda x: x[:-1], open(manifest_in).readlines()) + sources = filter(lambda x: string.find(x, 'Optik') == -1, sources) + sources = filter(lambda x: string.find(x, 'Platform') == -1, sources) + sources = filter(lambda x: string.find(x, 'Tool') == -1, sources) + # XXX + sources = filter(lambda x: string.find(x, 'Options') == -1, sources) + + e = os.path.join(build, '..', 'scons', 'engine') + sources = map(lambda x, e=e: os.path.join(e, x), sources) + + epydoc_commands = [ + Delete('$OUTDIR'), + '$EPYDOC $EPYDOCFLAGS --debug --output $OUTDIR --docformat=restructuredText --name SCons --url http://www.scons.org/ $SOURCES', + Touch('$TARGET'), + ] + + htmldir = os.path.join(build, 'HTML', 'scons-api') + env.Command('${OUTDIR}/index.html', sources, epydoc_commands, + EPYDOC=epydoc, EPYDOCFLAGS='--html', OUTDIR=htmldir) + tar_deps.append(htmldir) + tar_list.append(htmldir) + + # PDF and PostScript and TeX are built from the + # same invocation. + api_dir = os.path.join(build, 'scons-api') + api_pdf = os.path.join(api_dir, 'api.pdf') + api_ps = os.path.join(api_dir, 'api.ps') + api_tex = os.path.join(api_dir, 'api.tex') + api_targets = [api_pdf, api_ps, api_tex] + env.Command(api_targets, sources, epydoc_commands, + EPYDOC=epydoc, EPYDOCFLAGS='--pdf', OUTDIR=api_dir) + Local(api_targets) + + pdf_install = os.path.join(build, 'PDF', 'scons-api.pdf') + env.InstallAs(pdf_install, api_pdf) + tar_deps.append(pdf_install) + tar_list.append(pdf_install) + Local(pdf_install) + + ps_install = os.path.join(build, 'PS', 'scons-api.ps') + env.InstallAs(ps_install, api_ps) + tar_deps.append(ps_install) + tar_list.append(ps_install) + Local(ps_install) + +# +# Now actually create the tar file of the documentation, +# for easy distribution to the web site. +# +if tar_deps: + tar_list = string.join(map(lambda x, b=build+'/': string.replace(x, b, ''), + tar_list)) + t = env.Command(dist_doc_tar_gz, tar_deps, + "tar cf${TAR_HFLAG} - -C %s %s | gzip > $TARGET" % (build, tar_list)) + AddPostAction(dist_doc_tar_gz, Chmod(dist_doc_tar_gz, 0644)) + Local(t) + Alias('doc', t) +else: + Alias('doc', os.path.join(build_dir, 'doc')) |