check-config.py
130 lines
| 4.2 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
|
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 | |||
def main(args): | ||||
for f in args: | ||||
sect = '' | ||||
prevname = '' | ||||
confsect = '' | ||||
timeless
|
r27313 | carryover = '' | ||
Matt Mackall
|
r25790 | for l in open(f): | ||
# 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 | ||||
m = re.search(r'# (?:internal|experimental|deprecated|developer)' | ||||
timeless
|
r27312 | ' config: (\S+\.\S+)$', l) | ||
Matt Mackall
|
r25790 | if m: | ||
documented[m.group(1)] = 1 | ||||
# 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>' | ||||
if name in foundopts and (ctype, default) != foundopts[name]: | ||||
Pulkit Goyal
|
r28352 | print(l) | ||
print("conflict on %s: %r != %r" % (name, (ctype, default), | ||||
foundopts[name])) | ||||
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])) | ||||