check-config.py
142 lines
| 4.6 KiB
| text/x-python
|
PythonLexer
/ contrib / check-config.py
Matt Mackall
|
r25790 | #!/usr/bin/env python | ||
# | ||||
# check-config - a config flag documentation checker for Mercurial | ||||
# | ||||
# Copyright 2015 Matt Mackall <mpm@selenic.com> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
Pulkit Goyal
|
r28352 | from __future__ import absolute_import, print_function | ||
Matt Mackall
|
r25790 | import re | ||
import sys | ||||
foundopts = {} | ||||
documented = {} | ||||
Gregory Szorc
|
r33192 | allowinconsistent = set() | ||
Matt Mackall
|
r25790 | |||
Gregory Szorc
|
r32847 | configre = re.compile(r''' | ||
# Function call | ||||
Gregory Szorc
|
r32848 | ui\.config(?P<ctype>|int|bool|list)\( | ||
Gregory Szorc
|
r32847 | # First argument. | ||
Gregory Szorc
|
r32848 | ['"](?P<section>\S+)['"],\s* | ||
Gregory Szorc
|
r32847 | # Second argument | ||
Gregory Szorc
|
r32848 | ['"](?P<option>\S+)['"](,\s+ | ||
(?:default=)?(?P<default>\S+?))? | ||||
Gregory Szorc
|
r32847 | \)''', re.VERBOSE | re.MULTILINE) | ||
Gregory Szorc
|
r32849 | configwithre = re.compile(''' | ||
ui\.config(?P<ctype>with)\( | ||||
# First argument is callback function. This doesn't parse robustly | ||||
# if it is e.g. a function call. | ||||
[^,]+,\s* | ||||
['"](?P<section>\S+)['"],\s* | ||||
['"](?P<option>\S+)['"](,\s+ | ||||
(?:default=)?(?P<default>\S+?))? | ||||
\)''', re.VERBOSE | re.MULTILINE) | ||||
timeless
|
r27313 | configpartialre = (r"""ui\.config""") | ||
Matt Mackall
|
r25790 | |||
Gregory Szorc
|
r33192 | ignorere = re.compile(r''' | ||
\#\s(?P<reason>internal|experimental|deprecated|developer|inconsistent)\s | ||||
config:\s(?P<config>\S+\.\S+)$ | ||||
''', re.VERBOSE | re.MULTILINE) | ||||
Matt Mackall
|
r25790 | def main(args): | ||
for f in args: | ||||
sect = '' | ||||
prevname = '' | ||||
confsect = '' | ||||
timeless
|
r27313 | carryover = '' | ||
Ryan McElroy
|
r33571 | linenum = 0 | ||
Matt Mackall
|
r25790 | for l in open(f): | ||
Ryan McElroy
|
r33571 | linenum += 1 | ||
Matt Mackall
|
r25790 | |||
# check topic-like bits | ||||
m = re.match('\s*``(\S+)``', l) | ||||
if m: | ||||
prevname = m.group(1) | ||||
if re.match('^\s*-+$', l): | ||||
sect = prevname | ||||
prevname = '' | ||||
if sect and prevname: | ||||
name = sect + '.' + prevname | ||||
documented[name] = 1 | ||||
# check docstring bits | ||||
m = re.match(r'^\s+\[(\S+)\]', l) | ||||
if m: | ||||
confsect = m.group(1) | ||||
continue | ||||
timeless
|
r27311 | m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l) | ||
Matt Mackall
|
r25790 | if m: | ||
name = confsect + '.' + m.group(1) | ||||
documented[name] = 1 | ||||
# like the bugzilla extension | ||||
timeless
|
r27311 | m = re.match(r'^\s*(\S+\.\S+)$', l) | ||
Matt Mackall
|
r25790 | if m: | ||
documented[m.group(1)] = 1 | ||||
timeless
|
r27310 | # like convert | ||
m = re.match(r'^\s*:(\S+\.\S+):\s+', l) | ||||
if m: | ||||
documented[m.group(1)] = 1 | ||||
Matt Mackall
|
r25790 | # quoted in help or docstrings | ||
timeless
|
r27311 | m = re.match(r'.*?``(\S+\.\S+)``', l) | ||
Matt Mackall
|
r25790 | if m: | ||
documented[m.group(1)] = 1 | ||||
# look for ignore markers | ||||
Gregory Szorc
|
r33192 | m = ignorere.search(l) | ||
Matt Mackall
|
r25790 | if m: | ||
Gregory Szorc
|
r33192 | if m.group('reason') == 'inconsistent': | ||
allowinconsistent.add(m.group('config')) | ||||
else: | ||||
documented[m.group('config')] = 1 | ||||
Matt Mackall
|
r25790 | |||
# look for code-like bits | ||||
timeless
|
r27313 | line = carryover + l | ||
Gregory Szorc
|
r32849 | m = configre.search(line) or configwithre.search(line) | ||
Matt Mackall
|
r25790 | if m: | ||
Gregory Szorc
|
r32848 | ctype = m.group('ctype') | ||
Matt Mackall
|
r25790 | if not ctype: | ||
ctype = 'str' | ||||
Gregory Szorc
|
r32848 | name = m.group('section') + "." + m.group('option') | ||
default = m.group('default') | ||||
Matt Mackall
|
r25790 | if default in (None, 'False', 'None', '0', '[]', '""', "''"): | ||
default = '' | ||||
if re.match('[a-z.]+$', default): | ||||
default = '<variable>' | ||||
Gregory Szorc
|
r33192 | if (name in foundopts and (ctype, default) != foundopts[name] | ||
and name not in allowinconsistent): | ||||
Ryan McElroy
|
r33571 | print(l.rstrip()) | ||
Pulkit Goyal
|
r28352 | print("conflict on %s: %r != %r" % (name, (ctype, default), | ||
foundopts[name])) | ||||
Ryan McElroy
|
r33571 | print("at %s:%d:" % (f, linenum)) | ||
Matt Mackall
|
r25790 | foundopts[name] = (ctype, default) | ||
timeless
|
r27313 | carryover = '' | ||
else: | ||||
m = re.search(configpartialre, line) | ||||
if m: | ||||
carryover = line | ||||
else: | ||||
carryover = '' | ||||
Matt Mackall
|
r25790 | |||
for name in sorted(foundopts): | ||||
if name not in documented: | ||||
if not (name.startswith("devel.") or | ||||
name.startswith("experimental.") or | ||||
name.startswith("debug.")): | ||||
ctype, default = foundopts[name] | ||||
if default: | ||||
default = ' [%s]' % default | ||||
Pulkit Goyal
|
r28352 | print("undocumented: %s (%s)%s" % (name, ctype, default)) | ||
Matt Mackall
|
r25790 | |||
if __name__ == "__main__": | ||||
FUJIWARA Katsunori
|
r27992 | if len(sys.argv) > 1: | ||
sys.exit(main(sys.argv[1:])) | ||||
else: | ||||
sys.exit(main([l.rstrip() for l in sys.stdin])) | ||||