##// END OF EJS Templates
check-config: escape period in regexp for inline comments
timeless -
r27312:f925d492 default
parent child Browse files
Show More
@@ -1,98 +1,98
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # check-config - a config flag documentation checker for Mercurial
3 # check-config - a config flag documentation checker for Mercurial
4 #
4 #
5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
5 # Copyright 2015 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 import re
10 import re
11 import sys
11 import sys
12
12
13 foundopts = {}
13 foundopts = {}
14 documented = {}
14 documented = {}
15
15
16 configre = (r"""ui\.config(|int|bool|list)\(['"](\S+)['"], ?"""
16 configre = (r"""ui\.config(|int|bool|list)\(['"](\S+)['"], ?"""
17 r"""['"](\S+)['"](,\s(?:default=)?(\S+?))?\)""")
17 r"""['"](\S+)['"](,\s(?:default=)?(\S+?))?\)""")
18
18
19 def main(args):
19 def main(args):
20 for f in args:
20 for f in args:
21 sect = ''
21 sect = ''
22 prevname = ''
22 prevname = ''
23 confsect = ''
23 confsect = ''
24 for l in open(f):
24 for l in open(f):
25
25
26 # check topic-like bits
26 # check topic-like bits
27 m = re.match('\s*``(\S+)``', l)
27 m = re.match('\s*``(\S+)``', l)
28 if m:
28 if m:
29 prevname = m.group(1)
29 prevname = m.group(1)
30 if re.match('^\s*-+$', l):
30 if re.match('^\s*-+$', l):
31 sect = prevname
31 sect = prevname
32 prevname = ''
32 prevname = ''
33
33
34 if sect and prevname:
34 if sect and prevname:
35 name = sect + '.' + prevname
35 name = sect + '.' + prevname
36 documented[name] = 1
36 documented[name] = 1
37
37
38 # check docstring bits
38 # check docstring bits
39 m = re.match(r'^\s+\[(\S+)\]', l)
39 m = re.match(r'^\s+\[(\S+)\]', l)
40 if m:
40 if m:
41 confsect = m.group(1)
41 confsect = m.group(1)
42 continue
42 continue
43 m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
43 m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
44 if m:
44 if m:
45 name = confsect + '.' + m.group(1)
45 name = confsect + '.' + m.group(1)
46 documented[name] = 1
46 documented[name] = 1
47
47
48 # like the bugzilla extension
48 # like the bugzilla extension
49 m = re.match(r'^\s*(\S+\.\S+)$', l)
49 m = re.match(r'^\s*(\S+\.\S+)$', l)
50 if m:
50 if m:
51 documented[m.group(1)] = 1
51 documented[m.group(1)] = 1
52
52
53 # like convert
53 # like convert
54 m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
54 m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
55 if m:
55 if m:
56 documented[m.group(1)] = 1
56 documented[m.group(1)] = 1
57
57
58 # quoted in help or docstrings
58 # quoted in help or docstrings
59 m = re.match(r'.*?``(\S+\.\S+)``', l)
59 m = re.match(r'.*?``(\S+\.\S+)``', l)
60 if m:
60 if m:
61 documented[m.group(1)] = 1
61 documented[m.group(1)] = 1
62
62
63 # look for ignore markers
63 # look for ignore markers
64 m = re.search(r'# (?:internal|experimental|deprecated|developer)'
64 m = re.search(r'# (?:internal|experimental|deprecated|developer)'
65 ' config: (\S+.\S+)$', l)
65 ' config: (\S+\.\S+)$', l)
66 if m:
66 if m:
67 documented[m.group(1)] = 1
67 documented[m.group(1)] = 1
68
68
69 # look for code-like bits
69 # look for code-like bits
70 m = re.search(configre, l)
70 m = re.search(configre, l)
71 if m:
71 if m:
72 ctype = m.group(1)
72 ctype = m.group(1)
73 if not ctype:
73 if not ctype:
74 ctype = 'str'
74 ctype = 'str'
75 name = m.group(2) + "." + m.group(3)
75 name = m.group(2) + "." + m.group(3)
76 default = m.group(5)
76 default = m.group(5)
77 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
77 if default in (None, 'False', 'None', '0', '[]', '""', "''"):
78 default = ''
78 default = ''
79 if re.match('[a-z.]+$', default):
79 if re.match('[a-z.]+$', default):
80 default = '<variable>'
80 default = '<variable>'
81 if name in foundopts and (ctype, default) != foundopts[name]:
81 if name in foundopts and (ctype, default) != foundopts[name]:
82 print l
82 print l
83 print "conflict on %s: %r != %r" % (name, (ctype, default),
83 print "conflict on %s: %r != %r" % (name, (ctype, default),
84 foundopts[name])
84 foundopts[name])
85 foundopts[name] = (ctype, default)
85 foundopts[name] = (ctype, default)
86
86
87 for name in sorted(foundopts):
87 for name in sorted(foundopts):
88 if name not in documented:
88 if name not in documented:
89 if not (name.startswith("devel.") or
89 if not (name.startswith("devel.") or
90 name.startswith("experimental.") or
90 name.startswith("experimental.") or
91 name.startswith("debug.")):
91 name.startswith("debug.")):
92 ctype, default = foundopts[name]
92 ctype, default = foundopts[name]
93 if default:
93 if default:
94 default = ' [%s]' % default
94 default = ' [%s]' % default
95 print "undocumented: %s (%s)%s" % (name, ctype, default)
95 print "undocumented: %s (%s)%s" % (name, ctype, default)
96
96
97 if __name__ == "__main__":
97 if __name__ == "__main__":
98 sys.exit(main(sys.argv[1:]))
98 sys.exit(main(sys.argv[1:]))
General Comments 0
You need to be logged in to leave comments. Login now