[Patchew-devel] [PATCH 07/17] mods: refactor extraction of configuration into a dictionary

Paolo Bonzini pbonzini at redhat.com
Thu May 2 11:17:54 UTC 2019


Both the email and testing modules have code to extract the
configuration from project properties into a dictionary.
Generalize that code, using the project_config_schema to
drive the conversion, and use it in the git plugin as well

This matches the way configuration will be stored in the database
when we move away from project properties.  In fact, all
this nice visitor code will disappear very soon...

Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
---
 mod.py          | 37 ++++++++++++++++++++++++++++++++++++-
 mods/email.py   | 16 ++--------------
 mods/git.py     | 28 ++++++++++++++++------------
 mods/testing.py | 25 ++++---------------------
 4 files changed, 58 insertions(+), 48 deletions(-)

diff --git a/mod.py b/mod.py
index 6f172d5..9e15064 100644
--- a/mod.py
+++ b/mod.py
@@ -53,7 +53,7 @@ class PatchewModule(object):
         prefix = prefix + scm.name + "."
         def _build_map_items():
             r = {}
-            for p, v in project.get_properties().items():
+            for p in project.get_properties().keys():
                 if not p.startswith(prefix):
                     continue
                 name = p[len(prefix):]
@@ -150,6 +150,41 @@ class PatchewModule(object):
         scm = self.project_config_schema
         return self._build_one(request, project, scm.name + ".", scm)
 
+    def _get_map_scm(self, project, prop_name, scm):
+        prefix = prop_name + "."
+        result = {}
+        for p in project.get_properties().keys():
+            if not p.startswith(prefix):
+                continue
+            name = p[len(prefix):]
+            name = name[:name.rfind(".")]
+            if name in result:
+                continue
+            assert scm.item.name == '{name}'
+            value = self._get_one(project, prefix + name, scm.item)
+            result[name] = value
+        return result
+
+    def _get_array_scm(self, project, prop_name, scm):
+        prefix = prop_name + "."
+        result = {}
+        for i in scm.members:
+            assert i.name != '{name}'
+            result[i.name] = self._get_one(project, prefix + i.name, i)
+        return result
+
+    def _get_one(self, project, prop_name, scm):
+        if type(scm) == MapSchema:
+            return self._get_map_scm(project, prop_name, scm)
+        elif type(scm) == ArraySchema:
+            return self._get_array_scm(project, prop_name, scm)
+        else:
+            return project.get_property(prop_name)
+
+    def get_project_config(self, project):
+        scm = self.project_config_schema
+        return self._get_one(project, scm.name, scm)
+
 _loaded_modules = {}
 
 def _module_init_config(cls):
diff --git a/mods/email.py b/mods/email.py
index 14553f0..23590d4 100644
--- a/mods/email.py
+++ b/mods/email.py
@@ -52,7 +52,7 @@ Email information is configured in "INI" style:
     default_config = _default_config
 
     email_schema = \
