mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-02-04 16:16:00 +01:00
546 lines
20 KiB
Python
546 lines
20 KiB
Python
#
|
|
# SConscript file for building SCons documentation.
|
|
#
|
|
|
|
# MIT License
|
|
#
|
|
# Copyright 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 sys
|
|
import glob
|
|
|
|
import bootstrap
|
|
|
|
Import('command_line', 'env', 'whereis', 'revaction')
|
|
|
|
#
|
|
# -- Check prerequisites for building the documentation ---
|
|
#
|
|
skip_doc = False
|
|
|
|
try:
|
|
import SConsDoc
|
|
import SConsExamples
|
|
except ImportError as exc:
|
|
print("doc: SConsDoc failed to import, the error was:")
|
|
print(" ImportError: %s" % exc)
|
|
print(" Please make sure that python-lxml is installed.")
|
|
skip_doc = True
|
|
|
|
fop = whereis('fop')
|
|
xep = whereis('xep')
|
|
|
|
if not fop and not xep:
|
|
print("doc: No PDF renderer found (fop|xep)!")
|
|
skip_doc = True
|
|
|
|
skip_doc_arg = ARGUMENTS.get('SKIP_DOC')
|
|
if skip_doc_arg is not None:
|
|
skip_doc = skip_doc_arg in ['True', '1', 'true']
|
|
|
|
#
|
|
# --- Configure build
|
|
#
|
|
env = env.Clone()
|
|
|
|
build = os.path.join(command_line.build_dir, 'doc')
|
|
|
|
gs = whereis('gs')
|
|
lynx = whereis('lynx')
|
|
|
|
dist_doc_tar_gz = '$DISTDIR/scons-doc-${VERSION}.tar.gz'
|
|
|
|
tar_deps = []
|
|
tar_list = []
|
|
|
|
orig_env = env
|
|
env = orig_env.Clone(SCONS_PY=File('#/scripts/scons.py').rfile())
|
|
|
|
|
|
#
|
|
# --- Helpers ---
|
|
#
|
|
def writeVersionXml(verfile, date, ver, rev, copyright_years):
|
|
""" Helper function: Write a version.xml file. """
|
|
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
|
|
with open(verfile, "w") as vf:
|
|
vf.write("""<!--
|
|
THIS IS AN AUTOMATICALLY-GENERATED FILE. DO NOT EDIT.
|
|
-->
|
|
<!ENTITY builddate "%s">
|
|
<!ENTITY buildversion "%s">
|
|
<!ENTITY buildrevision "%s">
|
|
<!ENTITY copyright_years "%s">
|
|
""" % (date, ver, rev, copyright_years))
|
|
|
|
|
|
# The names of the target files for the MAN pages
|
|
man_page_list = ['scons.1', 'scons-time.1', 'sconsign.1']
|
|
|
|
# Template for the MAN page texts when we can't properly
|
|
# create them because the skip_doc flag is set (required
|
|
# modules/tools aren't installed in the current system)
|
|
man_replace_tpl = r""".TH "%(uctitle)s" "1" "%(today)s" "SCons %(version)s" "SCons %(version)s"
|
|
.ie \n(.g .ds Aq \(aq
|
|
.el .ds Aq '
|
|
.nh
|
|
.ad l
|
|
.SH "NOTE"
|
|
%(title)s \- This is a replacement file, stemming from an incomplete
|
|
packaging process without the required doc modules installed. Please
|
|
update the system and try running bootstrap.py again.
|
|
"""
|
|
|
|
#
|
|
# --- Processing ---
|
|
#
|
|
|
|
if skip_doc:
|
|
print("doc: ...skipping building User Guide.")
|
|
print(" ...creating fake MAN pages.")
|
|
|
|
# Since the top-level SConstruct requires the MAN
|
|
# pages to exist for the basic packaging, we create simple
|
|
# stub texts here as replacement...
|
|
scdir = os.path.join(build, 'man')
|
|
if not os.path.isdir(scdir):
|
|
os.makedirs(scdir)
|
|
|
|
import time
|
|
|
|
today = time.strftime("%Y-%m-%d",
|
|
time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
|
|
version = env.subst('$VERSION')
|
|
for m in man_page_list:
|
|
man, _ = os.path.splitext(m)
|
|
fman = open(os.path.join(scdir, m), "w")
|
|
fman.write(man_replace_tpl % {'uctitle': man.upper().replace("-", "\\-"),
|
|
'today': today,
|
|
'title': man,
|
|
'version': version})
|
|
fman.close()
|
|
else:
|
|
if not lynx:
|
|
print("doc: Warning, lynx is not installed...created release packages won't be complete!")
|
|
|
|
#
|
|
# 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, copyright_years = env.Dictionary('DATE', 'VERSION', 'REVISION', 'COPYRIGHT_YEARS')
|
|
version_xml = File(os.path.join(build, "version.xml"))
|
|
writeVersionXml(str(version_xml), date, ver, rev, copyright_years)
|
|
|
|
import shutil
|
|
import SCons.Builder
|
|
import SCons.Util
|
|
|
|
|
|
#
|
|
# Builder for copying files to an Install dir, based
|
|
# on their extension (better: glob matching pattern)...
|
|
#
|
|
def _glob_install_action(target, source, env):
|
|
if not SCons.Util.is_List(target):
|
|
target = [target]
|
|
if not SCons.Util.is_List(source):
|
|
source = [source]
|
|
for t, s in zip(target, source):
|
|
shutil.copy(str(s), str(t))
|
|
|
|
|
|
def _glob_install_emitter(target, source, env):
|
|
if not SCons.Util.is_List(target):
|
|
target = [target]
|
|
if not SCons.Util.is_List(source):
|
|
source = [source]
|
|
|
|
res = []
|
|
res_src = []
|
|
tdir = env.Dir(target[0])
|
|
for g in glob.glob(str(source[0])):
|
|
head, tail = os.path.split(g)
|
|
res.append(os.path.join(str(tdir), tail))
|
|
res_src.append(g)
|
|
return res, res_src
|
|
|
|
|
|
_glob_install_builder = SCons.Builder.Builder(action=_glob_install_action,
|
|
emitter=_glob_install_emitter)
|
|
env['BUILDERS']['GlobInstall'] = _glob_install_builder
|
|
|
|
|
|
#
|
|
# Builder for copying ChunkedHTML files to an Install dir...
|
|
#
|
|
def _chunked_install_action(target, source, env):
|
|
if not SCons.Util.is_List(target):
|
|
target = [target]
|
|
if not SCons.Util.is_List(source):
|
|
source = [source]
|
|
tdir, tail = os.path.split(str(target[0]))
|
|
spattern = os.path.join(os.path.split(str(source[0]))[0], '*.html')
|
|
for g in glob.glob(spattern):
|
|
shutil.copy(g, tdir)
|
|
|
|
|
|
def _chunked_install_emitter(target, source, env):
|
|
if not SCons.Util.is_List(target):
|
|
target = [target]
|
|
if not SCons.Util.is_List(source):
|
|
source = [source]
|
|
|
|
tdir = env.Dir(target[0])
|
|
head, tail = os.path.split(str(source[0]))
|
|
return os.path.join(str(tdir), tail), source
|
|
|
|
|
|
_chunked_install_builder = SCons.Builder.Builder(action=_chunked_install_action,
|
|
emitter=_chunked_install_emitter)
|
|
env['BUILDERS']['ChunkedInstall'] = _chunked_install_builder
|
|
|
|
if not env.GetOption('clean'):
|
|
#
|
|
# Ensure that all XML files are valid against our XSD, and
|
|
# that all example names and example output suffixes are unique
|
|
#
|
|
print("Validating files against SCons XSD...")
|
|
if SConsDoc.validate_all_xml(['SCons'], xsdfile='xsd/scons.xsd'):
|
|
print("OK")
|
|
else:
|
|
print("Validation failed! Please correct the errors above and try again.")
|
|
sys.exit(1)
|
|
|
|
print("Checking whether all example names are unique...")
|
|
if SConsExamples.exampleNamesAreUnique(os.path.join('doc', 'user')):
|
|
print("OK")
|
|
else:
|
|
print(
|
|
"Not all example names and suffixes are unique! Please correct the errors listed above and try again.")
|
|
sys.exit(1)
|
|
|
|
# List of prerequisite files in the build/doc folder
|
|
buildsuite = []
|
|
|
|
|
|
def copy_dbfiles(env, toolpath, paths, fpattern, use_builddir=True):
|
|
""" Helper function, copies a bunch of files matching
|
|
the given fpattern to a target directory.
|
|
"""
|
|
global buildsuite
|
|
if not SCons.Util.is_List(toolpath):
|
|
toolpath = [toolpath]
|
|
if not SCons.Util.is_List(paths):
|
|
paths = [paths]
|
|
if not SCons.Util.is_List(fpattern):
|
|
fpattern = [fpattern]
|
|
|
|
if use_builddir:
|
|
target_dir = env.Dir(os.path.join(command_line.build_dir, *(toolpath + paths)))
|
|
buildsuite.extend(env.GlobInstall(target_dir,
|
|
os.path.join('..', *(toolpath + paths + fpattern))))
|
|
else:
|
|
target_dir = env.Dir(os.path.join(*(toolpath + paths)))
|
|
buildsuite.extend(env.GlobInstall(target_dir,
|
|
os.path.join(*(paths + fpattern))))
|
|
|
|
|
|
#
|
|
# Copy generated files (.gen/.mod/.xml) to the build folder
|
|
#
|
|
copy_dbfiles(env, build, 'generated', '*.gen', False)
|
|
copy_dbfiles(env, build, 'generated', '*.mod', False)
|
|
copy_dbfiles(env, build, ['generated', 'examples'], '*', False)
|
|
|
|
#
|
|
# Copy XSLT files (.xslt) to the build folder
|
|
#
|
|
copy_dbfiles(env, build, 'xslt', '*.*', False)
|
|
|
|
#
|
|
# Copy DocBook stylesheets and Tool to the build folder
|
|
#
|
|
dbtoolpath = ['SCons', 'Tool', 'docbook']
|
|
copy_dbfiles(env, dbtoolpath, [], '__init__.py')
|
|
copy_dbfiles(env, dbtoolpath, 'utils', 'xmldepend.xsl')
|
|
dbpath = dbtoolpath + ['docbook-xsl-1.76.1']
|
|
copy_dbfiles(env, dbpath, [], 'VERSION')
|
|
copy_dbfiles(env, dbpath, ['common'], '*.*')
|
|
copy_dbfiles(env, dbpath, ['lib'], '*.*')
|
|
copy_dbfiles(env, dbpath, ['html'], '*.*')
|
|
copy_dbfiles(env, dbpath, ['fo'], '*.*')
|
|
copy_dbfiles(env, dbpath, ['manpages'], '*.*')
|
|
copy_dbfiles(env, dbpath, ['epub'], '*.xsl')
|
|
copy_dbfiles(env, dbpath, ['xhtml-1_1'], '*.*')
|
|
|
|
#
|
|
# Copy additional Tools (gs, zip)
|
|
#
|
|
toolpath = ['SCons', 'Tool']
|
|
copy_dbfiles(env, toolpath, [], 'gs.py')
|
|
copy_dbfiles(env, toolpath, [], 'zip.py')
|
|
|
|
#
|
|
# Each document will live in its own subdirectory "build/doc/xxx".
|
|
# List them here by their subfolder names. Note, how the specifiers
|
|
# for each subdir (=DOCTARGETS) have nothing to do with which
|
|
# formats get created...but which of the outputs get installed
|
|
# to the build folder and added to the different source and binary
|
|
# packages in the end.
|
|
# In addition to the list of target formats (DOCTARGETS), we also
|
|
# store some dependency information in this dict. The DOCDEPENDS
|
|
# list contains all files from each local "MANIFEST", after
|
|
# installing/copying them to the build directory. It basically
|
|
# links the original sources to the respective build folder,
|
|
# such that a simple 'python bootstrap.py' rebuilds the
|
|
# documentation when a file, like 'doc/user/depends.xml'
|
|
# for example, changes.
|
|
# Finally, in DOCNODES we store the created PDF and HTML files,
|
|
# such that we can then install them in the proper places for
|
|
# getting picked up by the archiving/packaging stages.
|
|
DOCTARGETS = 0
|
|
DOCDEPENDS = 1
|
|
DOCNODES = 2
|
|
docs = {'design': (['chunked', 'pdf'], [], []),
|
|
# 'python10' : (['chunked','html','pdf'], [], []),
|
|
'reference': (['chunked', 'html', 'pdf'], [], []),
|
|
# 'developer' : (['chunked','html','pdf'], [], []),
|
|
'user': (['chunked', 'html', 'pdf', 'epub', 'text'], [], []),
|
|
'man': (['man', 'epub', 'text'], [], [])
|
|
}
|
|
|
|
#
|
|
# 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 = bootstrap.parseManifestLines('.', manifest)
|
|
for s in src_files:
|
|
if not s:
|
|
continue
|
|
base, ext = os.path.splitext(s)
|
|
if ext in ['.fig', '.jpg']:
|
|
buildsuite.extend(env.Command(os.path.join(build, s),
|
|
s,
|
|
Copy("$TARGET", "$SOURCE")))
|
|
else:
|
|
revaction([env.File(os.path.join(build, s))],
|
|
[env.File(s)], env)
|
|
|
|
for doc in docs:
|
|
|
|
#
|
|
# Read MANIFEST file and copy the listed files to the
|
|
# build directory, while branding them with the
|
|
# SCons copyright and the current revision number...
|
|
#
|
|
if not os.path.exists(os.path.join(build, doc)):
|
|
env.Execute(Mkdir(os.path.join(build, doc)))
|
|
if not os.path.exists(os.path.join(build, doc, 'titlepage')):
|
|
env.Execute(Mkdir(os.path.join(build, doc, 'titlepage')))
|
|
manifest = File(os.path.join(doc, 'MANIFEST')).rstr()
|
|
src_files = bootstrap.parseManifestLines(doc, manifest)
|
|
for s in src_files:
|
|
if not s:
|
|
continue
|
|
doc_s = os.path.join(doc, s)
|
|
build_s = os.path.join(build, doc, s)
|
|
base, ext = os.path.splitext(doc_s)
|
|
head, tail = os.path.split(s)
|
|
if head:
|
|
target_dir = os.path.join(build, doc, head)
|
|
else:
|
|
target_dir = os.path.join(build, doc)
|
|
if ext in ['.fig', '.jpg', '.svg']:
|
|
docs[doc][DOCDEPENDS].extend(env.Command(build_s, doc_s,
|
|
Copy("$TARGET", "$SOURCE")))
|
|
else:
|
|
btarget = env.File(build_s)
|
|
docs[doc][DOCDEPENDS].append(btarget)
|
|
revaction([btarget], [env.File(doc_s)], env)
|
|
|
|
#
|
|
# For each document, build the document itself in HTML,
|
|
# and PDF formats.
|
|
#
|
|
for doc in docs:
|
|
|
|
#
|
|
# Call SCons in each local doc folder
|
|
#
|
|
cleanopt = ''
|
|
if env.GetOption('clean'):
|
|
cleanopt = ' -c'
|
|
scdir = os.path.join(build, doc)
|
|
sctargets = []
|
|
if 'html' in docs[doc][DOCTARGETS]:
|
|
sctargets.append(env.File(os.path.join(scdir, 'index.html')))
|
|
if 'chunked' in docs[doc][DOCTARGETS]:
|
|
sctargets.append(env.File(os.path.join(scdir, 'scons-%s' % doc, 'index.html')))
|
|
if 'pdf' in docs[doc][DOCTARGETS]:
|
|
sctargets.append(env.File(os.path.join(scdir, 'scons-%s.pdf' % doc)))
|
|
if 'epub' in docs[doc][DOCTARGETS]:
|
|
sctargets.append(env.File(os.path.join(scdir, 'scons-%s.epub' % doc)))
|
|
|
|
if 'man' in docs[doc][DOCTARGETS]:
|
|
for m in man_page_list:
|
|
sctargets.append(os.path.join(scdir, m))
|
|
man, _1 = os.path.splitext(m)
|
|
|
|
sctargets.append(os.path.join(scdir, 'scons-%s.pdf' % man))
|
|
sctargets.append(os.path.join(scdir, 'scons-%s.html' % man))
|
|
|
|
docs[doc][DOCNODES].extend(env.Command(sctargets, buildsuite + docs[doc][DOCDEPENDS],
|
|
"cd %s && $PYTHON ${SCONS_PY.abspath}%s" % (scdir, cleanopt)))
|
|
|
|
install_css = False
|
|
for doc in docs:
|
|
|
|
# Collect the output files for this subfolder
|
|
htmldir = os.path.join(build, 'HTML', 'scons-%s' % doc)
|
|
htmlindex = os.path.join(htmldir, 'index.html')
|
|
html = os.path.join(build, 'HTML', 'scons-%s.html' % doc)
|
|
pdf = os.path.join(build, 'PDF', 'scons-%s.pdf' % doc)
|
|
epub = os.path.join(build, 'EPUB', 'scons-%s.epub' % doc)
|
|
text = os.path.join(build, 'TEXT', 'scons-%s.txt' % doc)
|
|
if 'chunked' in docs[doc][DOCTARGETS]:
|
|
installed_chtml = env.ChunkedInstall(env.Dir(htmldir),
|
|
os.path.join(build, doc, 'scons-%s' % doc, 'index.html'))
|
|
installed_chtml_css = env.Install(env.Dir(htmldir),
|
|
os.path.join(build, doc, 'scons.css'))
|
|
env.Depends(installed_chtml, docs[doc][DOCNODES])
|
|
env.Depends(installed_chtml_css, docs[doc][DOCNODES])
|
|
|
|
tar_deps.extend([htmlindex, installed_chtml_css])
|
|
tar_list.extend([htmldir])
|
|
Local(htmlindex)
|
|
env.Ignore(htmlindex, version_xml)
|
|
|
|
if 'html' in docs[doc][DOCTARGETS]:
|
|
env.InstallAs(env.File(html), env.File(os.path.join(build, doc, 'index.html')))
|
|
tar_deps.extend([html])
|
|
tar_list.extend([html])
|
|
Local(html)
|
|
env.Ignore(html, version_xml)
|
|
install_css = True
|
|
|
|
if 'pdf' in docs[doc][DOCTARGETS]:
|
|
env.InstallAs(env.File(pdf), env.File(os.path.join(build, doc, 'scons-%s.pdf' % doc)))
|
|
Local(pdf)
|
|
env.Ignore(pdf, version_xml)
|
|
|
|
tar_deps.append(pdf)
|
|
tar_list.append(pdf)
|
|
|
|
if 'epub' in docs[doc][DOCTARGETS] and gs:
|
|
env.InstallAs(env.File(epub), env.File(os.path.join(build, doc, 'scons-%s.epub' % doc)))
|
|
Local(epub)
|
|
env.Ignore(epub, version_xml)
|
|
|
|
tar_deps.append(epub)
|
|
tar_list.append(epub)
|
|
|
|
if ('text' in docs[doc][DOCTARGETS] and lynx and
|
|
(('html' in docs[doc][DOCTARGETS]) or (doc == 'man'))):
|
|
texthtml = os.path.join(build, doc, 'index.html')
|
|
if doc == 'man':
|
|
# Special handling for single MAN file
|
|
texthtml = os.path.join(build, doc, 'scons-scons.html')
|
|
|
|
env.Command(text, env.File(texthtml), "lynx -dump ${SOURCE.abspath} > $TARGET")
|
|
Local(text)
|
|
|
|
env.Ignore(text, version_xml)
|
|
|
|
tar_deps.append(text)
|
|
tar_list.append(text)
|
|
|
|
if 'man' in docs[doc][DOCTARGETS]:
|
|
#
|
|
# Man page(s)
|
|
#
|
|
for m in man_page_list:
|
|
man, _1 = os.path.splitext(m)
|
|
|
|
pdf = os.path.join(build, 'PDF', '%s-man.pdf' % man)
|
|
html = os.path.join(build, 'HTML', '%s-man.html' % man)
|
|
|
|
env.InstallAs(env.File(pdf), env.File(os.path.join(build, 'man', 'scons-%s.pdf' % man)))
|
|
env.InstallAs(env.File(html), env.File(os.path.join(build, 'man', 'scons-%s.html' % man)))
|
|
|
|
tar_deps.extend([pdf, html])
|
|
tar_list.extend([pdf, html])
|
|
|
|
# Install CSS file, common to all single HTMLs
|
|
if install_css:
|
|
css_file = os.path.join(build, 'HTML', 'scons.css')
|
|
env.InstallAs(env.File(css_file),
|
|
env.File(os.path.join(build, 'user', 'scons.css')))
|
|
tar_deps.extend([css_file])
|
|
tar_list.extend([css_file])
|
|
Local(css_file)
|
|
|
|
if not skip_doc:
|
|
# Build API DOCS
|
|
# TODO: Better specify dependencies on source files
|
|
pdf_file = env.Command('#/build/doc/api/scons-api.pdf',
|
|
env.Glob('#/SCons/*'),
|
|
[Delete("#/build/doc/api"),
|
|
"cd doc && make pdf"])
|
|
pdf_install = os.path.join(build, 'PDF', 'scons-api.pdf')
|
|
env.InstallAs(pdf_install, pdf_file)
|
|
tar_deps.append(pdf_install)
|
|
tar_list.append(pdf_install)
|
|
|
|
htmldir = os.path.join(build, 'HTML', 'scons-api')
|
|
html_files = env.Command('#/build/doc/HTML/scons-api/index.html',
|
|
env.Glob('#/SCons/*'),
|
|
"cd doc && make dirhtml BUILDDIR=${HTMLDIR}",
|
|
HTMLDIR=htmldir)
|
|
tar_deps.append(htmldir)
|
|
tar_list.append(htmldir)
|
|
|
|
#
|
|
# Now actually create the tar file of the documentation,
|
|
# for easy distribution to the web site.
|
|
#
|
|
if tar_deps:
|
|
tar_list = ' '.join([x.replace(build + '/', '') for x in 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, 0o644))
|
|
Local(t)
|
|
Alias('doc', t)
|
|
else:
|
|
Alias('doc', os.path.join(command_line.build_dir, 'doc'))
|