Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/config.py @ 46661:a3dced4b7b04
config: track the "level" of a value
Config value now remember the "level" of the config that loaded it. This will be
used to ensure good priority management for alias.
Differential Revision: https://phab.mercurial-scm.org/D9926
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Fri, 29 Jan 2021 11:21:49 +0100 |
parents | d3df397e7a59 |
children | d4ba4d51f85f |
comparison
equal
deleted
inserted
replaced
46660:d3df397e7a59 | 46661:a3dced4b7b04 |
---|---|
20 ) | 20 ) |
21 | 21 |
22 | 22 |
23 class config(object): | 23 class config(object): |
24 def __init__(self, data=None): | 24 def __init__(self, data=None): |
25 self._current_source_level = 0 | |
25 self._data = {} | 26 self._data = {} |
26 self._unset = [] | 27 self._unset = [] |
27 if data: | 28 if data: |
28 for k in data._data: | 29 for k in data._data: |
29 self._data[k] = data[k].copy() | 30 self._data[k] = data[k].copy() |
31 self._current_source_level = data._current_source_level + 1 | |
32 | |
33 def new_source(self): | |
34 """increment the source counter | |
35 | |
36 This is used to define source priority when reading""" | |
37 self._current_source_level += 1 | |
30 | 38 |
31 def copy(self): | 39 def copy(self): |
32 return config(self) | 40 return config(self) |
33 | 41 |
34 def __contains__(self, section): | 42 def __contains__(self, section): |
43 def __iter__(self): | 51 def __iter__(self): |
44 for d in self.sections(): | 52 for d in self.sections(): |
45 yield d | 53 yield d |
46 | 54 |
47 def update(self, src): | 55 def update(self, src): |
56 current_level = self._current_source_level | |
57 current_level += 1 | |
58 max_level = self._current_source_level | |
48 for s, n in src._unset: | 59 for s, n in src._unset: |
49 ds = self._data.get(s, None) | 60 ds = self._data.get(s, None) |
50 if ds is not None and n in ds: | 61 if ds is not None and n in ds: |
51 self._data[s] = ds.preparewrite() | 62 self._data[s] = ds.preparewrite() |
52 del self._data[s][n] | 63 del self._data[s][n] |
54 ds = self._data.get(s, None) | 65 ds = self._data.get(s, None) |
55 if ds: | 66 if ds: |
56 self._data[s] = ds.preparewrite() | 67 self._data[s] = ds.preparewrite() |
57 else: | 68 else: |
58 self._data[s] = util.cowsortdict() | 69 self._data[s] = util.cowsortdict() |
59 self._data[s].update(src._data[s]) | 70 for k, v in src._data[s].items(): |
71 value, source, level = v | |
72 level += current_level | |
73 max_level = max(level, current_level) | |
74 self._data[s][k] = (value, source, level) | |
75 self._current_source_level = max_level | |
60 | 76 |
61 def _get(self, section, item): | 77 def _get(self, section, item): |
62 return self._data.get(section, {}).get(item) | 78 return self._data.get(section, {}).get(item) |
63 | 79 |
64 def get(self, section, item, default=None): | 80 def get(self, section, item, default=None): |
83 result = self._get(section, item) | 99 result = self._get(section, item) |
84 if result is None: | 100 if result is None: |
85 return b"" | 101 return b"" |
86 return result[1] | 102 return result[1] |
87 | 103 |
104 def level(self, section, item): | |
105 result = self._get(section, item) | |
106 if result is None: | |
107 return None | |
108 return result[2] | |
109 | |
88 def sections(self): | 110 def sections(self): |
89 return sorted(self._data.keys()) | 111 return sorted(self._data.keys()) |
90 | 112 |
91 def items(self, section): | 113 def items(self, section): |
92 items = pycompat.iteritems(self._data.get(section, {})) | 114 items = pycompat.iteritems(self._data.get(section, {})) |
93 return [(k, v) for (k, (v, s)) in items] | 115 return [(k, v[0]) for (k, v) in items] |
94 | 116 |
95 def set(self, section, item, value, source=b""): | 117 def set(self, section, item, value, source=b""): |
96 if pycompat.ispy3: | 118 if pycompat.ispy3: |
97 assert not isinstance( | 119 assert not isinstance( |
98 section, str | 120 section, str |
105 ), b'config values may not be unicode strings on Python 3' | 127 ), b'config values may not be unicode strings on Python 3' |
106 if section not in self: | 128 if section not in self: |
107 self._data[section] = util.cowsortdict() | 129 self._data[section] = util.cowsortdict() |
108 else: | 130 else: |
109 self._data[section] = self._data[section].preparewrite() | 131 self._data[section] = self._data[section].preparewrite() |
110 self._data[section][item] = (value, source) | 132 self._data[section][item] = (value, source, self._current_source_level) |
111 | 133 |
112 def alter(self, section, key, new_value): | 134 def alter(self, section, key, new_value): |
113 """alter a value without altering its source or level | 135 """alter a value without altering its source or level |
114 | 136 |
115 This method is meant to be used by `ui.fixconfig` only.""" | 137 This method is meant to be used by `ui.fixconfig` only.""" |
213 if l.startswith(b' '): | 235 if l.startswith(b' '): |
214 message = b"unexpected leading whitespace: %s" % message | 236 message = b"unexpected leading whitespace: %s" % message |
215 raise error.ConfigError(message, (b"%s:%d" % (src, line))) | 237 raise error.ConfigError(message, (b"%s:%d" % (src, line))) |
216 | 238 |
217 def read(self, path, fp=None, sections=None, remap=None): | 239 def read(self, path, fp=None, sections=None, remap=None): |
240 self.new_source() | |
218 if not fp: | 241 if not fp: |
219 fp = util.posixfile(path, b'rb') | 242 fp = util.posixfile(path, b'rb') |
220 assert ( | 243 assert ( |
221 getattr(fp, 'mode', 'rb') == 'rb' | 244 getattr(fp, 'mode', 'rb') == 'rb' |
222 ), b'config files must be opened in binary mode, got fp=%r mode=%r' % ( | 245 ), b'config files must be opened in binary mode, got fp=%r mode=%r' % ( |
227 dir = os.path.dirname(path) | 250 dir = os.path.dirname(path) |
228 | 251 |
229 def include(rel, remap, sections): | 252 def include(rel, remap, sections): |
230 abs = os.path.normpath(os.path.join(dir, rel)) | 253 abs = os.path.normpath(os.path.join(dir, rel)) |
231 self.read(abs, remap=remap, sections=sections) | 254 self.read(abs, remap=remap, sections=sections) |
255 # anything after the include has a higher level | |
256 self.new_source() | |
232 | 257 |
233 self.parse( | 258 self.parse( |
234 path, fp.read(), sections=sections, remap=remap, include=include | 259 path, fp.read(), sections=sections, remap=remap, include=include |
235 ) | 260 ) |
236 | 261 |