From 3c73d240ede12a4dd512c573d227478019368e96 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: May 11 2016 21:00:21 +0000
Subject: [PATCH 1/5] cg matching policy handlers


---

diff --git a/hub/kojihub.py b/hub/kojihub.py
index db7b69a..daaf639 100644
--- a/hub/kojihub.py
+++ b/hub/kojihub.py
@@ -40,6 +40,7 @@ import hashlib
 from koji.util import md5_constructor
 from koji.util import sha1_constructor
 from koji.util import dslice
+from koji.util import multi_fnmatch
 import os
 import re
 import rpm
@@ -7383,6 +7384,30 @@ def policy_get_pkg(data):
     #else
     raise koji.GenericError, "policy requires package data"
 
+
+def policy_get_cgs(data):
+    """Determine content generators from policy data"""
+
+    if not data.has_key('build'):
+        raise koji.GenericError, "policy requires build data"
+    binfo = get_build(data['build'], strict=True)
+
+    # first get buildroots used
+    rpm_brs = [r['buildroot_id'] for r in list_rpms(buildID=binfo['id'])]
+    archive_brs = [a['buildroot_id'] for a in list_archives(buildID=binfo['id'])]
+
+    # pull cg info out
+    # note that br_id will be None if a component had no buildroot
+    cgs = set()
+    for br_id in set(rpm_brs + archive_brs):
+        if br_id is None:
+            cgs.add(None)
+        else:
+            cgs.add(get_buildroot(br_id, strict=True)['cg_name'])
+
+    return cgs
+
+
 class NewPackageTest(koji.policy.BaseSimpleTest):
     """Checks to see if a package exists yet"""
     name = 'is_new_package'
@@ -7415,6 +7440,54 @@ class VolumeTest(koji.policy.MatchTest):
         data[self.field] = volinfo['name']
         return super(VolumeTest, self).run(data)
 
+
+class CGMatchAnyTest(koji.policy.BaseSimpleTest):
+    """Checks content generator against glob patterns
+
+    The 'any' means that if any of the cgs for the build (there can be more
+    than one) match the pattern list, then the result is True
+    """
+
+    name = 'cg_match_any'
+
+    def run(self, data):
+        #we need to find the volume name from the base data
+        cgs = policy_get_cgs(data)
+        patterns = self.str.split()[1:]
+        for cg_name in cgs:
+            if cg_name is None:
+                # component with no br, or br with no cg
+                continue
+            if multi_fnmatch(cg_name, patterns):
+                return True
+        # else
+        return False
+
+
+class CGMatchAllTest(koji.policy.BaseSimpleTest):
+    """Checks content generator against glob patterns
+
+    The 'all' means that all of the cgs for the build (there can be more
+    than one) must match the pattern list for the result to be true.
+    """
+
+    name = 'cg_match_all'
+
+    def run(self, data):
+        #we need to find the volume name from the base data
+        cgs = policy_get_cgs(data)
+        if not cgs:
+            return False
+        patterns = self.str.split()[1:]
+        for cg_name in cgs:
+            if cg_name is None:
+                return False
+            if not multi_fnmatch(cg_name, patterns):
+                return False
+        # else
+        return True
+
+
 class TagTest(koji.policy.MatchTest):
     name = 'tag'
     field = '_tagname'

From f9bd7bb1f46b0a5f45ccb416a0b5d6887b572167 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: May 11 2016 21:00:21 +0000
Subject: [PATCH 2/5] use build source value for source test, if available


---

diff --git a/hub/kojihub.py b/hub/kojihub.py
index daaf639..fb6f9cb 100644
--- a/hub/kojihub.py
+++ b/hub/kojihub.py
@@ -7691,24 +7691,27 @@ class SourceTest(koji.policy.MatchTest):
         if data.has_key('source'):
             data[self.field] = data['source']
         elif data.has_key('build'):
-            #crack open the build task
             build = get_build(data['build'])
