Rollup merge of #7298 - flip1995:ci-switch-to-monster, r=xFrednet,flip1995

Switch CI to new metadata collection

r? `@xFrednet`

Things we have to keep in mind:

- This removes the template files and the scripts used for deployment from the checkout. This was added in #5517. I don't think we ever needed those there. Not sure though.
- ~~As a result, we can't remove the python scripts yet. We have to wait until this hits a stable Clippy release.~~ I'll just break the next stable deploy and do it by hand once.
- This should be merged together with #7279. Me and `@xFrednet` will coordinate the switch
- ...?

I still have to try out some things:

- [x] Is it worth caching? Yes
- [x] ~~Is it worth to do a release build?~~ Nope
- [x] Does it actually work? With a few changes, yes
- [ ] ...?

changelog: Clippy now uses a lint to generate its documentation 🎉
This commit is contained in:
Philipp Krones 2021-07-28 15:06:26 +02:00 committed by GitHub
commit bcdf147aaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 26 additions and 213 deletions

9
.github/deploy.sh vendored
View File

@ -8,13 +8,12 @@ rm -rf out/master/ || exit 0
echo "Making the docs for master"
mkdir out/master/
cp util/gh-pages/index.html out/master
python3 ./util/export.py out/master/lints.json
cp util/gh-pages/lints.json out/master
if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
cp -r out/master "out/$TAG_NAME"
rm -f out/stable
ln -s "$TAG_NAME" out/stable
cp -Tr out/master "out/$TAG_NAME"
ln -sf "$TAG_NAME" out/stable
fi
if [[ $BETA = "true" ]]; then
@ -28,8 +27,8 @@ cp util/gh-pages/versions.html out/index.html
echo "Making the versions.json file"
python3 ./util/versions.py out
cd out
# Now let's go have some fun with the cloned repo
cd out
git config user.name "GHA CI"
git config user.email "gha@ci.invalid"

View File

