From a193b1edeebc0f96cc15e9702af97a0480cd9c4b Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 27 Jan 2011 14:50:51 -0600 Subject: schemas: Build DTD docs, provide -doc subpackage in RPM (Resolves #984) From the ticket: I've attached a patch that does two things: 1. Uses xs3p (http://xml.fiforms.org/xs3p/), an XSLT stylesheet, to do transforms on the Bcfg2 DTD and automatically generates documentation on the DTD. I added a build_dtddoc command to setup.py that performs the transforms using lxml.etree and puts the resulting HTML in build/dtd. I also added some documentation to bundle.xsd; it's not much, but should demonstrate the ease with which the DTD can be documented with this system in use. 2. I added both build_sphinx and build_dtddoc commands to the RPM specfile, and added a -doc subpackage to put the resulting HTML in. The specfile builds successfully on CentOS 5 and Fedora 13. There are a couple of known issues: 1. The output from xs3p uses pop-ups to present documentation on non-global components, which, due to the way the Bcfg2 DTD is written, is most of them. This is ugly. It could be improved by modifying the XSLT, but I'm not a web designer and wasn't sure the best way to present that information. Either way, this is a start. 2. The python-sphinx10 package in EPEL 5 apparently has a bug where it fails to add itself to sys.path after installing. There's some ugliness in the spec file to get around that. Signed-off-by: Sol Jerome --- setup.py | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index ad2fa7331..9eaa6f626 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,114 @@ #!/usr/bin/env python from distutils.core import setup +from distutils.core import Command +from fnmatch import fnmatch +from glob import glob +import os.path +import lxml.etree + +class BuildDTDDoc (Command): + """Build DTD documentation""" + + description = "Build DTD documentation" + + # List of option tuples: long name, short name (None if no short + # name), and help string. + user_options = [ + ('links-file=', 'l', 'Links file'), + ('source-dir=', 's', 'Source directory'), + ('build-dir=', None, 'Build directory'), + ('xslt=', None, 'XSLT file'), + ] + + def initialize_options(self): + """Set default values for all the options that this command + supports.""" + + self.build_links = False + self.links_file = None + self.source_dir = None + self.build_dir = None + self.xslt = None + + def finalize_options(self): + """Set final values for all the options that this command + supports.""" + if self.source_dir is None: + if os.path.isdir('schemas'): + for root, dirnames, filenames in os.walk('schemas'): + for filename in filenames: + if fnmatch(filename, '*.xsd'): + self.source_dir = root + self.announce('Using source directory %s' % root) + break + self.ensure_dirname('source_dir') + self.source_dir = os.path.abspath(self.source_dir) + + if self.build_dir is None: + build = self.get_finalized_command('build') + self.build_dir = os.path.join(build.build_base, 'dtd') + self.mkpath(self.build_dir) + + if self.links_file is None: + self.links_file = "links.xml" + if os.path.isfile(os.path.join(self.source_dir, "links.xml")): + self.announce("Using linksFile links.xml") + else: + self.build_links = True + + if self.xslt is None: + xsl_files = glob(os.path.join(self.source_dir, '*.xsl')) + if xsl_files: + self.xslt = xsl_files[0] + self.announce("Using XSLT file %s" % self.xslt) + self.ensure_filename('xslt') + + def run (self): + """Perform XSLT transforms, writing output to self.build_dir""" + + xslt = lxml.etree.parse(self.xslt).getroot() + transform = lxml.etree.XSLT(xslt) + + if self.build_links: + self.announce("Building linksFile %s" % self.links_file) + links_xml = \ + lxml.etree.Element('links', + attrib={'xmlns':"http://titanium.dstc.edu.au/xml/xs3p"}) + for filename in glob(os.path.join(self.source_dir, '*.xsd')): + attrib = {'file-location':os.path.basename(filename), + 'docfile-location':os.path.splitext(os.path.basename(filename))[0] + ".html"} + links_xml.append(lxml.etree.Element('schema', attrib=attrib)) + open(os.path.join(self.source_dir, self.links_file), + "w").write(lxml.etree.tostring(links_xml)) + + # build parameter dict + params = {'printLegend':"'false'", + 'printGlossary':"'false'", + 'sortByComponent':"'false'",} + if self.links_file is not None: + params['linksFile'] = "'%s'" % self.links_file + params['searchIncludedSchemas'] = "'true'" + + for filename in glob(os.path.join(self.source_dir, '*.xsd')): + outfile = \ + os.path.join(self.build_dir, + os.path.splitext(os.path.basename(filename))[0] + + ".html") + self.announce("Transforming %s to %s" % (filename, outfile)) + xml = lxml.etree.parse(filename).getroot() + xhtml = str(transform(xml, **params)) + open(outfile, 'w').write(xhtml) + +cmdclass = {} + try: from sphinx.setup_command import BuildDoc - cmdclass = {'build_sphinx': BuildDoc} + cmdclass['build_sphinx'] = BuildDoc except ImportError: - cmdclass = {} -from glob import glob + pass + +cmdclass['build_dtddoc'] = BuildDTDDoc setup(cmdclass=cmdclass, name="Bcfg2", -- cgit v1.2.3-1-g7c22