Show More
@@ -258,93 +258,3 b' class config(object):' | |||||
258 | self.parse( |
|
258 | self.parse( | |
259 | path, fp.read(), sections=sections, remap=remap, include=include |
|
259 | path, fp.read(), sections=sections, remap=remap, include=include | |
260 | ) |
|
260 | ) | |
261 |
|
||||
262 |
|
||||
263 | def parselist(value): |
|
|||
264 | """parse a configuration value as a list of comma/space separated strings |
|
|||
265 |
|
||||
266 | >>> parselist(b'this,is "a small" ,test') |
|
|||
267 | ['this', 'is', 'a small', 'test'] |
|
|||
268 | """ |
|
|||
269 |
|
||||
270 | def _parse_plain(parts, s, offset): |
|
|||
271 | whitespace = False |
|
|||
272 | while offset < len(s) and ( |
|
|||
273 | s[offset : offset + 1].isspace() or s[offset : offset + 1] == b',' |
|
|||
274 | ): |
|
|||
275 | whitespace = True |
|
|||
276 | offset += 1 |
|
|||
277 | if offset >= len(s): |
|
|||
278 | return None, parts, offset |
|
|||
279 | if whitespace: |
|
|||
280 | parts.append(b'') |
|
|||
281 | if s[offset : offset + 1] == b'"' and not parts[-1]: |
|
|||
282 | return _parse_quote, parts, offset + 1 |
|
|||
283 | elif s[offset : offset + 1] == b'"' and parts[-1][-1:] == b'\\': |
|
|||
284 | parts[-1] = parts[-1][:-1] + s[offset : offset + 1] |
|
|||
285 | return _parse_plain, parts, offset + 1 |
|
|||
286 | parts[-1] += s[offset : offset + 1] |
|
|||
287 | return _parse_plain, parts, offset + 1 |
|
|||
288 |
|
||||
289 | def _parse_quote(parts, s, offset): |
|
|||
290 | if offset < len(s) and s[offset : offset + 1] == b'"': # "" |
|
|||
291 | parts.append(b'') |
|
|||
292 | offset += 1 |
|
|||
293 | while offset < len(s) and ( |
|
|||
294 | s[offset : offset + 1].isspace() |
|
|||
295 | or s[offset : offset + 1] == b',' |
|
|||
296 | ): |
|
|||
297 | offset += 1 |
|
|||
298 | return _parse_plain, parts, offset |
|
|||
299 |
|
||||
300 | while offset < len(s) and s[offset : offset + 1] != b'"': |
|
|||
301 | if ( |
|
|||
302 | s[offset : offset + 1] == b'\\' |
|
|||
303 | and offset + 1 < len(s) |
|
|||
304 | and s[offset + 1 : offset + 2] == b'"' |
|
|||
305 | ): |
|
|||
306 | offset += 1 |
|
|||
307 | parts[-1] += b'"' |
|
|||
308 | else: |
|
|||
309 | parts[-1] += s[offset : offset + 1] |
|
|||
310 | offset += 1 |
|
|||
311 |
|
||||
312 | if offset >= len(s): |
|
|||
313 | real_parts = _configlist(parts[-1]) |
|
|||
314 | if not real_parts: |
|
|||
315 | parts[-1] = b'"' |
|
|||
316 | else: |
|
|||
317 | real_parts[0] = b'"' + real_parts[0] |
|
|||
318 | parts = parts[:-1] |
|
|||
319 | parts.extend(real_parts) |
|
|||
320 | return None, parts, offset |
|
|||
321 |
|
||||
322 | offset += 1 |
|
|||
323 | while offset < len(s) and s[offset : offset + 1] in [b' ', b',']: |
|
|||
324 | offset += 1 |
|
|||
325 |
|
||||
326 | if offset < len(s): |
|
|||
327 | if offset + 1 == len(s) and s[offset : offset + 1] == b'"': |
|
|||
328 | parts[-1] += b'"' |
|
|||
329 | offset += 1 |
|
|||
330 | else: |
|
|||
331 | parts.append(b'') |
|
|||
332 | else: |
|
|||
333 | return None, parts, offset |
|
|||
334 |
|
||||
335 | return _parse_plain, parts, offset |
|
|||
336 |
|
||||
337 | def _configlist(s): |
|
|||
338 | s = s.rstrip(b' ,') |
|
|||
339 | if not s: |
|
|||
340 | return [] |
|
|||
341 | parser, parts, offset = _parse_plain, [b''], 0 |
|
|||
342 | while parser: |
|
|||
343 | parser, parts, offset = parser(parts, s, offset) |
|
|||
344 | return parts |
|
|||
345 |
|
||||
346 | if value is not None and isinstance(value, bytes): |
|
|||
347 | result = _configlist(value.lstrip(b' ,\n')) |
|
|||
348 | else: |
|
|||
349 | result = value |
|
|||
350 | return result or [] |
|
@@ -887,10 +887,10 b' class ui(object):' | |||||
887 | """ |
|
887 | """ | |
888 | # default is not always a list |
|
888 | # default is not always a list | |
889 | v = self.configwith( |
|
889 | v = self.configwith( | |
890 |
|
|
890 | stringutil.parselist, section, name, default, b'list', untrusted | |
891 | ) |
|
891 | ) | |
892 | if isinstance(v, bytes): |
|
892 | if isinstance(v, bytes): | |
893 |
return |
|
893 | return stringutil.parselist(v) | |
894 | elif v is None: |
|
894 | elif v is None: | |
895 | return [] |
|
895 | return [] | |
896 | return v |
|
896 | return v |
@@ -868,6 +868,96 b' def parsebool(s):' | |||||
868 | return _booleans.get(s.lower(), None) |
|
868 | return _booleans.get(s.lower(), None) | |
869 |
|
869 | |||
870 |
|
870 | |||
|
871 | def parselist(value): | |||
|
872 | """parse a configuration value as a list of comma/space separated strings | |||
|
873 | ||||
|
874 | >>> parselist(b'this,is "a small" ,test') | |||
|
875 | ['this', 'is', 'a small', 'test'] | |||
|
876 | """ | |||
|
877 | ||||
|
878 | def _parse_plain(parts, s, offset): | |||
|
879 | whitespace = False | |||
|
880 | while offset < len(s) and ( | |||
|
881 | s[offset : offset + 1].isspace() or s[offset : offset + 1] == b',' | |||
|
882 | ): | |||
|
883 | whitespace = True | |||
|
884 | offset += 1 | |||
|
885 | if offset >= len(s): | |||
|
886 | return None, parts, offset | |||
|
887 | if whitespace: | |||
|
888 | parts.append(b'') | |||
|
889 | if s[offset : offset + 1] == b'"' and not parts[-1]: | |||
|
890 | return _parse_quote, parts, offset + 1 | |||
|
891 | elif s[offset : offset + 1] == b'"' and parts[-1][-1:] == b'\\': | |||
|
892 | parts[-1] = parts[-1][:-1] + s[offset : offset + 1] | |||
|
893 | return _parse_plain, parts, offset + 1 | |||
|
894 | parts[-1] += s[offset : offset + 1] | |||
|
895 | return _parse_plain, parts, offset + 1 | |||
|
896 | ||||
|
897 | def _parse_quote(parts, s, offset): | |||
|
898 | if offset < len(s) and s[offset : offset + 1] == b'"': # "" | |||
|
899 | parts.append(b'') | |||
|
900 | offset += 1 | |||
|
901 | while offset < len(s) and ( | |||
|
902 | s[offset : offset + 1].isspace() | |||
|
903 | or s[offset : offset + 1] == b',' | |||
|
904 | ): | |||
|
905 | offset += 1 | |||
|
906 | return _parse_plain, parts, offset | |||
|
907 | ||||
|
908 | while offset < len(s) and s[offset : offset + 1] != b'"': | |||
|
909 | if ( | |||
|
910 | s[offset : offset + 1] == b'\\' | |||
|
911 | and offset + 1 < len(s) | |||
|
912 | and s[offset + 1 : offset + 2] == b'"' | |||
|
913 | ): | |||
|
914 | offset += 1 | |||
|
915 | parts[-1] += b'"' | |||
|
916 | else: | |||
|
917 | parts[-1] += s[offset : offset + 1] | |||
|
918 | offset += 1 | |||
|
919 | ||||
|
920 | if offset >= len(s): | |||
|
921 | real_parts = _configlist(parts[-1]) | |||
|
922 | if not real_parts: | |||
|
923 | parts[-1] = b'"' | |||
|
924 | else: | |||
|
925 | real_parts[0] = b'"' + real_parts[0] | |||
|
926 | parts = parts[:-1] | |||
|
927 | parts.extend(real_parts) | |||
|
928 | return None, parts, offset | |||
|
929 | ||||
|
930 | offset += 1 | |||
|
931 | while offset < len(s) and s[offset : offset + 1] in [b' ', b',']: | |||
|
932 | offset += 1 | |||
|
933 | ||||
|
934 | if offset < len(s): | |||
|
935 | if offset + 1 == len(s) and s[offset : offset + 1] == b'"': | |||
|
936 | parts[-1] += b'"' | |||
|
937 | offset += 1 | |||
|
938 | else: | |||
|
939 | parts.append(b'') | |||
|
940 | else: | |||
|
941 | return None, parts, offset | |||
|
942 | ||||
|
943 | return _parse_plain, parts, offset | |||
|
944 | ||||
|
945 | def _configlist(s): | |||
|
946 | s = s.rstrip(b' ,') | |||
|
947 | if not s: | |||
|
948 | return [] | |||
|
949 | parser, parts, offset = _parse_plain, [b''], 0 | |||
|
950 | while parser: | |||
|
951 | parser, parts, offset = parser(parts, s, offset) | |||
|
952 | return parts | |||
|
953 | ||||
|
954 | if value is not None and isinstance(value, bytes): | |||
|
955 | result = _configlist(value.lstrip(b' ,\n')) | |||
|
956 | else: | |||
|
957 | result = value | |||
|
958 | return result or [] | |||
|
959 | ||||
|
960 | ||||
871 | def evalpythonliteral(s): |
|
961 | def evalpythonliteral(s): | |
872 | """Evaluate a string containing a Python literal expression""" |
|
962 | """Evaluate a string containing a Python literal expression""" | |
873 | # We could backport our tokenizer hack to rewrite '' to u'' if we want |
|
963 | # We could backport our tokenizer hack to rewrite '' to u'' if we want |
@@ -361,10 +361,11 b' impl Config {' | |||||
361 | /// |
|
361 | /// | |
362 | /// This is appropriate for new configuration keys. The value syntax is |
|
362 | /// This is appropriate for new configuration keys. The value syntax is | |
363 | /// **not** the same as most existing list-valued config, which has Python |
|
363 | /// **not** the same as most existing list-valued config, which has Python | |
364 |
/// parsing implemented in `parselist()` in |
|
364 | /// parsing implemented in `parselist()` in | |
365 | /// Faithfully porting that parsing algorithm to Rust (including behavior |
|
365 | /// `mercurial/utils/stringutil.py`. Faithfully porting that parsing | |
366 | /// that are arguably bugs) turned out to be non-trivial and hasn’t been |
|
366 | /// algorithm to Rust (including behavior that are arguably bugs) | |
367 | /// completed as of this writing. |
|
367 | /// turned out to be non-trivial and hasn’t been completed as of this | |
|
368 | /// writing. | |||
368 | /// |
|
369 | /// | |
369 | /// Instead, the "simple" syntax is: split on comma, then trim leading and |
|
370 | /// Instead, the "simple" syntax is: split on comma, then trim leading and | |
370 | /// trailing whitespace of each component. Quotes or backslashes are not |
|
371 | /// trailing whitespace of each component. Quotes or backslashes are not |
@@ -131,7 +131,6 b' expected_mods_tested = set(' | |||||
131 | ('mercurial.changelog', '{}'), |
|
131 | ('mercurial.changelog', '{}'), | |
132 | ('mercurial.cmdutil', '{}'), |
|
132 | ('mercurial.cmdutil', '{}'), | |
133 | ('mercurial.color', '{}'), |
|
133 | ('mercurial.color', '{}'), | |
134 | ('mercurial.config', '{}'), |
|
|||
135 | ('mercurial.dagparser', "{'optionflags': 4}"), |
|
134 | ('mercurial.dagparser', "{'optionflags': 4}"), | |
136 | ('mercurial.encoding', '{}'), |
|
135 | ('mercurial.encoding', '{}'), | |
137 | ('mercurial.fancyopts', '{}'), |
|
136 | ('mercurial.fancyopts', '{}'), |
General Comments 0
You need to be logged in to leave comments.
Login now