@ -39,10 +39,23 @@ jobs:
if: github.ref == 'refs/heads/beta'
run: echo "BETA=true" >> $GITHUB_ENV
- name: Use scripts and templates from master branch
# We need to check out all files that (transitively) depend on the
# structure of the gh-pages branch, so that we're able to change that
# structure without breaking the deployment.
- name: Use deploy files from master branch
run: |
git fetch --no-tags --prune --depth=1 origin master
git checkout origin/master -- .github/deploy.sh util/gh-pages/ util/*.py
git checkout origin/master -- .github/deploy.sh util/versions.py util/gh-pages/versions.html
# Generate lockfile for caching to avoid build problems with cached deps
- name: cargo generate-lockfile
run: cargo generate-lockfile
- name: Cache
uses: Swatinem/rust-cache@v1.3.0
- name: cargo collect-metadata
run: cargo collect-metadata
- name: Deploy
run: |

View File

@ -15,8 +15,8 @@ pub fn run(port: u16, lint: Option<&str>) -> ! {
loop {
if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
Command::new("python3")
.arg("util/export.py")
Command::new("cargo")
.arg("collect-metadata")
.spawn()
.unwrap()
.wait()

View File

@ -32,7 +32,7 @@
};
/// This is the output file of the lint collector.
const OUTPUT_FILE: &str = "../util/gh-pages/metadata_collection.json";
const OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// These lints are excluded from the export.
const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "internal_metadata_collector"];
/// These groups will be ignored by the lint group matcher. This is useful for collections like

View File

@ -183,7 +183,7 @@ fn run_metadata_collection_lint() {
use std::time::SystemTime;
// Setup for validation
let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json");
let start_time = SystemTime::now();
// Run collection as is

View File

@ -1,84 +0,0 @@
#!/usr/bin/env python
# Build the gh-pages
from collections import OrderedDict
import re
import sys
import json
from lintlib import parse_all, log
lint_subheadline = re.compile(r'''^\*\*([\w\s]+?)[:?.!]?\*\*(.*)''')
rust_code_block = re.compile(r'''```rust.+?```''', flags=re.DOTALL)
CONF_TEMPLATE = """\
This lint has the following configuration variables:
* `%s: %s`: %s (defaults to `%s`)."""
def parse_code_block(match):
lines = []
for line in match.group(0).split('\n'):
# fix syntax highlighting for headers like ```rust,ignore
if line.startswith('```rust'):
lines.append('```rust')
elif not line.startswith('# '):
lines.append(line)
return '\n'.join(lines)
def parse_lint_def(lint):
lint_dict = {}
lint_dict['id'] = lint.name
lint_dict['group'] = lint.group
lint_dict['level'] = lint.level
lint_dict['docs'] = OrderedDict()
last_section = None
for line in lint.doc:
match = re.match(lint_subheadline, line)
if match:
last_section = match.groups()[0]
text = match.groups()[1]
else:
text = line
if not last_section:
log.warning("Skipping comment line as it was not preceded by a heading")
log.debug("in lint `%s`, line `%s`", lint.name, line)
if last_section not in lint_dict['docs']:
lint_dict['docs'][last_section] = ""
lint_dict['docs'][last_section] += text + "\n"
for section in lint_dict['docs']:
lint_dict['docs'][section] = re.sub(rust_code_block, parse_code_block, lint_dict['docs'][section].strip())
return lint_dict
def main():
lintlist, configs = parse_all()
lints = {}
for lint in lintlist:
lints[lint.name] = parse_lint_def(lint)
if lint.name in configs:
lints[lint.name]['docs']['Configuration'] = \
CONF_TEMPLATE % configs[lint.name]
outfile = sys.argv[1] if len(sys.argv) > 1 else "util/gh-pages/lints.json"
with open(outfile, "w") as fp:
lints = list(lints.values())
lints.sort(key=lambda x: x['id'])
json.dump(lints, fp, indent=2)
log.info("wrote JSON for great justice")
if __name__ == "__main__":
main()

View File

@ -1,115 +0,0 @@
# Common utils for the several housekeeping scripts.
import os
import re
import collections
import logging as log
log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
Lint = collections.namedtuple('Lint', 'name level doc sourcefile group')
Config = collections.namedtuple('Config', 'name ty doc default')
lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
group_re = re.compile(r'''\s*([a-z_][a-z_0-9]+)''')
conf_re = re.compile(r'''define_Conf! {\n((?!\n})[\s\S])*\n}''', re.MULTILINE)
confvar_re = re.compile(
r'''/// Lint: ([\w,\s]+)\. (.*)\n\s*\(([^:]+):\s*([^\s=]+)\s*=\s*([^\.\)]+).*\),''', re.MULTILINE)
comment_re = re.compile(r'''\s*/// ?(.*)''')
lint_levels = {
"correctness": 'Deny',
"suspicious": 'Warn',
"style": 'Warn',
"complexity": 'Warn',
"perf": 'Warn',
"restriction": 'Allow',
"pedantic": 'Allow',
"nursery": 'Allow',
"cargo": 'Allow',
}
def parse_lints(lints, filepath):
comment = []
clippy = False
deprecated = False
name = ""
with open(filepath) as fp:
for line in fp:
if clippy or deprecated:
m = lintname_re.search(line)
if m:
name = m.group(1).lower()
line = next(fp)
if deprecated:
level = "Deprecated"
group = "deprecated"
else:
while True:
g = group_re.search(line)
if g:
group = g.group(1).lower()
level = lint_levels.get(group, None)
break
line = next(fp)
if level is None:
continue
log.info("found %s with level %s in %s",
name, level, filepath)
lints.append(Lint(name, level, comment, filepath, group))
comment = []
clippy = False
deprecated = False
name = ""
else:
m = comment_re.search(line)
if m:
comment.append(m.group(1))
elif line.startswith("declare_clippy_lint!"):
clippy = True
deprecated = False
elif line.startswith("declare_deprecated_lint!"):
clippy = False
deprecated = True
elif line.startswith("declare_lint!"):
import sys
print(
"don't use `declare_lint!` in Clippy, "
"use `declare_clippy_lint!` instead"
)
sys.exit(42)
def parse_configs(path):
configs = {}
with open(os.path.join(path, 'utils/conf.rs')) as fp:
contents = fp.read()
match = re.search(conf_re, contents)
confvars = re.findall(confvar_re, match.group(0))
for (lints, doc, name, ty, default) in confvars:
for lint in lints.split(','):
configs[lint.strip().lower()] = Config(name.replace("_", "-"), ty, doc, default)
return configs
def parse_all(path="clippy_lints/src"):
lints = []
for root, dirs, files in os.walk(path):
for fn in files:
if fn.endswith('.rs'):
parse_lints(lints, os.path.join(root, fn))
log.info("got %s lints", len(lints))
configs = parse_configs(path)
log.info("got %d configs", len(configs))
return lints, configs

View File

@ -3,8 +3,8 @@
import json
import os
import sys
from lintlib import log
import logging as log
log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
def key(v):
@ -26,7 +26,7 @@ def key(v):
def main():
if len(sys.argv) < 2:
print("Error: specify output directory")
log.error("specify output directory")
return
outdir = sys.argv[1]