##// END OF EJS Templates
interfaces: convert `repository.imanifeststorage` from zope `Attribute` attrs...
interfaces: convert `repository.imanifeststorage` from zope `Attribute` attrs This is the same transformation as b455dfddfed0 did for dirstate.

File last commit:

r52756:f4733654 default
r53375:d01af74e default
Show More
configitems.py
215 lines | 6.7 KiB | text/x-python | PythonLexer
configitems: add a basic class to hold config item information...
r32983 # configitems.py - centralized declaration of configuration option
#
# Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
configitems: add a basic class to hold config item information...
r32983
configitems: extract the logic to build a registrar on any configtable...
r33126 import functools
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 import re
configitems: extract the logic to build a registrar on any configtable...
r33126
Raphaël Gomès
configitems: declare items in a TOML file...
r51655 from .utils import resourceutil
configitems: introduce a central registry for config option...
r32984 from . import (
Boris Feld
configitems: register the 'web.encoding' config
r34236 encoding,
configitems: introduce a central registry for config option...
r32984 error,
)
Raphaël Gomès
configitems: declare items in a TOML file...
r51655 try:
import tomllib # pytype: disable=import-error
tomllib.load # trigger lazy import
except ModuleNotFoundError:
# Python <3.11 compat
from .thirdparty import tomli as tomllib
Augie Fackler
formatting: blacken the codebase...
r43346
configitems: add an official API for extensions to register config item...
r33127 def loadconfigtable(ui, extname, configtable):
"""update config item known to the ui with the extension ones"""
Gregory Szorc
configitems: traverse sections deterministically...
r35826 for section, items in sorted(configtable.items()):
Boris Feld
configitems: fix registration of extensions config...
r34769 knownitems = ui._knownconfig.setdefault(section, itemregister())
configitems: add a devel warning for extensions items overiding core one...
r33128 knownkeys = set(knownitems)
newkeys = set(items)
for key in sorted(knownkeys & newkeys):
Raphaël Gomès
configitems: fix typo in devel warning about extension overrides
r51651 msg = b"extension '%s' overwrites config item '%s.%s'"
configitems: add a devel warning for extensions items overiding core one...
r33128 msg %= (extname, section, key)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.develwarn(msg, config=b'warn-config')
configitems: add a devel warning for extensions items overiding core one...
r33128
knownitems.update(items)
configitems: add an official API for extensions to register config item...
r33127
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class configitem:
configitems: add a basic class to hold config item information...
r32983 """represent a known config item
:section: the official config section where to find this item,
:name: the official name within the section,
:default: default value for this item,
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 :alias: optional list of tuples as alternatives,
:generic: this is a generic definition, match name using regular expression.
configitems: add a basic class to hold config item information...
r32983 """
Augie Fackler
formatting: blacken the codebase...
r43346 def __init__(
self,
section,
name,
default=None,
alias=(),
generic=False,
priority=0,
experimental=False,
Raphaël Gomès
configitems: add `documentation` field...
r51653 documentation="",
Raphaël Gomès
configitems: move blackbox's config items to the new configitems.toml...
r51658 in_core_extension=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
configitems: add a basic class to hold config item information...
r32983 self.section = section
self.name = name
self.default = default
Raphaël Gomès
configitems: add `documentation` field...
r51653 self.documentation = documentation
David Demelier
configitems: add alias support in config...
r33329 self.alias = list(alias)
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 self.generic = generic
self.priority = priority
Navaneeth Suresh
config: add experimental argument to the config registrar...
r43028 self.experimental = experimental
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 self._re = None
Raphaël Gomès
configitems: move blackbox's config items to the new configitems.toml...
r51658 self.in_core_extension = in_core_extension
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 if generic:
self._re = re.compile(self.name)
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 class itemregister(dict):
"""A specialized dictionary that can handle wild-card selection"""
def __init__(self):
super(itemregister, self).__init__()
self._generics = set()
pytype: ignore some signature mismatch in configitems...
r52185 def update(self, other): # pytype: disable=signature-mismatch
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 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):
Boris Feld
configitems: do not directly match generic items...
r34875 baseitem = super(itemregister, self).get(key)
if baseitem is not None and not baseitem.generic:
return baseitem
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663
# search for a matching generic item
generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
for item in generics:
Boris Feld
configitems: document the choice of using 'match' instead of 'search'
r34876 # we use 'match' instead of 'search' to make the matching simpler
# for people unfamiliar with regular expression. Having the match
# rooted to the start of the string will produce less surprising
# result for user writing simple regex for sub-attribute.
#
# For example using "color\..*" match produces an unsurprising
# result, while using search could suddenly match apparently
# unrelated configuration that happens to contains "color."
# anywhere. This is a tradeoff where we favor requiring ".*" on
# some match to avoid the need to prefix most pattern with "^".
# The "^" seems more error prone.
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 if item._re.match(key):
return item
Boris Feld
configitems: do not directly match generic items...
r34875 return None
configitems: introduce a central registry for config option...
r32984
Augie Fackler
formatting: blacken the codebase...
r43346
Raphaël Gomès
configitems: declare items in a TOML file...
r51655 def sanitize_item(item):
"""Apply the transformations that are encoded on top of the pure data"""
# Set the special defaults
default_type_key = "default-type"
default_type = item.pop(default_type_key, None)
if default_type == "dynamic":
item["default"] = dynamicdefault
elif default_type == "list_type":
item["default"] = list
elif default_type == "lambda":
assert isinstance(item["default"], list)
default = [e.encode() for e in item["default"]]
item["default"] = lambda: default
elif default_type == "lazy_module":
item["default"] = lambda: encoding.encoding
else:
if default_type is not None:
msg = "invalid default config type %r for '%s.%s'"
msg %= (default_type, item["section"], item["name"])
raise error.ProgrammingError(msg)
# config expects bytes
alias = item.get("alias")
if alias:
item["alias"] = [(k.encode(), v.encode()) for (k, v) in alias]
if isinstance(item.get("default"), str):
item["default"] = item["default"].encode()
item["section"] = item["section"].encode()
item["name"] = item["name"].encode()
def read_configitems_file():
"""Returns the deserialized TOML structure from the configitems file"""
with resourceutil.open_resource(b"mercurial", b"configitems.toml") as fp:
return tomllib.load(fp)
def configitems_from_toml(items):
"""Register the configitems from the *deserialized* toml file"""
for item in items["items"]:
sanitize_item(item)
coreconfigitem(**item)
templates = items["templates"]
for application in items["template-applications"]:
template_items = templates[application["template"]]
for template_item in template_items:
item = template_item.copy()
prefix = application.get("prefix", "")
item["section"] = application["section"]
if prefix:
item["name"] = f'{prefix}.{item["suffix"]}'
else:
item["name"] = item["suffix"]
sanitize_item(item)
item.pop("suffix", None)
coreconfigitem(**item)
def import_configitems_from_file():
as_toml = read_configitems_file()
configitems_from_toml(as_toml)
configitems: introduce a central registry for config option...
r32984 coreitems = {}
Augie Fackler
formatting: blacken the codebase...
r43346
configitems: extract the logic to build a registrar on any configtable...
r33126 def _register(configtable, *args, **kwargs):
configitems: introduce a central registry for config option...
r32984 item = configitem(*args, **kwargs)
Boris Feld
configitems: allow for the registration of "generic" config item...
r34663 section = configtable.setdefault(item.section, itemregister())
configitems: introduce a central registry for config option...
r32984 if item.name in section:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b"duplicated config item registration for '%s.%s'"
configitems: introduce a central registry for config option...
r32984 raise error.ProgrammingError(msg % (item.section, item.name))
section[item.name] = item
configitems: register 'ui.quiet' as first example...
r32986
Augie Fackler
formatting: blacken the codebase...
r43346
Boris Feld
configitems: handle case were the default value is not static...
r33471 # special value for case where the default is derived from other values
dynamicdefault = object()
configitems: register 'ui.quiet' as first example...
r32986 # Registering actual config items
Augie Fackler
formatting: blacken the codebase...
r43346
configitems: extract the logic to build a registrar on any configtable...
r33126 def getitemregister(configtable):
Yuya Nishihara
registrar: host "dynamicdefault" constant by configitem object...
r34918 f = functools.partial(_register, configtable)
# export pseudo enum as configitem.*
f.dynamicdefault = dynamicdefault
return f
configitems: extract the logic to build a registrar on any configtable...
r33126
Augie Fackler
formatting: blacken the codebase...
r43346
configitems: extract the logic to build a registrar on any configtable...
r33126 coreconfigitem = getitemregister(coreitems)
Raphaël Gomès
configitems: declare items in a TOML file...
r51655 import_configitems_from_file()