-        ArraySchema("email_notification", "Email Notification",
+        ArraySchema("{name}", "Email Notification",
                     desc="Email notification",
                     members=[
                         EnumSchema("event", "Event",
@@ -191,19 +191,7 @@ Email information is configured in "INI" style:
         return "<%s at patchew.org>" % uuid.uuid1()
 
     def get_notifications(self, project):
-        ret = {}
-        for k, v in project.get_properties().items():
-            if not k.startswith("email.notifications."):
-                continue
-            tn = k[len("email.notifications."):]
-            if "." not in tn:
-                continue
-            an = tn[tn.find(".") + 1:]
-            tn = tn[:tn.find(".")]
-            ret.setdefault(tn, {})
-            ret[tn][an] = v
-            ret[tn]["name"] = tn
-        return ret
+        return self.get_project_config(project).get("notifications", {})
 
     def on_event(self, event, **params):
         class EmailCancelled(Exception):
diff --git a/mods/git.py b/mods/git.py
index 110f261..d459a0b 100644
--- a/mods/git.py
+++ b/mods/git.py
@@ -98,9 +98,6 @@ class GitModule(PatchewModule):
         if series.is_complete:
             self.mark_as_pending_apply(series)
 
-    def get_project_config(self, project, what):
-        return project.get_property("git." + what)
-
     def _is_repo(self, path):
         if not os.path.isdir(path):
             return False
@@ -116,10 +113,14 @@ class GitModule(PatchewModule):
 
     def get_mirror(self, po, request, format):
         response = {}
-        for key, prop in (("head", "git.head"),
-                          ("pushurl", "git.push_to"),
-                          ("url", "git.public_repo")):
-            response[key] = po.get_property(prop) or None
+        config = self.get_project_config(po)
+        if "push_to" in config:
+            response["pushurl"] = config["push_to"]
+        if "public_repo" in config:
+            response["url"] = config["public_repo"]
+        head = po.get_property("git.head")
+        if head:
+            response["head"] = head
         return response
 
     def rest_project_fields_hook(self, request, fields):
@@ -130,7 +131,9 @@ class GitModule(PatchewModule):
 
     def get_projects_prepare_hook(self, project, response):
         response["git.head"] = project.get_property("git.head")
-        response["git.push_to"] = project.get_property("git.push_to")
+        config = self.get_project_config(project)
+        if "push_to" in config:
+            response["git.push_to"] = config["push_to"]
 
     def prepare_message_hook(self, request, message, detailed):
         if not message.is_series_head:
@@ -264,9 +267,9 @@ class ApplierGetView(APILoginRequiredView):
                                                       "properties", "tags"])
 
         po = m.project
-        for prop in ["git.push_to", "git.public_repo", "git.url_template"]:
-            if po.get_property(prop):
-                response[prop] = po.get_property(prop)
+        config = _instance.get_project_config(po)
+        for k, v in config.items():
+            response["git." + k] = v
         base = _instance.get_base(m)
         if base:
             response["git.repo"] = base.data["repo"]
@@ -296,7 +299,8 @@ class ApplierReportView(APILoginRequiredView):
             if url:
                 data['url'] = url
             elif tag:
-                url_template = p.get_property("git.url_template")
+                config = _instance.get_project_config(po)
+                url_template = config.get("url_template")
                 if url_template:
                     data['url'] = url_template.replace("%t", tag)
             if base:
diff --git a/mods/testing.py b/mods/testing.py
index caafc19..0125288 100644
--- a/mods/testing.py
+++ b/mods/testing.py
@@ -298,18 +298,7 @@ class TestingModule(PatchewModule):
         ret = {}
         if isinstance(obj, Message):
             obj = obj.project
-        for k, v in obj.get_properties().items():
-            if not k.startswith("testing.tests."):
-                continue
-            tn = k[len("testing.tests."):]
-            if "." not in tn:
-                continue
-            an = tn[tn.find(".") + 1:]
-            tn = tn[:tn.find(".")]
-            ret.setdefault(tn, {})
-            ret[tn][an] = v
-            ret[tn]["name"] = tn
-        return ret
+        return self.get_project_config(obj).get("tests", {})
 
     def _build_reset_ops(self, obj):
         if isinstance(obj, Message):
@@ -409,15 +398,8 @@ class TestingModule(PatchewModule):
             project.extra_ops += self._build_reset_ops(project)
 
     def get_capability_probes(self, project):
-        ret = {}
-        for k, v in project.get_properties().items():
-            prefix = "testing.requirements."
-            if not k.startswith(prefix):
-                continue
-            name = k[len(prefix):]
-            name = name[:name.find(".")]
-            ret[name] = v
-        return ret
+        props = self.get_project_config(project).get('requirements', {})
+        return {k: v['script'] for k, v in props.items()}
 
     def get_testing_probes(self, project, request, format):
         return self.get_capability_probes(project)
@@ -494,6 +476,7 @@ class TestingGetView(APILoginRequiredView):
                 if req not in capabilities:
                     break
             else:
+                t["name"] = tn
                 yield r, t
 
     def _find_project_test(self, request, po, tester, capabilities):
-- 
2.21.0





More information about the Patchew-devel mailing list