mercurial/config.py
changeset 46622 a3dced4b7b04
parent 46621 d3df397e7a59
child 46819 d4ba4d51f85f
equal deleted inserted replaced
46621:d3df397e7a59 46622: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