Skip to content

Commit 9ffb366

Browse files
committed
Make Python utils more idiomatic, use better names, fix -c mode of update_wiki.
1 parent 672ef2e commit 9ffb366

File tree

4 files changed

+160
-246
lines changed

4 files changed

+160
-246
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ out
77
*.so
88
*.rlib
99
*.dll
10+
*.pyc
1011

1112
# Executables
1213
*.exe

util/export.py

+29-127
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,29 @@
11
#!/usr/bin/env python
22
# Build the gh-pages
33

4-
import json
5-
import os
64
import re
75
import sys
6+
import json
87

8+
from lintlib import parse_all, log
99

10-
level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''')
11-
conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
12-
confvar_re = re.compile(r'''/// Lint: (\w+). (.*).*\n *\("([^"]*)", (?:[^,]*), (.*) => (.*)\),''')
1310
lint_subheadline = re.compile(r'''^\*\*([\w\s]+?)[:?.!]?\*\*(.*)''')
1411

15-
conf_template = """
12+
CONF_TEMPLATE = """\
1613
This lint has the following configuration variables:
1714
18-
* `%s: %s`: %s (defaults to `%s`).
19-
"""
20-
21-
22-
# TODO: actual logging
23-
def warn(*args):
24-
print(args)
25-
26-
27-
def debug(*args):
28-
print(args)
29-
30-
31-
def info(*args):
32-
print(args)
33-
34-
35-
def parse_path(p="clippy_lints/src"):
36-
lints = []
37-
for f in os.listdir(p):
38-
if f.endswith(".rs"):
39-
parse_file(lints, os.path.join(p, f))
40-
41-
conf = parse_conf(p)
42-
info(conf)
15+
* `%s: %s`: %s (defaults to `%s`)."""
4316

44-
for lint_id in conf:
45-
lint = next(l for l in lints if l['id'] == lint_id)
46-
if lint:
47-
lint['docs']['Configuration'] = (conf_template % conf[lint_id]).strip()
4817

49-
return lints
50-
51-
52-
def parse_conf(p):
53-
c = {}
54-
with open(p + '/utils/conf.rs') as f:
55-
f = f.read()
56-
57-
m = re.search(conf_re, f)
58-
m = m.groups()[0]
59-
60-
m = re.findall(confvar_re, m)
61-
62-
for (lint, doc, name, default, ty) in m:
63-
c[lint.lower()] = (name, ty, doc, default)
64-
65-
return c
66-
67-
68-
def parseLintDef(level, comment, name):
69-
lint = {}
70-
lint['id'] = name
71-
lint['level'] = level
72-
lint['docs'] = {}
18+
def parse_lint_def(lint):
19+
lint_dict = {}
20+
lint_dict['id'] = lint.name
21+
lint_dict['level'] = lint.level
22+
lint_dict['docs'] = {}
7323

7424
last_section = None
7525

76-
for line in comment:
26+
for line in lint.doc:
7727
if len(line.strip()) == 0:
7828
continue
7929

@@ -86,77 +36,29 @@ def parseLintDef(level, comment, name):
8636
text = line
8737

8838
if not last_section:
89-
warn("Skipping comment line as it was not preceded by a heading")
90-
debug("in lint `%s`, line `%s`" % name, line)
91-
92-
lint['docs'][last_section] = (lint['docs'].get(last_section, "") + "\n" + text).strip()
93-
94-
return lint
95-
96-
97-
def parse_file(d, f):
98-
last_comment = []
99-
comment = True
100-
101-
with open(f) as rs:
102-
for line in rs:
103-
if comment:
104-
if line.startswith("///"):
105-
if line.startswith("/// "):
106-
last_comment.append(line[4:])
107-
else:
108-
last_comment.append(line[3:])
109-
elif line.startswith("declare_lint!"):
110-
comment = False
111-
deprecated = False
112-
restriction = False
113-
elif line.startswith("declare_restriction_lint!"):
114-
comment = False
115-
deprecated = False
116-
restriction = True
117-
elif line.startswith("declare_deprecated_lint!"):
118-
comment = False
119-
deprecated = True
120-
else:
121-
last_comment = []
122-
if not comment:
123-
l = line.strip()
124-
m = re.search(r"pub\s+([A-Z_][A-Z_0-9]*)", l)
125-
126-
if m:
127-
name = m.group(1).lower()
128-
129-
# Intentionally either a never looping or infinite loop
130-
while not deprecated and not restriction:
131-
m = re.search(level_re, line)
132-
if m:
133-
level = m.group(0)
134-
break
135-
136-
line = next(rs)
137-
138-
if deprecated:
139-
level = "Deprecated"
140-
elif restriction:
141-
level = "Allow"
142-
143-
info("found %s with level %s in %s" % (name, level, f))
144-
d.append(parseLintDef(level, last_comment, name=name))
145-
last_comment = []
146-
comment = True
147-
if "}" in l:
148-
warn("Warning: Missing Lint-Name in", f)
149-
comment = True
39+
log.warn("Skipping comment line as it was not preceded by a heading")
40+
log.debug("in lint `%s`, line `%s`", lint.name, line)
41+
42+
lint_dict['docs'][last_section] = \
43+
(lint_dict['docs'].get(last_section, "") + "\n" + text).strip()
44+
45+
return lint_dict
15046