-            if build['task_id'] is None:
-                #imported, no source to match against
-                return False
-            task = Task(build['task_id'])
-            info = task.getInfo()
-            params = task.getRequest()
-            #signatures:
-            # build - (src, target, opts=None)
-            # maven - (url, target, opts=None)
-            # winbuild - (name, source_url, target, opts=None)
-            if info['method'] == 'winbuild':
-                data[self.field] = params[1]
-            elif info['method'] == 'indirectionimage':
+            if build['source'] is not None:
+                data[self.field] = build['source']
+            elif build['task_id'] is None:
+                # no source to match against
                 return False
             else:
-                data[self.field] = params[0]
+                #crack open the build task
+                task = Task(build['task_id'])
+                info = task.getInfo()
+                params = task.getRequest()
+                #signatures:
+                # build - (src, target, opts=None)
+                # maven - (url, target, opts=None)
+                # winbuild - (name, source_url, target, opts=None)
+                if info['method'] == 'winbuild':
+                    data[self.field] = params[1]
+                elif info['method'] == 'indirectionimage':
+                    return False
+                else:
+                    data[self.field] = params[0]
         else:
             return False
         return super(SourceTest, self).run(data)

From 32160aa47ea55d765ca8ee7144ae0c96c58d41e1 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: May 11 2016 21:00:21 +0000
Subject: [PATCH 3/5] show source in buildinfo display, if available


---

diff --git a/cli/koji b/cli/koji
index 2fc90d9..6b4361d 100755
--- a/cli/koji
+++ b/cli/koji
@@ -3232,6 +3232,9 @@ def anon_handle_buildinfo(options, session, args):
         print "BUILD: %(name)s-%(version)s-%(release)s [%(id)d]" % info
         print "State: %(state)s" % info
         print "Built by: %(owner_name)s" % info
+        source = info.get('source')
+        if source is not None:
+            print "Source: %s" % source
         if 'volume_name' in info:
             print "Volume: %(volume_name)s" % info
         if task:
diff --git a/www/kojiweb/buildinfo.chtml b/www/kojiweb/buildinfo.chtml
index 73b85dd..3936055 100644
--- a/www/kojiweb/buildinfo.chtml
+++ b/www/kojiweb/buildinfo.chtml
@@ -24,6 +24,11 @@
     <tr>
       <th>Epoch</th><td>$build.epoch</td>
     </tr>
+    #if $build.get('source')
+    <tr>
+      <th>Source</th><td>$build['source']</td>
+    </tr>
+    #end if
     #if $mavenbuild
     <tr>
       <th>Maven&nbsp;groupId</th><td>$mavenbuild.group_id</td>

From dfcdbbaff2e07bbd53263adac34fec2e16fdd766 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: May 11 2016 21:00:22 +0000
Subject: [PATCH 4/5] don't ignore source data in cg_import


---

diff --git a/hub/kojihub.py b/hub/kojihub.py
index fb6f9cb..d8e85a6 100644
--- a/hub/kojihub.py
+++ b/hub/kojihub.py
@@ -4805,7 +4805,7 @@ class CG_Importer(object):
             raise koji.GenericError("Build already exists: %r" % buildinfo)
         else:
             # gather needed data
-            buildinfo = dslice(metadata['build'], ['name', 'version', 'release', 'extra'])
+            buildinfo = dslice(metadata['build'], ['name', 'version', 'release', 'extra', 'source'])
             # epoch is not in the metadata spec, but we allow it to be specified
             buildinfo['epoch'] = metadata['build'].get('epoch', None)
             buildinfo['start_time'] = \

From b0da550dfc3c8fc1f2e0fb6056d64bbd26b32017 Mon Sep 17 00:00:00 2001
From: Mike McLean <mikem@redhat.com>
Date: May 11 2016 21:00:22 +0000
Subject: [PATCH 5/5] ignore tagless buildroots in BuildTagTest


---

diff --git a/hub/kojihub.py b/hub/kojihub.py
index d8e85a6..ba7a972 100644
--- a/hub/kojihub.py
+++ b/hub/kojihub.py
@@ -7571,6 +7571,9 @@ class BuildTagTest(koji.policy.BaseSimpleTest):
                 if br_id is None:
                     continue
                 tagname = get_buildroot(br_id)['tag_name']
+                if tagname is None:
+                    # content generator buildroots might not have tag info
+                    continue
                 for pattern in args:
                     if fnmatch.fnmatch(tagname, pattern):
                         return True

