[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