[jhbuild] Handle <if> tags in moduleset files



commit b4664812b4353655f42391c0bfa327429075c11b
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Dec 20 17:54:12 2013 -0500

    Handle <if> tags in moduleset files
    
    If we encounter an <if> tag, consult the conditions set in the config
    in order to decide if we should include its content or not.  If the
    condition is met, the child elements are added to the parent of the
    <if/> tag as if the condition tag were not there at all.  If the
    condition is not met, the entire content is simply dropped.
    
    We do the processing as a transformation on the DOM as a whole,
    immediately after parsing the moduleset XML, before doing any additional
    processing.  This allows <if> to be used for anything and it means we
    don't need to deal with it separately from each place.
    
    Although the tool itself will accept <if> anywhere we use the schemas to
    restrict its use to the purposes of conditionalising dependencies
    (including suggests) and {autogen,make,makeinstall}args.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=720839

 jhbuild/moduleset.py     |   45 +++++++++++++++++++++++++++++++++++++++++++++
 modulesets/moduleset.dtd |   19 ++++++++++++++++---
 modulesets/moduleset.rnc |    9 ++++++---
 3 files changed, 67 insertions(+), 6 deletions(-)
---
diff --git a/jhbuild/moduleset.py b/jhbuild/moduleset.py
index 3dc3aca..c3d64e3 100644
--- a/jhbuild/moduleset.py
+++ b/jhbuild/moduleset.py
@@ -378,6 +378,48 @@ def _child_elements_matching(parent, names):
         if node.nodeType == node.ELEMENT_NODE and node.nodeName in names:
             yield node
 
+def _handle_conditions(config, element):
+    """
+    If we encounter an <if> tag, consult the conditions set in the config
+    in order to decide if we should include its content or not.  If the
+    condition is met, the child elements are added to the parent of the
+    <if/> tag as if the condition tag were not there at all.  If the
+    condition is not met, the entire content is simply dropped.
+
+    We do the processing as a transformation on the DOM as a whole,
+    immediately after parsing the moduleset XML, before doing any additional
+    processing.  This allows <if> to be used for anything and it means we
+    don't need to deal with it separately from each place.
+
+    Although the tool itself will accept <if> anywhere we use the schemas to
+    restrict its use to the purposes of conditionalising dependencies
+    (including suggests) and {autogen,make,makeinstall}args.
+    """
+
+    for condition_tag in _child_elements_matching(element, ['if']):
+        # In all cases, we remove the element from the parent
+        element.childNodes.remove(condition_tag)
+
+        # grab the condition from the attributes
+        c_if = condition_tag.getAttribute('condition-set')
+        c_unless = condition_tag.getAttribute('condition-unset')
+
+        if (not c_if) == (not c_unless):
+            raise FatalError(_("<if> must have exactly one of condition-set='' or condition-unset=''"))
+
+        # check the condition
+        condition_true = ((c_if and c_if in config.conditions) or
+                          (c_unless and c_unless not in config.conditions))
+
+        if condition_true:
+            # add the child elements of <condition> back into the parent
+            for condition_child in _child_elements(condition_tag):
+                element.childNodes.append(condition_child)
+
+    # now, recurse
+    for c in _child_elements(element):
+        _handle_conditions(config, c)
+
 def _parse_module_set(config, uri):
     try:
         filename = httpcache.load(uri, nonetwork=config.nonetwork, age=0)
@@ -392,6 +434,9 @@ def _parse_module_set(config, uri):
         raise FatalError(_('failed to parse %s: %s') % (uri, e))
 
     assert document.documentElement.nodeName == 'moduleset'
+
+    _handle_conditions(config, document.documentElement)
+
     moduleset = ModuleSet(config = config)
     moduleset_name = document.documentElement.getAttribute('name')
     if not moduleset_name:
diff --git a/modulesets/moduleset.dtd b/modulesets/moduleset.dtd
index bc9eed6..bad1c0f 100644
--- a/modulesets/moduleset.dtd
+++ b/modulesets/moduleset.dtd
@@ -2,6 +2,19 @@
 <!ATTLIST moduleset
        name     CDATA  #IMPLIED>
 
+<!-- DTD is incapable of allowing different children of an element
+     of a given name depending on the context in which it appears so
+     this is more permissive than it ought to be.  The RNG version
+     of the schema gets this correct.
+
+     DTD also appears to be incapable of describing the fact that
+     exactly one of condition-set='' and condition-unset='' is required.
+-->
+<!ELEMENT if (if|dep|autogenargs|makeargs|makeinstallargs)+>
+<!ATTLIST if
+       condition-set   CDATA   #IMPLIED
+       condition-unset CDATA   #IMPLIED>
+
 <!ELEMENT repository (mirror*)>
 <!ATTLIST repository
        name     CDATA  #REQUIRED
@@ -34,7 +47,7 @@
 <!ELEMENT include EMPTY>
 <!ATTLIST include href CDATA #REQUIRED>
 
-<!ELEMENT autotools 
(autogenargs*,makeargs*,makeinstallargs*,pkg-config?,branch,dependencies?,suggests?,after?)>
+<!ELEMENT autotools 
(if*,autogenargs*,makeargs*,makeinstallargs*,pkg-config?,branch,dependencies?,suggests?,after?)>
 <!-- Note: Here the ID type is not used as some existing IDs in modsets are not
      valid XML ID types - instead CDATA is used -->
 <!ATTLIST autotools
@@ -156,8 +169,8 @@
 
 <!-- Other children -->
 <!ELEMENT pkg-config (#PCDATA)>
-<!ELEMENT dependencies (dep*)>
-<!ELEMENT suggests (dep*)>
+<!ELEMENT dependencies (dep|if)*>
+<!ELEMENT suggests (dep|if)*>
 <!ELEMENT after (dep*)>
 <!ELEMENT systemdependencies (dep*)>
 <!ELEMENT dep EMPTY>
diff --git a/modulesets/moduleset.rnc b/modulesets/moduleset.rnc
index bb2b4a7..dabe7ab 100644
--- a/modulesets/moduleset.rnc
+++ b/modulesets/moduleset.rnc
@@ -72,9 +72,10 @@ attlist.mirror &=
 attlist.include &= attribute href { text }
 # As parsed by get_dependencies()
 dependencieselements = dependencies?, suggests?, after?, systemdependencies?
+argsif = element if { attlist.if, argsif*, autogenargs*, makeargs*, makeinstallargs* }
 autotools =
   element autotools {
-    attlist.autotools, autogenargs*, makeargs*, makeinstallargs*, pkg-config?, branch, dependencieselements
+    attlist.autotools, argsif*, autogenargs*, makeargs*, makeinstallargs*, pkg-config?, branch, 
dependencieselements
   }
 # Note: Here the ID type is not used as some existing IDs in modsets are not
 # valid XML ID types - instead CDATA is used
@@ -210,9 +211,11 @@ attlist.testedmodules &= empty
 tested = element tested { attlist.tested, empty }
 attlist.tested &= attribute package { text }
 # Other children
-dependencies = element dependencies { attlist.dependencies, dep* }
+attlist.if = attribute condition-set { text } | attribute condition-unset { text }
+depif = element if { attlist.if, depif*, dep* }
+dependencies = element dependencies { attlist.dependencies, depif*, dep* }
 attlist.dependencies &= empty
-suggests = element suggests { attlist.suggests, dep* }
+suggests = element suggests { attlist.suggests, depif*, dep* }
 attlist.suggests &= empty
 after = element after { attlist.after, dep* }
 attlist.after &= empty


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]