##// END OF EJS Templates
config: remove pycompat.iteritems()...
Gregory Szorc -
r49775:b4ab4fd2 default
parent child Browse files
Show More
@@ -1,258 +1,257 b''
1 1 # config.py - configuration parsing for Mercurial
2 2 #
3 3 # Copyright 2009 Olivia Mackall <olivia@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import errno
10 10 import os
11 11
12 12 from .i18n import _
13 13 from .pycompat import getattr
14 14 from . import (
15 15 encoding,
16 16 error,
17 pycompat,
18 17 util,
19 18 )
20 19
21 20
22 21 class config(object):
23 22 def __init__(self, data=None):
24 23 self._current_source_level = 0
25 24 self._data = {}
26 25 self._unset = []
27 26 if data:
28 27 for k in data._data:
29 28 self._data[k] = data[k].copy()
30 29 self._current_source_level = data._current_source_level + 1
31 30
32 31 def new_source(self):
33 32 """increment the source counter
34 33
35 34 This is used to define source priority when reading"""
36 35 self._current_source_level += 1
37 36
38 37 def copy(self):
39 38 return config(self)
40 39
41 40 def __contains__(self, section):
42 41 return section in self._data
43 42
44 43 def hasitem(self, section, item):
45 44 return item in self._data.get(section, {})
46 45
47 46 def __getitem__(self, section):
48 47 return self._data.get(section, {})
49 48
50 49 def __iter__(self):
51 50 for d in self.sections():
52 51 yield d
53 52
54 53 def update(self, src):
55 54 current_level = self._current_source_level
56 55 current_level += 1
57 56 max_level = self._current_source_level
58 57 for s, n in src._unset:
59 58 ds = self._data.get(s, None)
60 59 if ds is not None and n in ds:
61 60 self._data[s] = ds.preparewrite()
62 61 del self._data[s][n]
63 62 for s in src:
64 63 ds = self._data.get(s, None)
65 64 if ds:
66 65 self._data[s] = ds.preparewrite()
67 66 else:
68 67 self._data[s] = util.cowsortdict()
69 68 for k, v in src._data[s].items():
70 69 value, source, level = v
71 70 level += current_level
72 71 max_level = max(level, current_level)
73 72 self._data[s][k] = (value, source, level)
74 73 self._current_source_level = max_level
75 74
76 75 def _get(self, section, item):
77 76 return self._data.get(section, {}).get(item)
78 77
79 78 def get(self, section, item, default=None):
80 79 result = self._get(section, item)
81 80 if result is None:
82 81 return default
83 82 return result[0]
84 83
85 84 def backup(self, section, key):
86 85 """return a tuple allowing restore to reinstall a previous value
87 86
88 87 The main reason we need it is because it handles the "no data" case.
89 88 """
90 89 try:
91 90 item = self._data[section][key]
92 91 except KeyError:
93 92 return (section, key)
94 93 else:
95 94 return (section, key) + item
96 95
97 96 def source(self, section, item):
98 97 result = self._get(section, item)
99 98 if result is None:
100 99 return b""
101 100 return result[1]
102 101
103 102 def level(self, section, item):
104 103 result = self._get(section, item)
105 104 if result is None:
106 105 return None
107 106 return result[2]
108 107
109 108 def sections(self):
110 109 return sorted(self._data.keys())
111 110
112 111 def items(self, section):
113 items = pycompat.iteritems(self._data.get(section, {}))
112 items = self._data.get(section, {}).items()
114 113 return [(k, v[0]) for (k, v) in items]
115 114
116 115 def set(self, section, item, value, source=b""):
117 116 assert not isinstance(
118 117 section, str
119 118 ), b'config section may not be unicode strings on Python 3'
120 119 assert not isinstance(
121 120 item, str
122 121 ), b'config item may not be unicode strings on Python 3'
123 122 assert not isinstance(
124 123 value, str
125 124 ), b'config values may not be unicode strings on Python 3'
126 125 if section not in self:
127 126 self._data[section] = util.cowsortdict()
128 127 else:
129 128 self._data[section] = self._data[section].preparewrite()
130 129 self._data[section][item] = (value, source, self._current_source_level)
131 130
132 131 def alter(self, section, key, new_value):
133 132 """alter a value without altering its source or level
134 133
135 134 This method is meant to be used by `ui.fixconfig` only."""
136 135 item = self._data[section][key]
137 136 size = len(item)
138 137 new_item = (new_value,) + item[1:]
139 138 assert len(new_item) == size
140 139 self._data[section][key] = new_item
141 140
142 141 def restore(self, data):
143 142 """restore data returned by self.backup"""
144 143 if len(data) != 2:
145 144 # restore old data
146 145 section, key = data[:2]
147 146 item = data[2:]
148 147 self._data[section] = self._data[section].preparewrite()
149 148 self._data[section][key] = item
150 149 else:
151 150 # no data before, remove everything
152 151 section, item = data
153 152 if section in self._data:
154 153 self._data[section].pop(item, None)
155 154
156 155 def parse(self, src, data, sections=None, remap=None, include=None):
157 156 sectionre = util.re.compile(br'\[([^\[]+)\]')
158 157 itemre = util.re.compile(br'([^=\s][^=]*?)\s*=\s*(.*\S|)')
159 158 contre = util.re.compile(br'\s+(\S|\S.*\S)\s*$')
160 159 emptyre = util.re.compile(br'(;|#|\s*$)')
161 160 commentre = util.re.compile(br'(;|#)')
162 161 unsetre = util.re.compile(br'%unset\s+(\S+)')
163 162 includere = util.re.compile(br'%include\s+(\S|\S.*\S)\s*$')
164 163 section = b""
165 164 item = None
166 165 line = 0
167 166 cont = False
168 167
169 168 if remap:
170 169 section = remap.get(section, section)
171 170
172 171 for l in data.splitlines(True):
173 172 line += 1
174 173 if line == 1 and l.startswith(b'\xef\xbb\xbf'):
175 174 # Someone set us up the BOM
176 175 l = l[3:]
177 176 if cont:
178 177 if commentre.match(l):
179 178 continue
180 179 m = contre.match(l)
181 180 if m:
182 181 if sections and section not in sections:
183 182 continue
184 183 v = self.get(section, item) + b"\n" + m.group(1)
185 184 self.set(section, item, v, b"%s:%d" % (src, line))
186 185 continue
187 186 item = None
188 187 cont = False
189 188 m = includere.match(l)
190 189
191 190 if m and include:
192 191 expanded = util.expandpath(m.group(1))
193 192 try:
194 193 include(expanded, remap=remap, sections=sections)
195 194 except IOError as inst:
196 195 if inst.errno != errno.ENOENT:
197 196 raise error.ConfigError(
198 197 _(b"cannot include %s (%s)")
199 198 % (expanded, encoding.strtolocal(inst.strerror)),
200 199 b"%s:%d" % (src, line),
201 200 )
202 201 continue
203 202 if emptyre.match(l):
204 203 continue
205 204 m = sectionre.match(l)
206 205 if m:
207 206 section = m.group(1)
208 207 if remap:
209 208 section = remap.get(section, section)
210 209 if section not in self:
211 210 self._data[section] = util.cowsortdict()
212 211 continue
213 212 m = itemre.match(l)
214 213 if m:
215 214 item = m.group(1)
216 215 cont = True
217 216 if sections and section not in sections:
218 217 continue
219 218 self.set(section, item, m.group(2), b"%s:%d" % (src, line))
220 219 continue
221 220 m = unsetre.match(l)
222 221 if m:
223 222 name = m.group(1)
224 223 if sections and section not in sections:
225 224 continue
226 225 if self.get(section, name) is not None:
227 226 self._data[section] = self._data[section].preparewrite()
228 227 del self._data[section][name]
229 228 self._unset.append((section, name))
230 229 continue
231 230
232 231 message = l.rstrip()
233 232 if l.startswith(b' '):
234 233 message = b"unexpected leading whitespace: %s" % message
235 234 raise error.ConfigError(message, (b"%s:%d" % (src, line)))
236 235
237 236 def read(self, path, fp=None, sections=None, remap=None):
238 237 self.new_source()
239 238 if not fp:
240 239 fp = util.posixfile(path, b'rb')
241 240 assert (
242 241 getattr(fp, 'mode', 'rb') == 'rb'
243 242 ), b'config files must be opened in binary mode, got fp=%r mode=%r' % (
244 243 fp,
245 244 fp.mode,
246 245 )
247 246
248 247 dir = os.path.dirname(path)
249 248
250 249 def include(rel, remap, sections):
251 250 abs = os.path.normpath(os.path.join(dir, rel))
252 251 self.read(abs, remap=remap, sections=sections)
253 252 # anything after the include has a higher level
254 253 self.new_source()
255 254
256 255 self.parse(
257 256 path, fp.read(), sections=sections, remap=remap, include=include
258 257 )
General Comments 0
You need to be logged in to leave comments. Login now