From 0cf1c210c46e11db20068dc327ba7cfd6b075a94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lorenz=20H=C3=BCdepohl?= <lorenz.huedepohl@rzg.mpg.de>
Date: Mon, 19 Mar 2018 15:35:24 +0100
Subject: [PATCH] Update of mpcdf_enable_repositories

Has a (hopefully) less confusing syntax now, option to directly restrict
set of compiler/MPI/CUDA modules from commandline
---
 mpcdf_common.py              | 58 +++++++++++++++++++++--
 mpcdf_enable_repositories.py | 89 +++++++++++++++++-------------------
 2 files changed, 95 insertions(+), 52 deletions(-)

diff --git a/mpcdf_common.py b/mpcdf_common.py
index 1039e9b..68a9792 100644
--- a/mpcdf_common.py
+++ b/mpcdf_common.py
@@ -71,17 +71,67 @@ def get_attribute_values(api_url, project, package, attribute, with_project=Fals
     return list(value.text for value in attribute.findall("./value"))
 
 
-def set_attribute(api_url, path, attribute):
+def set_attribute(api_url, project, package, attribute):
+    path = ["source", project]
+    if package:
+        path.append(package)
+    path.append("_attribute")
+
     attr_meta = ElementTree.tostring(attribute, encoding=osc.core.ET_ENCODING)
 
-    url = osc.core.makeurl(api_url, ["source"] + list(path) + ["_attribute"])
+    url = osc.core.makeurl(api_url, path)
     resp = ElementTree.fromstringlist(osc.core.streamfile(url, osc.core.http_POST, data=attr_meta))
     if resp.find("./summary").text != "Ok":
         raise osc.oscerr.APIError("Could not store attribute")
 
 
-def mpcdf_enable_repositories(api_url, project, package, verbose=False):
+def set_attribute_values(api_url, project, package, attribute, values):
+    root = ElementTree.Element("attributes")
+    attr = ElementTree.SubElement(root, "attribute")
+
+    namespace, name = attribute.split(":")
+    attr.set("namespace", namespace)
+    attr.set("name", name)
+
+    for value in values:
+        v = ElementTree.SubElement(attr, "value")
+        v.text = value
+
+    set_attribute(api_url, project, package, root)
+
+
+def has_attribute(api_url, project, package, attribute):
+    path = ["source", project]
+    if package:
+        path.append(package)
+    path.append("_attribute")
+    path.append(attribute)
+
+    url = osc.core.makeurl(api_url, path)
+    resp = ElementTree.fromstringlist(osc.core.streamfile(url, osc.core.http_GET))
+
+    namespace, name = attribute.split(":")
 
+    for a in resp.findall("./attribute"):
+        if a.get("namespace") == namespace and a.get("name") == name:
+            return True
+    return False
+
+
+def remove_attribute(api_url, project, package, attribute_name):
+    path = ["source"] + [project]
+    if package:
+        path.append(package)
+    path.append("_attribute")
+    path.append(attribute_name)
+
+    url = osc.core.makeurl(api_url, path)
+    resp = ElementTree.fromstringlist(osc.core.streamfile(url, osc.core.http_DELETE))
+    if resp.find("./summary").text != "Ok":
+        raise osc.oscerr.APIError("Could not remove attribute")
+
+
+def mpcdf_enable_repositories(api_url, project, package, verbose=False):
     root = ElementTree.fromstringlist(osc.core.show_package_meta(api_url, project, package))
     build = root.find("./build")
     if build is None:
@@ -151,7 +201,7 @@ def mpcdf_setup_repositories(api_url, project, distribution=None, parent=None, p
     if parent:
         for attribute in ["MPCDF:compiler_modules", "MPCDF:mpi_modules", "MPCDF:cuda_modules"]:
             print("Copying attribute '{0}' from parent project".format(attribute))
-            set_attribute(api_url, (project,), get_attribute(api_url, parent, None, attribute))
+            set_attribute(api_url, project, None, get_attribute(api_url, parent, None, attribute))
 
     compilers = list(get_attribute_values(api_url, project, None, "MPCDF:compiler_modules"))
     mpis = list(get_attribute_values(api_url, project, None, "MPCDF:mpi_modules"))
diff --git a/mpcdf_enable_repositories.py b/mpcdf_enable_repositories.py
index 5a28955..b4bc4cb 100644
--- a/mpcdf_enable_repositories.py
+++ b/mpcdf_enable_repositories.py
@@ -1,6 +1,5 @@
 #!/usr/bin/python2
 from __future__ import print_function
-from xml.etree import ElementTree
 
 import mpcdf_common
 
@@ -11,20 +10,18 @@ import osc.core
 import osc.cmdln
 
 
-@osc.cmdln.option('--cuda-mpi', action="store_true",
-                  help="Flag to enable for all CUDA+MPI repositories")
-@osc.cmdln.option('--cuda', action="store_true",
-                  help="Flag to enable for all CUDA repositories")
-@osc.cmdln.option('--mpi', action="store_true",
-                  help="Flag to enable for all MPI module repositories")
-@osc.cmdln.option('--compilers', action="store_true",
-                  help="Flag to enable for all compiler module repositories")
-@osc.cmdln.option('--system', action="store_true",
-                  help="Flag to enable for System repository")
-@osc.cmdln.option('--reset', action="store_true",
-                  help="Re-create the set of enabled repositories from the MPCDF:enable_repositores attribute")
-@osc.cmdln.option('--set', action="store_true",
-                  help="Modify the set of enabled repositories, without this the current setup is displayed")
+@osc.cmdln.option('--recreate', action="store_true",
+                  help="Re-create the set of enabled repositories from the stored attributes on the server")
+@osc.cmdln.option('--compiler-modules', nargs=1,
+                  help="Restrict the set of compilers to use")
+@osc.cmdln.option('--mpi-modules', nargs=1,
+                  help="Restrict the set of MPI implementations to use")
+@osc.cmdln.option('--cuda-modules', nargs=1,
+                  help="Restrict the set of CUDA implementations to use")
+@osc.cmdln.option('--set', nargs=1, metavar="FLAGS",
+                  help="Modify the set of enabled repositories, without this the current setup is displayed. "
+                       "FLAGS is a comma-separated list of a subset of 'system', 'compilers', 'mpi', 'cuda_mpi'")
+@osc.cmdln.alias("mpcdf_enable_repos")
 def do_mpcdf_enable_repositories(self, subcmd, opts, *args):
     """${cmd_name}: Select all appropriate repositories for an MPCDF package
 
@@ -43,9 +40,9 @@ def do_mpcdf_enable_repositories(self, subcmd, opts, *args):
     troublesome compiler)
 
     Usage:
-        osc ${cmd_name}                 [[PROJECT] PACKAGE]
-        osc ${cmd_name} --set [ flags ] [[PROJECT] PACKAGE]
-        osc ${cmd_name} --reset         [[PROJECT] PACKAGE]
+        osc ${cmd_name}                       [[PROJECT] PACKAGE]
+        osc ${cmd_name} --set FLAGS [options] [[PROJECT] PACKAGE]
+        osc ${cmd_name} --recreate            [[PROJECT] PACKAGE]
 
     ${cmd_option_list}
     """
@@ -69,37 +66,23 @@ def do_mpcdf_enable_repositories(self, subcmd, opts, *args):
     api_url = self.get_api_url()
 
     if opts.set:
-        root = ElementTree.fromstringlist(osc.core.show_attribute_meta(api_url, project, package, None, "MPCDF:enable_repositories", False, False))
-
-        attribute = root.find("./attribute")
-        if attribute is None:
-            attribute = ElementTree.SubElement(root, "attribute")
-            attribute.set("namespace", "MPCDF")
-            attribute.set("name", "enable_repositories")
-
-        for value in attribute.findall("./value"):
-            attribute.remove(value)
-
-        def value(content):
-            v = ElementTree.SubElement(attribute, "value")
-            v.text = content
-
-        if opts.system:
-            value("system")
-        if opts.compilers:
-            value("compilers")
-        if opts.mpi:
-            value("mpi")
-        if opts.cuda:
-            value("cuda")
-        if opts.cuda_mpi:
-            value("cuda_mpi")
-
-        mpcdf_common.set_attribute(api_url, (project, package), root)
-
-    if opts.reset or opts.set:
+        mpcdf_common.set_attribute_values(api_url, project, package, "MPCDF:enable_repositories", opts.set.split(","))
+
+        def set_or_remove(flag, attribute_name):
+            if flag:
+                print("Setting attribute", attribute_name, "to", flag)
+                mpcdf_common.set_attribute_values(api_url, project, package, attribute_name, flag.split(","))
+            elif mpcdf_common.has_attribute(api_url, project, package, attribute_name):
+                print("Removing attribute", attribute_name, "from package")
+                mpcdf_common.remove_attribute(api_url, project, package, attribute_name)
+
+        set_or_remove(opts.mpi_modules,      "MPCDF:mpi_modules")
+        set_or_remove(opts.cuda_modules,     "MPCDF:cuda_modules")
+        set_or_remove(opts.compiler_modules, "MPCDF:compiler_modules")
+
+    if opts.recreate or opts.set:
         mpcdf_common.mpcdf_enable_repositories(api_url, project, package, verbose=True)
-    elif (opts.compilers or opts.mpi or opts.cuda or opts.cuda_mpi):
+    elif (opts.compiler_modules or opts.mpi_modules or opts.cuda_modules):
         print("ERROR: Invalid arguments, try --help")
     else:
         try:
@@ -108,4 +91,14 @@ def do_mpcdf_enable_repositories(self, subcmd, opts, *args):
             repos = ()
             print("ERRROR: No attribute MPCDF:enable_repositories present, package unmanaged")
         if repos:
+            def print_attr(description, attribute_name):
+                try:
+                    values = mpcdf_common.get_attribute_values(api_url, project, package, attribute_name)
+                except Exception:
+                    return
+                print(description, ", ".join(values))
+
             print("Enabled for:", *repos)
+            print_attr("Compilers modules acive:", "MPCDF:compiler_modules")
+            print_attr("MPI modules active:", "MPCDF:mpi_modules")
+            print_attr("CUDA modules active:", "MPCDF:cuda_modules")
-- 
GitLab