##// END OF EJS Templates
check-config: look for ui.configwith...
Gregory Szorc -
r32849:e9fc5550 default
parent child Browse files
Show More
@@ -1,120 +1,130 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # check-config - a config flag documentation checker for Mercurial
4 4 #
5 5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 from __future__ import absolute_import, print_function
11 11 import re
12 12 import sys
13 13
14 14 foundopts = {}
15 15 documented = {}
16 16
17 17 configre = re.compile(r'''
18 18 # Function call
19 19 ui\.config(?P<ctype>|int|bool|list)\(
20 20 # First argument.
21 21 ['"](?P<section>\S+)['"],\s*
22 22 # Second argument
23 23 ['"](?P<option>\S+)['"](,\s+
24 24 (?:default=)?(?P<default>\S+?))?
25 25 \)''', re.VERBOSE | re.MULTILINE)
26 26
27 configwithre = re.compile('''
28 ui\.config(?P<ctype>with)\(
29 # First argument is callback function. This doesn't parse robustly
30 # if it is e.g. a function call.
31 [^,]+,\s*
32 ['"](?P<section>\S+)['"],\s*
33 ['"](?P<option>\S+)['"](,\s+
34 (?:default=)?(?P<default>\S+?))?
35 \)''', re.VERBOSE | re.MULTILINE)
36
27 37 configpartialre = (r"""ui\.config""")
28 38
29 39 def main(args):
30 40 for f in args:
31 41 sect = ''
32 42 prevname = ''
33 43 confsect = ''
34 44 carryover = ''
35 45 for l in open(f):
36 46
37 47 # check topic-like bits
38 48 m = re.match('\s*``(\S+)``', l)
39 49 if m:
40 50 prevname = m.group(1)
41 51 if re.match('^\s*-+$', l):
42 52 sect = prevname
43 53 prevname = ''
44 54
45 55 if sect and prevname:
46 56 name = sect + '.' + prevname
47 57 documented[name] = 1
48 58
49 59 # check docstring bits
50 60 m = re.match(r'^\s+\[(\S+)\]', l)
51 61 if m:
52 62 confsect = m.group(1)
53 63 continue
54 64 m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
55 65 if m:
56 66 name = confsect + '.' + m.group(1)
57 67 documented[name] = 1
58 68
59 69 # like the bugzilla extension
60 70 m = re.match(r'^\s*(\S+\.\S+)$', l)
61 71 if m:
62 72 documented[m.group(1)] = 1
63 73
64 74 # like convert
65 75 m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
66 76 if m:
67 77 documented[m.group(1)] = 1
68 78
69 79 # quoted in help or docstrings
70 80 m = re.match(r'.*?``(\S+\.\S+)``', l)
71 81 if m:
72 82 documented[m.group(1)] = 1
73 83
74 84 # look for ignore markers
75 85 m = re.search(r'# (?:internal|experimental|deprecated|developer)'
76 86 ' config: (\S+\.\S+)$', l)
77 87 if m:
78 88 documented[m.group(1)] = 1
79 89
80 90 # look for code-like bits
81 91 line = carryover + l
82 m = configre.search(line)
92 m = configre.search(line) or configwithre.search(line)
83 93 if m:
84 94 ctype = m.group('ctype')
85 95 if not ctype:
86 96 ctype = 'str'
87 97 name = m.group('section') + "." + m.group('option')
88 98 default = m.group('default')
89 99 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
90 100 default = ''
91 101 if re.match('[a-z.]+$', default):
92 102 default = '<variable>'
93 103 if name in foundopts and (ctype, default) != foundopts[name]:
94 104 print(l)
95 105 print("conflict on %s: %r != %r" % (name, (ctype, default),
96 106 foundopts[name]))
97 107 foundopts[name] = (ctype, default)
98 108 carryover = ''
99 109 else:
100 110 m = re.search(configpartialre, line)
101 111 if m:
102 112 carryover = line
103 113 else:
104 114 carryover = ''
105 115
106 116 for name in sorted(foundopts):
107 117 if name not in documented:
108 118 if not (name.startswith("devel.") or
109 119 name.startswith("experimental.") or
110 120 name.startswith("debug.")):
111 121 ctype, default = foundopts[name]
112 122 if default:
113 123 default = ' [%s]' % default
114 124 print("undocumented: %s (%s)%s" % (name, ctype, default))
115 125
116 126 if __name__ == "__main__":
117 127 if len(sys.argv) > 1:
118 128 sys.exit(main(sys.argv[1:]))
119 129 else:
120 130 sys.exit(main([l.rstrip() for l in sys.stdin]))
@@ -1,35 +1,37 b''
1 1 #require test-repo
2 2
3 3 $ . "$TESTDIR/helpers-testrepo.sh"
4 4
5 5 Sanity check check-config.py
6 6
7 7 $ cat > testfile.py << EOF
8 8 > # Good
9 9 > foo = ui.config('ui', 'username')
10 10 > # Missing
11 11 > foo = ui.config('ui', 'doesnotexist')
12 12 > # Missing different type
13 13 > foo = ui.configint('ui', 'missingint')
14 14 > # Missing with default value
15 15 > foo = ui.configbool('ui', 'missingbool1', default=True)
16 16 > foo = ui.configbool('ui', 'missingbool2', False)
17 17 > EOF
18 18
19 19 $ cat > files << EOF
20 20 > mercurial/help/config.txt
21 21 > $TESTTMP/testfile.py
22 22 > EOF
23 23
24 24 $ cd "$TESTDIR"/..
25 25
26 26 $ python contrib/check-config.py < $TESTTMP/files
27 27 undocumented: ui.doesnotexist (str)
28 28 undocumented: ui.missingbool1 (bool) [True]
29 29 undocumented: ui.missingbool2 (bool)
30 30 undocumented: ui.missingint (int)
31 31
32 32 New errors are not allowed. Warnings are strongly discouraged.
33 33
34 34 $ hg files "set:(**.py or **.txt) - tests/**" | sed 's|\\|/|g' |
35 35 > python contrib/check-config.py
36 undocumented: profiling.showmax (with) [0.999]
37 undocumented: profiling.showmin (with) [0.005]
General Comments 0
You need to be logged in to leave comments. Login now