From 4afbb96b1ef62469845e00ddaecb521fc5f0cbdb Mon Sep 17 00:00:00 2001
From: Anders Blomdell <anders.blomdell@control.lth.se>
Date: Mon, 30 Jan 2017 20:41:38 +0100
Subject: [PATCH] Added group merging for comps.xml (needed for CentOS at
 least)

---
 src/mio.py            | 111 +++++++++++++++++++++++++-----------------
 src/mio/repository.py |   8 +--
 src/mio/transform.py  |   9 ++++
 3 files changed, 79 insertions(+), 49 deletions(-)

diff --git a/src/mio.py b/src/mio.py
index dfa02c1..cc2503d 100755
--- a/src/mio.py
+++ b/src/mio.py
@@ -24,9 +24,11 @@ def parse_with_path(path, filename, repository):
     f = mio.filecache.loadfile(path, filename)
     tree = mio.parser.parse(f.filename, url=f.key)
     
+    join = None
     if tree._tag == "comps":
         # Transform comps to canonical form
         tree = mio.transform.from_fedora(tree)
+        join = mio.transform.join
     elif tree._tag == "hostinfo":
         # Transform hostinfo to canonical form
         tree = mio.transform.from_hostinfo(tree)
@@ -34,7 +36,7 @@ def parse_with_path(path, filename, repository):
         # Transform mio tree to canonical form
         tree = mio.transform.from_mio(tree)
 
-    repository.add(tree._group_)
+    repository.add(tree._group_, join=join)
 
 def parse(filename, repository):
     path = list(options.path)
@@ -48,58 +50,74 @@ def parse(filename, repository):
             pass
     raise Exception("Could not parse %s" % filename)
 
-def find_and_parse(target, builder, url=None):
-    path = list(options.path)
-    if url:
-        for p in url.path:
-            path.insert(0, os.path.dirname(p))
+class FindAndParse:
 
-    for p in path:
-        if target.startswith("/"):
-            m = re.match("^/([^/]*)", target)
-            filename = "%s.mio" % (m.group(1))
-            pass
-        elif target.startswith("@"):
-            filename = "base/comps.xml"
+    def __init__(self):
+        self.tried = set()
+
+    def parse_with_path(self, path, filename, builder, target):
+        if not (path,filename) in self.tried:
             try:
-                # Try to locate group file via repomd.xml
-                f = mio.filecache.loadfile(p, '/repodata/repomd.xml')
-                tree = mio.parser.parse(f.filename)
-                for l in tree._data_._location_:
-                    if l.type[1] == 'group':
-                        filename = l.href[0]
-                        break
-                    pass
-                pass
+                parse_with_path(path, filename, builder) 
+                self.tried.add((path,filename))
+                return True
             except IOError, e:
-                continue
-            pass
-        else:
-            filename = "hostinfo.xml"
+                self.tried.add((path,filename))
+                pass
+            except ValueError, e:
+                pass
+            except DuplicateGroupException, e:
+                print e
+                traceback.print_exc()
+                print "Failed to locate: %s" % target
+                sys.exit(1)
+                pass
             pass
-        try:
-            parse_with_path(p, filename, builder)
+        return False
+            
+
+    def __call__(self, target, builder, url=None):
+        path = list(options.path)
+        if url:
+            for p in url.path:
+                path.insert(0, os.path.dirname(p))
+                
+        OK = False
+        for p in path:
+            if target.startswith("/"):
+                m = re.match("^/([^/]*)", target)
+                OK |= self.parse_with_path(p, "%s.mio" % (m.group(1)), builder, target)
+                pass
+            elif target.startswith("@"):
+                filename = "base/comps.xml"
+                try:
+                    # Try to locate group file via repomd.xml
+                    f = mio.filecache.loadfile(p, '/repodata/repomd.xml')
+                    tree = mio.parser.parse(f.filename)
+                    for l in tree._data_._location_:
+                        if l.type[1] == 'group':
+                            OK |= self.parse_with_path(p, l.href[0], builder, target)
+                            break
+                        pass
+                    pass
+                except IOError, e:
+                    continue
+                pass
+            else:
+                OK |= self.parse_with_path(p, "hostinfo.xml", builder, target)
+                pass
+        
+        if OK:
             return
-        except IOError, e:
-            pass
-        except ValueError, e:
+        if options.noyum and target.startswith('@'):
+            # Synthetic target
+            tmp1 = mio.parser.Node("mio", 0)
+            tmp2 =  mio.parser.Node("group", 0, { "name": target })
+            tmp1._add(tmp2)
+            builder.add(tmp1._group_)
             pass
-        except DuplicateGroupException, e:
-            print e
-            traceback.print_exc()
+        else:
             print "Failed to locate: %s" % target
-            sys.exit(1)
-            pass
-        pass
-    if options.noyum and target.startswith('@'):
-        # Synthetic target
-        tmp1 = mio.parser.Node("mio", 0)
-        tmp2 =  mio.parser.Node("group", 0, { "name": target })
-        tmp1._add(tmp2)
-        builder.add(tmp1._group_)
-        pass
-    else:
-        print "Failed to locate: %s" % target
 
 if __name__ == '__main__':
     optParser = argparse.ArgumentParser(usage="%(prog)s [options]")
@@ -168,6 +186,7 @@ if __name__ == '__main__':
 
     mio.log.set_verbosity(NORMAL + options.verbose - options.quiet)
 
+    find_and_parse = FindAndParse()
     rules = mio.repository.Repository(find_and_parse)
 
     rpm_result = None
diff --git a/src/mio/repository.py b/src/mio/repository.py
index 34d6eb1..9339ea2 100755
--- a/src/mio/repository.py
+++ b/src/mio/repository.py
@@ -12,13 +12,15 @@ class Repository:
         self.group = {}
         self.filter = filter
         
-
-    def add(self, group):
+    def add(self, group, join=None):
         for g in group:
             name = g.name[0]
             if self.group.has_key(name):
                 og = self.group[name]
-                raise DuplicateGroupException(g, og)
+                if join:
+                    g = join(og, g)
+                else:
+                    raise DuplicateGroupException(g, og)
             self.group[name] = g
 
     def get(self, target):
diff --git a/src/mio/transform.py b/src/mio/transform.py
index a7846d2..03aba20 100755
--- a/src/mio/transform.py
+++ b/src/mio/transform.py
@@ -2,6 +2,15 @@ import mio.parser
 import copy
 import itertools
 
+def join(a, b):
+    result = mio.parser.Node("group", a._line, a._attribute)
+    for c in a._child():
+        result._add(copy.deepcopy(c))
+    for c in b._child():
+        result._add(copy.deepcopy(c))
+    result._parent = a._parent
+    return result
+
 def from_fedora(tree):
     result = mio.parser.Node("mio", tree._line)
     result._url = tree._url
-- 
GitLab