15147

15248
def main():
153-
lints = parse_path()
154-
info("got %s lints" % len(lints))
49+
lintlist, configs = parse_all()
50+
lints = {}
51+
for lint in lintlist:
52+
lints[lint.name] = parse_lint_def(lint)
53+
if lint.name in configs:
54+
lints[lint.name]['docs']['Configuration'] = \
55+
CONF_TEMPLATE % configs[lint.name]
56+
57+
outfile = sys.argv[1] if len(sys.argv) > 1 else "util/gh-pages/lints.json"
58+
with open(outfile, "w") as fp:
59+
json.dump(list(lints.values()), fp, indent=2)
60+
log.info("wrote JSON for great justice")
15561

156-
outdir = sys.argv[1] if len(sys.argv) > 1 else "util/gh-pages/lints.json"
157-
with open(outdir, "w") as file:
158-
json.dump(lints, file, indent=2)
159-
info("wrote JSON for great justice")
16062

16163
if __name__ == "__main__":
16264
main()

util/lintlib.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Common utils for the several housekeeping scripts.
2+
3+
import os
4+
import re
5+
import collections
6+
7+
import logging as log
8+
log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
9+
10+
Lint = collections.namedtuple('Lint', 'name level doc sourcefile')
11+
Config = collections.namedtuple('Config', 'name ty doc default')
12+
13+
lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
14+
level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''')
15+
conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
16+
confvar_re = re.compile(
17+
r'''/// Lint: (\w+). (.*).*\n *\("([^"]*)", (?:[^,]*), (.*) => (.*)\),''')
18+
19+
20+
def parse_lints(lints, filepath):
21+
last_comment = []
22+
comment = True
23+
24+
with open(filepath) as fp:
25+
for line in fp:
26+
if comment:
27+
if line.startswith("/// "):
28+
last_comment.append(line[4:])
29+
elif line.startswith("///"):
30+
last_comment.append(line[3:])
31+
elif line.startswith("declare_lint!"):
32+
comment = False
33+
deprecated = False
34+
restriction = False
35+
elif line.startswith("declare_restriction_lint!"):
36+
comment = False
37+
deprecated = False
38+
restriction = True
39+
elif line.startswith("declare_deprecated_lint!"):
40+
comment = False
41+
deprecated = True
42+
else:
43+
last_comment = []
44+
if not comment:
45+
m = lintname_re.search(line)
46+
if m:
47+
name = m.group(1).lower()
48+
49+
if deprecated:
50+
level = "Deprecated"
51+
elif restriction:
52+
level = "Allow"
53+
else:
54+
while True:
55+
m = level_re.search(line)
56+
if m:
57+
level = m.group(0)
58+
break
59+
line = next(fp)
60+
61+
log.info("found %s with level %s in %s",
62+
name, level, filepath)
63+
lints.append(Lint(name, level, last_comment, filepath))
64+
last_comment = []
65+
comment = True
66+
if "}" in line:
67+
log.warn("Warning: missing Lint-Name in %s", filepath)
68+
comment = True
69+
70+
71+
def parse_configs(path):
72+
configs = {}
73+
with open(os.path.join(path, 'utils/conf.rs')) as fp:
74+
contents = fp.read()
75+
76+
match = re.search(conf_re, contents)
77+
confvars = re.findall(confvar_re, match.group(1))
78+
79+
for (lint, doc, name, default, ty) in confvars:
80+
configs[lint.lower()] = Config(name, ty, doc, default)
81+
82+
return configs
83+
84+
85+
def parse_all(path="clippy_lints/src"):
86+
lints = []
87+
for filename in os.listdir(path):
88+
if filename.endswith(".rs"):
89+
parse_lints(lints, os.path.join(path, filename))
90+
log.info("got %s lints", len(lints))
91+
92+
configs = parse_configs(path)
93+
log.info("got %d configs", len(configs))
94+
95+
return lints, configs

0 commit comments

Comments
 (0)