From 88d41171dc7c80a7be92689a59347c0f984562dc Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 15 Sep 2011 09:06:41 -0400 Subject: made templated bundles understand and tags --- doc/server/plugins/structures/bundler/index.txt | 69 ++++++++++++++++--------- src/lib/Server/Plugins/SGenshi.py | 26 ++++++++-- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/doc/server/plugins/structures/bundler/index.txt b/doc/server/plugins/structures/bundler/index.txt index 0cc2a0e55..7483173cc 100644 --- a/doc/server/plugins/structures/bundler/index.txt +++ b/doc/server/plugins/structures/bundler/index.txt @@ -148,18 +148,25 @@ Use .. warning:: - Group tags are not used inside of Genshi templates. You can get the - same logic (and more) using Genshi conditionals. + ```` and ```` tags are allowed inside of Genshi + templates as of Bcfg2 1.2. However, they do not behave the same + as using a Genshi conditional, e.g.:: - .. code-block:: xml - - + - -Bcfg uses the Genshi API for templates, and performs a XML format + + The conditional is evaluated when the template is rendered, so + code inside the conditional is not executed if the conditional + fails. A ```` tag is evaluated *after* the template is + rendered, so code inside the tag is always executed. This is an + important distinction: if you have code that will fail on some + groups, you *must* use a Genshi conditional, not a ```` + tag. The same caveats apply to ```` tags. + +Bcfg2 uses the Genshi API for templates, and performs a XML format stream rendering of the template into an lxml entry, which is included in the client configuration. :ref:`Client metadata ` -is avilable inside of the template using the 'metadata' name. Note that +is available inside of the template using the 'metadata' name. Note that only the markup Genshi template format can be used, as the target output format is XML. @@ -210,45 +217,59 @@ and returns them in a newline delimited string. .. code-block:: xml - + - + .. note:: - * The use of the altsrc directive causes all ifcfg files to be handled by the same plugin and entry. - * The blocks have only been available in genshi since 0.4 (http://genshi.edgewall.org/ticket/84) + * The use of the altsrc directive causes all ifcfg files to be + handled by the same plugin and entry. + * The blocks have only been available in genshi since + 0.4 (http://genshi.edgewall.org/ticket/84) If you want a file to be only on a per-client basis, you can use an -if declaration: - -.. code-block:: xml +if declaration:: - + -or alternately: +or alternately:: -.. code-block:: xml + + + + + + + + + +or yet another way:: - + - + -The latter form is preferred if the if block contains multiple -files. While this example is simple, the test in the if block can in -fact be any python statement. +The final form is preferred if there is no code inside the block that +would fail on other clients. + +While these examples are simple, the test in the if block can in fact +be any python statement. .. _server-plugins-structures-bundler-index-examples: diff --git a/src/lib/Server/Plugins/SGenshi.py b/src/lib/Server/Plugins/SGenshi.py index efd981956..3745834a8 100644 --- a/src/lib/Server/Plugins/SGenshi.py +++ b/src/lib/Server/Plugins/SGenshi.py @@ -5,6 +5,7 @@ import genshi.input import genshi.template import lxml.etree import logging +import copy import sys import Bcfg2.Server.Plugin @@ -13,28 +14,45 @@ import Bcfg2.Server.Plugins.TGenshi logger = logging.getLogger('Bcfg2.Plugins.SGenshi') -class SGenshiTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile): +class SGenshiTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile, + Bcfg2.Server.Plugin.StructFile): + def __init__(self, name, specific, encoding): + Bcfg2.Server.Plugins.TGenshi.TemplateFile.__init__(self, name, + specific, encoding) + Bcfg2.Server.Plugin.StructFile.__init__(self, name) def get_xml_value(self, metadata): if not hasattr(self, 'template'): logger.error("No parsed template information for %s" % (self.name)) raise Bcfg2.Server.Plugin.PluginExecutionError try: - stream = self.template.generate(metadata=metadata,).filter( \ + stream = self.template.generate(metadata=metadata).filter( \ Bcfg2.Server.Plugins.TGenshi.removecomment) - data = stream.render('xml', strip_whitespace=False) - return lxml.etree.XML(data) + data = lxml.etree.XML(stream.render('xml', strip_whitespace=False)) + bundlename = self.name.split('/')[-1][:-4] + bundle = lxml.etree.Element('Bundle', name=bundlename) + for item in self.Match(metadata, data): + bundle.append(copy.deepcopy(item)) + return bundle except LookupError: lerror = sys.exc_info()[1] logger.error('Genshi lookup error: %s' % lerror) except genshi.template.TemplateError: terror = sys.exc_info()[1] logger.error('Genshi template error: %s' % terror) + raise except genshi.input.ParseError: perror = sys.exc_info()[1] logger.error('Genshi parse error: %s' % perror) raise + def Match(self, metadata, xdata): + """Return matching fragments of parsed template.""" + rv = [] + for child in xdata.getchildren(): + rv.extend(self._match(child, metadata)) + logger.debug("File %s got %d match(es)" % (self.name, len(rv))) + return rv class SGenshiEntrySet(Bcfg2.Server.Plugin.EntrySet): -- cgit v1.2.3-1-g7c22