Mercurial > hg
comparison mercurial/config.py @ 31481:a7c687c35119
ui: move configlist parser to config.py
The list parser is complex and reusable without ui. Let's move it to
config.py.
This allows us to parse a list from a "pure" config object without going
through ui. Like, we can make "_trustusers" calculated from raw configs,
instead of making sure it's synchronized by calling "fixconfig"s.
author | Jun Wu <quark@fb.com> |
---|---|
date | Fri, 17 Mar 2017 09:19:56 -0700 |
parents | d30fb3de4b40 |
children | 6a773d3050c9 |
comparison
equal
deleted
inserted
replaced
31480:07fe520280d2 | 31481:a7c687c35119 |
---|---|
177 assert getattr(fp, 'mode', r'rb') == r'rb', ( | 177 assert getattr(fp, 'mode', r'rb') == r'rb', ( |
178 'config files must be opened in binary mode, got fp=%r mode=%r' % ( | 178 'config files must be opened in binary mode, got fp=%r mode=%r' % ( |
179 fp, fp.mode)) | 179 fp, fp.mode)) |
180 self.parse(path, fp.read(), | 180 self.parse(path, fp.read(), |
181 sections=sections, remap=remap, include=self.read) | 181 sections=sections, remap=remap, include=self.read) |
182 | |
183 def parselist(value): | |
184 """parse a configuration value as a list of comma/space separated strings | |
185 | |
186 >>> parselist('this,is "a small" ,test') | |
187 ['this', 'is', 'a small', 'test'] | |
188 """ | |
189 | |
190 def _parse_plain(parts, s, offset): | |
191 whitespace = False | |
192 while offset < len(s) and (s[offset:offset + 1].isspace() | |
193 or s[offset:offset + 1] == ','): | |
194 whitespace = True | |
195 offset += 1 | |
196 if offset >= len(s): | |
197 return None, parts, offset | |
198 if whitespace: | |
199 parts.append('') | |
200 if s[offset:offset + 1] == '"' and not parts[-1]: | |
201 return _parse_quote, parts, offset + 1 | |
202 elif s[offset:offset + 1] == '"' and parts[-1][-1] == '\\': | |
203 parts[-1] = parts[-1][:-1] + s[offset:offset + 1] | |
204 return _parse_plain, parts, offset + 1 | |
205 parts[-1] += s[offset:offset + 1] | |
206 return _parse_plain, parts, offset + 1 | |
207 | |
208 def _parse_quote(parts, s, offset): | |
209 if offset < len(s) and s[offset:offset + 1] == '"': # "" | |
210 parts.append('') | |
211 offset += 1 | |
212 while offset < len(s) and (s[offset:offset + 1].isspace() or | |
213 s[offset:offset + 1] == ','): | |
214 offset += 1 | |
215 return _parse_plain, parts, offset | |
216 | |
217 while offset < len(s) and s[offset:offset + 1] != '"': | |
218 if (s[offset:offset + 1] == '\\' and offset + 1 < len(s) | |
219 and s[offset + 1:offset + 2] == '"'): | |
220 offset += 1 | |
221 parts[-1] += '"' | |
222 else: | |
223 parts[-1] += s[offset:offset + 1] | |
224 offset += 1 | |
225 | |
226 if offset >= len(s): | |
227 real_parts = _configlist(parts[-1]) | |
228 if not real_parts: | |
229 parts[-1] = '"' | |
230 else: | |
231 real_parts[0] = '"' + real_parts[0] | |
232 parts = parts[:-1] | |
233 parts.extend(real_parts) | |
234 return None, parts, offset | |
235 | |
236 offset += 1 | |
237 while offset < len(s) and s[offset:offset + 1] in [' ', ',']: | |
238 offset += 1 | |
239 | |
240 if offset < len(s): | |
241 if offset + 1 == len(s) and s[offset:offset + 1] == '"': | |
242 parts[-1] += '"' | |
243 offset += 1 | |
244 else: | |
245 parts.append('') | |
246 else: | |
247 return None, parts, offset | |
248 | |
249 return _parse_plain, parts, offset | |
250 | |
251 def _configlist(s): | |
252 s = s.rstrip(' ,') | |
253 if not s: | |
254 return [] | |
255 parser, parts, offset = _parse_plain, [''], 0 | |
256 while parser: | |
257 parser, parts, offset = parser(parts, s, offset) | |
258 return parts | |
259 | |
260 if value is not None and isinstance(value, bytes): | |
261 result = _configlist(value.lstrip(' ,\n')) | |
262 else: | |
263 result = value | |
264 return result or [] |