configitems: allow for the registration of "generic" config item
authorBoris Feld <boris.feld@octobus.net>
Tue, 10 Oct 2017 10:49:15 +0200
changeset 34662 181d913b17e6
parent 34661 eb586ed5d8ce
child 34663 6de7842290b2
configitems: allow for the registration of "generic" config item Some section can contains arbitrary keys (eg: color, alias, extensions). We add a way to register some generic config items for them. This is necessary to get all the config registered. We use a regular expression because some sub- attributes (eg: hooks.xxx.priority) can define default value on their own.
mercurial/configitems.py
--- a/mercurial/configitems.py	Thu Oct 12 09:39:50 2017 +0200
+++ b/mercurial/configitems.py	Tue Oct 10 10:49:15 2017 +0200
@@ -8,6 +8,7 @@
 from __future__ import absolute_import
 
 import functools
+import re
 
 from . import (
     encoding,
@@ -33,20 +34,56 @@
     :section: the official config section where to find this item,
        :name: the official name within the section,
     :default: default value for this item,
-    :alias: optional list of tuples as alternatives.
+    :alias: optional list of tuples as alternatives,
+    :generic: this is a generic definition, match name using regular expression.
     """
 
-    def __init__(self, section, name, default=None, alias=()):
+    def __init__(self, section, name, default=None, alias=(),
+                 generic=False, priority=0):
         self.section = section
         self.name = name
         self.default = default
         self.alias = list(alias)
+        self.generic = generic
+        self.priority = priority
+        self._re = None
+        if generic:
+            self._re = re.compile(self.name)
+
+class itemregister(dict):
+    """A specialized dictionary that can handle wild-card selection"""
+
+    def __init__(self):
+        super(itemregister, self).__init__()
+        self._generics = set()
+
+    def update(self, other):
+        super(itemregister, self).update(other)
+        self._generics.update(other._generics)
+
+    def __setitem__(self, key, item):
+        super(itemregister, self).__setitem__(key, item)
+        if item.generic:
+            self._generics.add(item)
+
+    def get(self, key):
+        if key in self:
+            return self[key]
+
+        # search for a matching generic item
+        generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
+        for item in generics:
+            if item._re.match(key):
+                return item
+
+        # fallback to dict get
+        return super(itemregister, self).get(key)
 
 coreitems = {}
 
 def _register(configtable, *args, **kwargs):
     item = configitem(*args, **kwargs)
-    section = configtable.setdefault(item.section, {})
+    section = configtable.setdefault(item.section, itemregister())
     if item.name in section:
         msg = "duplicated config item registration for '%s.%s'"
         raise error.ProgrammingError(msg % (item.section, item.name))