Patchwork [01,of,11] configitems: allow for the registration of "generic" config item

login
register
mail settings
Submitter Boris Feld
Date Oct. 13, 2017, 5:55 p.m.
Message ID <429c6e9c7c3a4f601db1.1507917307@FB>
Download mbox | patch
Permalink /patch/24840/
State Accepted
Headers show

Comments

Boris Feld - Oct. 13, 2017, 5:55 p.m.
# HG changeset patch
# User Boris Feld <boris.feld@octobus.net>
# Date 1507625355 -7200
#      Tue Oct 10 10:49:15 2017 +0200
# Node ID 429c6e9c7c3a4f601db17c6553a8fcdad35708a8
# Parent  37b4375b1221e3bda055f0cbecf06b3c9510fd2c
# EXP-Topic config.register.ready
# Available At https://bitbucket.org/octobus/mercurial-devel/
#              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 429c6e9c7c3a
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.
Yuya Nishihara - Oct. 14, 2017, 5:50 a.m.
On Fri, 13 Oct 2017 19:55:07 +0200, Boris Feld wrote:
> # HG changeset patch
> # User Boris Feld <boris.feld@octobus.net>
> # Date 1507625355 -7200
> #      Tue Oct 10 10:49:15 2017 +0200
> # Node ID 429c6e9c7c3a4f601db17c6553a8fcdad35708a8
> # Parent  37b4375b1221e3bda055f0cbecf06b3c9510fd2c
> # EXP-Topic config.register.ready
> # Available At https://bitbucket.org/octobus/mercurial-devel/
> #              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 429c6e9c7c3a
> configitems: allow for the registration of "generic" config item

> diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> --- a/mercurial/configitems.py
> +++ b/mercurial/configitems.py
> @@ -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)

Why is a generic item added to the dict too?
Yuya Nishihara - Oct. 15, 2017, 3:57 a.m.
On Sat, 14 Oct 2017 14:50:00 +0900, Yuya Nishihara wrote:
> On Fri, 13 Oct 2017 19:55:07 +0200, Boris Feld wrote:
> > # HG changeset patch
> > # User Boris Feld <boris.feld@octobus.net>
> > # Date 1507625355 -7200
> > #      Tue Oct 10 10:49:15 2017 +0200
> > # Node ID 429c6e9c7c3a4f601db17c6553a8fcdad35708a8
> > # Parent  37b4375b1221e3bda055f0cbecf06b3c9510fd2c
> > # EXP-Topic config.register.ready
> > # Available At https://bitbucket.org/octobus/mercurial-devel/
> > #              hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 429c6e9c7c3a
> > configitems: allow for the registration of "generic" config item
> 
> > diff --git a/mercurial/configitems.py b/mercurial/configitems.py
> > --- a/mercurial/configitems.py
> > +++ b/mercurial/configitems.py
> > @@ -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)
> 
> Why is a generic item added to the dict too?

More details: a generic item having pattern r'foo$' matches a literal 'foo$',
which seems wrong.

Patch

diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -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))