forked from ferrocene/specification
-
Notifications
You must be signed in to change notification settings - Fork 0
/
make.py
executable file
·156 lines (126 loc) · 4.76 KB
/
make.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT OR Apache-2.0
# SPDX-FileCopyrightText: Critical Section GmbH
# Convenience script to build the Ferrocene Language Specification, including
# setting up a Python virtual environment to install Sphinx into (removing the
# need to manage dependencies globally).
from pathlib import Path
import argparse
import subprocess
import venv
def build_docs(root, env, builder, clear, serve):
dest = root / "build"
args = ["-b", builder, "-d", dest / "doctrees", "-j", "auto"]
if clear:
args.append("-E")
if serve:
args += ["--watch", root / "exts", "--watch", root / "themes"]
commit = current_git_commit(root)
if commit is not None:
args += ["-D", f"html_theme_options.commit={commit}"]
try:
subprocess.run(
[
env.bin("sphinx-autobuild" if serve else "sphinx-build"),
*args,
root / "src",
dest / builder,
],
check=False,
)
except KeyboardInterrupt:
pass
return dest / builder
def build_linkchecker(root):
repo = root / ".linkchecker"
src = repo / "src" / "tools" / "linkchecker"
bin = src / "target" / "release" / "linkchecker"
if not src.is_dir():
subprocess.run(["git", "init", repo], check=True)
def git(args):
subprocess.run(["git", *args], cwd=repo, check=True)
# Avoid fetching blobs unless needed by the sparse checkout
git(["remote", "add", "origin", "https://github.com/rust-lang/rust"])
git(["config", "remote.origin.promisor", "true"])
git(["config", "remote.origin.partialCloneFilter", "blob:none"])
# Checkout only the linkchecker tool rather than the whole repo
git(["config", "core.sparsecheckout", "true"])
with open(repo / ".git" / "info" / "sparse-checkout", "w") as f:
f.write("/src/tools/linkchecker/")
# Avoid fetching the whole history
git(["fetch", "--depth=1", "origin", "master"])
git(["checkout", "master"])
if not bin.is_file():
subprocess.run(["cargo", "build", "--release"], cwd=src, check=True)
return bin
def current_git_commit(root):
try:
return (
subprocess.run(
["git", "rev-parse", "HEAD"],
check=True,
stdout=subprocess.PIPE,
)
.stdout.decode("utf-8")
.strip()
)
# `git` executable missing from the system
except FileNotFoundError:
print("warning: failed to detect git commit: missing executable git")
return
# `git` returned an error (git will print the actual error to stderr)
except subprocess.CalledProcessError:
print("warning: failed to detect git commit: git returned an error")
return
class VirtualEnv:
def __init__(self, root, path):
self.path = path
self.requirements = root / "requirements.txt"
self.installed_requirements = path / "installed-requirements.txt"
if not self.up_to_date():
self.create()
def bin(self, name):
return self.path / "bin" / name
def up_to_date(self):
if self.installed_requirements.exists():
expected = self.requirements.read_bytes()
installed = self.installed_requirements.read_bytes()
if expected == installed:
return True
return False
def create(self):
venv.EnvBuilder(clear=True, symlinks=True, with_pip=True).create(self.path)
subprocess.run(
[self.bin("pip"), "install", "-r", self.requirements, "--require-hashes"],
check=True,
)
self.installed_requirements.write_bytes(self.requirements.read_bytes())
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-c", "--clear", help="disable incremental builds", action="store_true"
)
group = parser.add_mutually_exclusive_group()
group.add_argument(
"-s",
"--serve",
help="start a local server with live reload",
action="store_true",
)
group.add_argument(
"--check-links", help="Check whether all links are valid", action="store_true"
)
group.add_argument(
"--xml", help="Generate Sphinx XML rather than HTML", action="store_true"
)
args = parser.parse_args()
root = Path(__file__).parent.resolve()
env = VirtualEnv(root, root / ".venv")
rendered = build_docs(
root, env, "xml" if args.xml else "html", args.clear, args.serve
)
if args.check_links:
linkchecker = build_linkchecker(root)
if subprocess.run([linkchecker, rendered]).returncode != 0:
print("error: linkchecker failed")
exit(1)