Allow multiple QA patches
authorHrvoje Ribicic <riba@google.com>
Tue, 18 Mar 2014 20:25:18 +0000 (20:25 +0000)
committerHrvoje Ribicic <riba@google.com>
Wed, 19 Mar 2014 18:32:04 +0000 (19:32 +0100)
This patch allows support for multiple patches placed in the "patch"
directory, which are executed in alphabetical order.

Signed-off-by: Hrvoje Ribicic <riba@google.com>
Reviewed-by: Michele Tartara <mtartara@google.com>

qa/qa_config.py

index e068213..2bf0ac6 100644 (file)
@@ -40,10 +40,11 @@ _VCLUSTER_MASTER_KEY = "vcluster-master"
 _VCLUSTER_BASEDIR_KEY = "vcluster-basedir"
 _ENABLED_DISK_TEMPLATES_KEY = "enabled-disk-templates"
 
-# The path of an optional JSON Patch file (as per RFC6902) that modifies QA's
+# The constants related to JSON patching (as per RFC6902) that modifies QA's
 # configuration.
 _QA_BASE_PATH = os.path.dirname(__file__)
 _QA_DEFAULT_PATCH = "qa-patch.json"
+_QA_PATCH_DIR = "patch"
 
 #: QA configuration (L{_QaConfig})
 _config = None
@@ -284,8 +285,39 @@ class _QaConfig(object):
     """
     patches = {}
     _QaConfig.LoadPatch(patches, _QA_DEFAULT_PATCH)
+    patch_dir_path = os.path.join(_QA_BASE_PATH, _QA_PATCH_DIR)
+    if os.path.exists(patch_dir_path):
+      for filename in os.listdir(patch_dir_path):
+        if filename.endswith(".json"):
+          _QaConfig.LoadPatch(patches, os.path.join(_QA_PATCH_DIR, filename))
     return patches
 
+  @staticmethod
+  def ApplyPatches(data, patch_module, patches):
+    """Applies any patches present, and returns the modified QA configuration.
+
+    First, patches from the patch directory are applied, ordered alphabetically
+    by name.
+
+    @type data: dict (deserialized json)
+    @param data: The QA configuration
+    @type patch_module: module
+    @param patch_module: The json patch module, loaded dynamically
+    @type patches: dict of string to dict
+    @param patches: The dictionary of patch path to content
+
+    @return: The modified configuration data.
+
+    """
+    for patch in sorted(patches):
+      if patch != _QA_DEFAULT_PATCH:
+        data = patch_module.apply_patch(data, patches[patch])
+
+    if _QA_DEFAULT_PATCH in patches:
+      data = patch_module.apply_patch(data, patches[_QA_DEFAULT_PATCH])
+
+    return data
+
   @classmethod
   def Load(cls, filename):
     """Loads a configuration file and produces a configuration object.
@@ -303,9 +335,7 @@ class _QaConfig(object):
       patches = _QaConfig.LoadPatches()
       if patches:
         mod = __import__("jsonpatch", fromlist=[])
-        # TODO: only one patch, the default one, is supported at the moment.
-        # If patches is not empty, it is within. Later changes will remedy this.
-        data = mod.apply_patch(data, patches[_QA_DEFAULT_PATCH])
+        data = _QaConfig.ApplyPatches(data, mod, patches)
     except IOError:
       pass
     except ImportError: