[2,of,2,RFC] RFC: switch to immutable configs

David Soria Parra dsp at experimentalworks.net
Wed Mar 29 18:56:21 EDT 2017


On Mon, Mar 27, 2017 at 11:38:07AM -0700, Jun Wu wrote:
> # HG changeset patch
> # User Jun Wu <quark at fb.com>
> # Date 1490639836 25200
> #      Mon Mar 27 11:37:16 2017 -0700
> # Node ID 13bee3e959f04f970f2fc0a01120f0b30d725b84
> # Parent  4eb7c76340791f379a34f9df4ec42e0c8b9b2a2f
> RFC: switch to immutable configs

I personally like the overall direction
> +def _filterconfig(subconfig):
> +    '''remove configs according to HGPLAIN and HGPLAINEXCEPT
> +
> +    subconfig is an immutable config object. Returns an immutable config object
> +    with related fields filtered.
> +    '''
> +    filters = {}
> +    if _isplain():
> +        def filterui(items):
> +            result = util.sortdict(items)
> +            for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
> +                      'logtemplate', 'statuscopies', 'style',
> +                      'traceback', 'verbose'):
> +                if k in result:
> +                    del result[k]
> +            return result
> +
> +        filters['ui'] = filterui
> +        filters['defaults'] = {}
> +    if _isplain('alias'):
> +        filters['alias'] = {}
> +    if _isplain('revsetalias'):
> +        filters['revsetalias'] = {}
> +    if _isplain('templatealias'):
> +        filters['templatealias'] = {}
> +    if _isplain('commands'):
> +        filters['commands'] = {}
> +
> +    if filters:
> +        return config.filteredconfig('filter', subconfig, filters)
> +    else:
> +        return subconfig
> +
> +def _getconfig(configroot, section, name, default=None, index=0):
> +    '''get value (index=0) or source (index=-1) from an immutable config'''
> +    value = configroot.getsection(section).get(name, (None,))[index]
> +    if value is None:
> +        value = default
> +    return value
> +
> +def _buildconfigroot(cfg, ocfg, gcfg):
> +    return config.mergedconfig('root', [cfg, ocfg, gcfg])
> +
> +def dependson(*fields):
> +    '''cache result which gets invalidates if any field changes'''
> +
> +    def decorator(oldfunc):
> +        cached = [[None], None] # cache key, result
> +        def getcachekey(self):
> +            return [getattr(self, f, None) for f in fields]
> +
> +        def newfunc(self):
> +            newkey = getcachekey(self)
> +            oldkey = cached[0]
> +            if oldkey == newkey:
> +                return cached[1]
> +            result = oldfunc(self)
> +            cached[:] = [newkey, result]
> +            return result
> +        newfunc.__name__ = oldfunc.__name__
> +        newfunc.__doc__ = oldfunc.__doc__
> +        return newfunc
> +    return decorator
> +
>  class ui(object):
>      def __init__(self, src=None):
> @@ -146,16 +257,7 @@ class ui(object):
>          # This exists to prevent an extra list lookup.
>          self._bufferapplylabels = None
> -        self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
> -        self._reportuntrusted = True
> -        self._ocfg = config.config() # overlay
> -        self._tcfg = config.config() # trusted
> -        self._ucfg = config.config() # untrusted
> -        self._trustusers = set()
> -        self._trustgroups = set()
>          self.callhooks = True
>          # Insecure server connections requested.
>          self.insecureconnections = False
> -        # Blocked time
> -        self.logblockedtimes = False
>          # color mode: see mercurial/color.py for possible value
>          self._colormode = None
> @@ -170,9 +272,9 @@ class ui(object):
>              self._disablepager = src._disablepager
>  
> -            self._tcfg = src._tcfg.copy()
> -            self._ucfg = src._ucfg.copy()
> -            self._ocfg = src._ocfg.copy()
> -            self._trustusers = src._trustusers.copy()
> -            self._trustgroups = src._trustgroups.copy()
> +            # immutable configs can be reused without copying
> +            self._ocfgs = src._ocfgs
> +            self._tcfgs = src._tcfgs
> +            self._ucfgs = src._ucfgs
> +
>              self.environ = src.environ
>              self.callhooks = src.callhooks
> @@ -182,6 +284,4 @@ class ui(object):
>              self._styles = src._styles.copy()
>  
> -            self.fixconfig()
> -
>              self.httppasswordmgrdb = src.httppasswordmgrdb
>              self._blockedtimes = src._blockedtimes
> @@ -199,4 +299,9 @@ class ui(object):
>              self._blockedtimes = collections.defaultdict(int)
>  
> +            # immutable configs
> +            self._ocfgs = config.mergedconfig('setconfig', []) # overlay
> +            self._tcfgs = config.mergedconfig('loaded', []) # trusted
i would probably actually call them 'trusted' instead of 'loaded'
> +            self._ucfgs = config.mergedconfig('loaded', []) # trusted+untrusted
with merge configs in, we would split up trusted+untrusted into trusted and
untrusted?

> +    def setconfig(self, section, name, value, source='', priority=None):
I think we can do better by using the title, e.g. 'untrusted', 'setconfig' to
access the right layer. a numeric priority seems to be very hard to use and I
think we could improve this interface a bit.
> +        title = source or 'setconfig'
> +        acfg = config.atomicconfig(title, [(section, name, (value, source))])
> +        try:
> +            cwd = pycompat.getcwd()
> +        except OSError:
> +            pass
> +        else:
> +            acfg = _fixpathsection(acfg, cwd)
> +        if priority == 3:
> +            # global overlay
> +            self.__class__._gcfgs = self.__class__._gcfgs.append(acfg)
> +        elif priority == 2:
> +            # change overlay in this ui
> +            self._ocfgs = self._ocfgs.append(acfg)
> +        elif priority == 1:
> +            # change overlay in this ui, do not override existing overlays
> +            self._ocfgs = self._ocfgs.prepend(acfg)
> +        else:
> +            self._tcfgs = self._tcfgs.append(acfg)
> +            self._ucfgs = self._ucfgs.append(acfg)
>  


More information about the Mercurial-devel mailing list