diff options
author | Chris St. Pierre <stpierreca@ornl.gov> | 2011-01-27 14:50:51 -0600 |
---|---|---|
committer | Sol Jerome <sol.jerome@gmail.com> | 2011-01-27 14:50:51 -0600 |
commit | a193b1edeebc0f96cc15e9702af97a0480cd9c4b (patch) | |
tree | 02f3b923c8b41ef0058fb003713404a3ac2f32ef | |
parent | 48d88b48a08091340f16add2f505101948c8a9d9 (diff) | |
download | bcfg2-a193b1edeebc0f96cc15e9702af97a0480cd9c4b.tar.gz bcfg2-a193b1edeebc0f96cc15e9702af97a0480cd9c4b.tar.bz2 bcfg2-a193b1edeebc0f96cc15e9702af97a0480cd9c4b.zip |
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 <sol.jerome@gmail.com>
-rw-r--r-- | redhat/bcfg2.spec.in | 33 | ||||
-rw-r--r-- | schemas/bundle.xsd | 193 | ||||
-rw-r--r-- | setup.py | 108 |
3 files changed, 311 insertions, 23 deletions
diff --git a/redhat/bcfg2.spec.in b/redhat/bcfg2.spec.in index 9378e9267..dd6e70f86 100644 --- a/redhat/bcfg2.spec.in +++ b/redhat/bcfg2.spec.in @@ -26,6 +26,17 @@ BuildRequires: python-setuptools-devel BuildRequires: python-setuptools %endif +%if 0%{?rhel} <= 5 +BuildRequires: python-sphinx10 +# the python-sphinx10 package doesn't set sys.path correctly, so we +# have to do it for them +%define pythonpath %(rpm -ql python-sphinx10 | grep '\.egg$') +%else +BuildRequires: python-sphinx >= 0.6 +%endif + +BuildRequires: python-lxml + %if "%{py_ver}" == "2.4" Requires: python-elementtree %else if "%{py_ver}" < "2.5" @@ -81,6 +92,13 @@ Requires(postun): /sbin/service %description server Configuration management server +%package doc +Summary: Configuration management system documentation +Group: Documentation + +%description doc +Configuration management system documentation + %prep %setup -q -n %{name}-%{version}-%{release} @@ -104,6 +122,10 @@ done %build %{__python} -c 'import setuptools; execfile("setup.py")' build +%{__python} -c 'import setuptools; execfile("setup.py")' build_dtddoc + +%{?pythonpath: export PYTHONPATH="%{pythonpath}"} +%{__python} -c 'import setuptools; execfile("setup.py")' build_sphinx %install rm -rf %{buildroot} @@ -117,6 +139,7 @@ mkdir -p %{buildroot}%{_sysconfdir}/sysconfig mkdir -p %{buildroot}%{_libexecdir} mkdir -p %{buildroot}%{_var}/lib/bcfg2 mkdir -p %{buildroot}%{_var}/cache/bcfg2 +mkdir -p %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version} mv %{buildroot}%{_bindir}/bcfg2* %{buildroot}%{_sbindir} @@ -128,6 +151,9 @@ install -m 755 tools/bcfg2-cron %{buildroot}%{_libexecdir}/bcfg2-cron install -m 644 debian/bcfg2.default %{buildroot}%{_sysconfdir}/sysconfig/bcfg2 +mv build/sphinx/html/* %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version} +mv build/dtd %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version}/ + touch %{buildroot}%{_sysconfdir}/bcfg2.conf touch %{buildroot}%{_sysconfdir}/bcfg2.key @@ -216,7 +242,14 @@ fi %dir %{_var}/lib/bcfg2 +%files doc +%defattr(0644,root,root,-) +%doc %{_defaultdocdir}/bcfg2-doc-%{version} + %changelog +* Thu Jan 27 2011 Chris St. Pierre <stpierreca@ornl.gov> 1.2.0pre1-0.0 +- Added -doc sub-package + * Wed Jun 15 2009 Sol Jerome <solj@ices.utexas.edu> 1.0pre4-0.1 - Remove python-cheetah dependency diff --git a/schemas/bundle.xsd b/schemas/bundle.xsd index d674fb86a..bf72915d8 100644 --- a/schemas/bundle.xsd +++ b/schemas/bundle.xsd @@ -14,32 +14,185 @@ <xsd:complexType name='GroupType'> <xsd:choice minOccurs='0' maxOccurs='unbounded'> - <xsd:element name='Package' type='StructureEntry'/> - <xsd:element name='Path' type='PathEntry'/> - <xsd:element name='Service' type='StructureEntry'/> - <xsd:element name='Action' type='StructureEntry'/> - <xsd:element name='BoundPackage' type='PackageType'/> - <xsd:element name='BoundPath' type='BoundPathEntry'/> - <xsd:element name='BoundService' type='ServiceType'/> - <xsd:element name='BoundAction' type='ActionType'/> - <xsd:element name='Group' type='GroupType'/> + <xsd:element name='Package' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Package entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Path' type='PathEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Path entry. The entry will + either be handled by Cfg, TGenshi, or another + DirectoryBacked plugin; or handled by Rules, in which case + the full specification of this entry will be included in + Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Service' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Service entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Action' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of an Action entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundPackage' type='PackageType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a software package to be managed. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundPath' type='BoundPathEntry'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a filesystem path to be handled + by the POSIX driver. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundService' type='ServiceType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a system service to be managed. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundAction' type='ActionType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a command to be run. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Group' type='GroupType'> + <xsd:annotation> + <xsd:documentation> + Elements within Group tags only apply to clients that are + members of that group (or vice-versa; see #element_negate + below) + </xsd:documentation> + </xsd:annotation> + </xsd:element> </xsd:choice> - <xsd:attribute type='xsd:string' name='name' use='required'/> - <xsd:attribute type='xsd:string' name='negate' /> + <xsd:attribute type='xsd:string' name='name' use='required'> + <xsd:annotation> + <xsd:documentation>The group name</xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute type='xsd:string' name='negate'> + <xsd:annotation> + <xsd:documentation> + Negate the sense of this group; i.e., entries within this + tag are only used on clients that are not members of the + group + </xsd:documentation> + </xsd:annotation> + </xsd:attribute> </xsd:complexType> <xsd:element name='Bundle'> + <xsd:annotation> + <xsd:documentation> + A bundle describes a group of inter-dependent configuration + entries, such as the combination of packages, configuration + files, and service activations that comprise typical Unix + daemons. Bundles are used to add groups of configuration + entries to the inventory of client configurations, as + opposed to describing particular versions of those + entries. For example, a bundle could say that the + configuration file ``/etc/passwd`` should be included in a + configuration, but will not describe the particular version + of ``/etc/passwd`` that a given client will receive. + </xsd:documentation> + </xsd:annotation> <xsd:complexType> <xsd:choice minOccurs='0' maxOccurs='unbounded'> - <xsd:element name='Package' type='StructureEntry'/> - <xsd:element name='Path' type='PathEntry'/> - <xsd:element name='Service' type='StructureEntry'/> - <xsd:element name='Action' type='StructureEntry'/> - <xsd:element name='BoundPackage' type='PackageType'/> - <xsd:element name='BoundPath' type='BoundPathEntry'/> - <xsd:element name='BoundService' type='ServiceType'/> - <xsd:element name='BoundAction' type='ActionType'/> - <xsd:element name='Group' type='GroupType'/> + <xsd:element name='Package' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Package entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Path' type='PathEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Path entry. The entry will + either be handled by Cfg, TGenshi, or another + DirectoryBacked plugin; or handled by Rules, in which case + the full specification of this entry will be included in + Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Service' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of a Service entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Action' type='StructureEntry'> + <xsd:annotation> + <xsd:documentation> + Abstract implementation of an Action entry. The full + specification will be included in Rules. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundPackage' type='PackageType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a software package to be managed. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundPath' type='BoundPathEntry'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a filesystem path to be handled + by the POSIX driver. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundService' type='ServiceType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a system service to be managed. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='BoundAction' type='ActionType'> + <xsd:annotation> + <xsd:documentation> + Fully bound description of a command to be run. + </xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name='Group' type='GroupType'> + <xsd:annotation> + <xsd:documentation> + Elements within Group tags only apply to clients that are + members of that group + </xsd:documentation> + </xsd:annotation> + </xsd:element> </xsd:choice> <xsd:attribute type='xsd:string' name='description' /> <xsd:attribute type='xsd:string' name='name'/> @@ -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", |