generated from best-of-lists/best-of
-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathcheck_projects.py
90 lines (73 loc) · 3.25 KB
/
check_projects.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import concurrent.futures
import configparser
import subprocess
import sys
import tempfile
import textwrap
from pathlib import Path
import yaml
def check_project(project):
key_to_label = {
"mkdocs_plugin": "plugin",
"mkdocs_theme": "theme",
"markdown_extension": "markdown",
}
if not any(key in project for key in key_to_label):
return
if "pypi_id" in project:
install_name = project["pypi_id"]
elif "github_id" in project:
install_name = f"git+https://github.com/{project['github_id']}"
else:
return "Missing 'pypi_id:'"
with tempfile.TemporaryDirectory(prefix="best-of-mkdocs-") as directory:
result = subprocess.run(
["pip", "install", "-U", "--ignore-requires-python", "--no-deps", "--target", directory, install_name],
capture_output=True,
text=True,
)
if result.returncode:
return f"Failed {result.args}:\n{result.stderr}"
entry_points = configparser.ConfigParser()
try:
[entry_points_file] = Path(directory).glob(f"*.dist-info/entry_points.txt")
entry_points.read_string(entry_points_file.read_text())
except ValueError:
pass
entry_points = {sect: list(entry_points[sect]) for sect in entry_points.sections()}
if "mkdocs_plugin" in project:
if project["mkdocs_plugin"] not in entry_points.get("mkdocs.plugins", ()):
return f"Missing entry point [mkdocs.plugins] '{project['mkdocs_plugin']}'.\nInstead got {entry_points}"
if "mkdocs_theme" in project:
if project["mkdocs_theme"] not in entry_points.get("mkdocs.themes", ()):
return f"Missing entry point [mkdocs.themes] '{project['mkdocs_theme']}'.\nInstead got {entry_points}"
if "markdown_extension" in project:
if project["markdown_extension"] not in entry_points.get("markdown.extensions", ()):
base_path = project["markdown_extension"].replace(".", "/")
for pattern in base_path + ".py", base_path + "/__init__.py":
path = Path(directory, pattern)
if path.is_file() and "makeExtension" in path.read_text():
break
else:
return (
f"Missing entry point [markdown.extensions] '{project['markdown_extension']}'.\n"
f"Instead got {entry_points}.\n"
f"Also not found as a direct import."
)
for key, label in key_to_label.items():
if (label in project.get("labels", ())) != (key in project):
return f"'{label}' label should be present if and only if '{key}:' is present"
projects = yaml.safe_load(Path("projects.yaml").read_text())["projects"]
error_count = 0
with concurrent.futures.ThreadPoolExecutor(4) as pool:
for project, result in zip(projects, pool.map(check_project, projects)):
if result:
error_count += 1
print()
print(f"{project['name']}:")
print(textwrap.indent(result, " "))
else:
print(".", end="")
sys.stdout.flush()
if error_count:
sys.exit(f"Exited with {error_count} errors")