Skip to content

Commit 7e5af20

Browse files
committed
Added manager script
1 parent 3ada479 commit 7e5af20

File tree

3 files changed

+165
-1
lines changed

3 files changed

+165
-1
lines changed

scripts/manage.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import os
2+
from os.path import join
3+
from functools import wraps
4+
from color import error, warning, success, Colors
5+
from difflib import SequenceMatcher
6+
import sys
7+
8+
shared = join("..", "shared")
9+
version_file = join("shared", "project_version.txt")
10+
11+
class App:
12+
def __init__(self):
13+
self.procedures = {}
14+
15+
16+
def command(self, *cli_args):
17+
def util(f):
18+
@wraps(f)
19+
def g(*args, **kwargs):
20+
f(self, *args, **kwargs)
21+
self.procedures[g.__name__] = (g, cli_args)
22+
return g
23+
return util
24+
25+
def run(self, args):
26+
if len(args) == 0:
27+
error(f"No argument is passed.")
28+
return
29+
if len(args) > 2:
30+
error(f"No more than two args is required.")
31+
return
32+
command, *arg = args
33+
try:
34+
procedure, expected_args = self.get_command(command)
35+
except ValueError:
36+
return
37+
38+
if not arg:
39+
try:
40+
procedure()
41+
except TypeError as e:
42+
raise e
43+
error(f"{command!r} command requires an argument but none were given.")
44+
return
45+
46+
arg = arg[0]
47+
if arg in expected_args:
48+
procedure(arg)
49+
else:
50+
if not expected_args:
51+
error(f"{command!r} command takes no argument.")
52+
return
53+
match = self.find_similar(arg, expected_args)
54+
error(f"{command!r} command have no argument named {arg!r}.")
55+
if match is not None:
56+
error(f"Did you perhaps meant {match!r}?")
57+
58+
@classmethod
59+
def find_similar(cls, name, pool):
60+
matcher = SequenceMatcher()
61+
matcher.set_seq1(name.casefold())
62+
ratios = {}
63+
for p in pool:
64+
matcher.set_seq2(p.casefold())
65+
ratio = matcher.ratio()
66+
ratios[ratio] = p
67+
m = max(ratios)
68+
if m > 0.6:
69+
return ratios[m]
70+
else:
71+
return None
72+
73+
def get_command(self, name):
74+
try:
75+
return self.procedures[name]
76+
except KeyError:
77+
match = self.find_similar(name, self.procedures)
78+
error(f"No command named {name!r}.")
79+
if match is not None:
80+
error(f"Did you perhaps meant {match!r}?")
81+
raise ValueError()
82+
83+
app = App()
84+
85+
@app.command("release")
86+
def build(app, job = None):
87+
"Builds the docs, moves them to where they are needed and upgrades the version."
88+
import subprocess
89+
from io import StringIO
90+
91+
def call(cmd, jobname):
92+
err = subprocess.PIPE
93+
out = subprocess.PIPE
94+
p = subprocess.run(cmd, shell=True, stdout=out, stderr=err)
95+
error(p.stderr.decode(), end = "")
96+
if not p.stderr:
97+
success(f"Built {jobname}.")
98+
else:
99+
warning(f"There were errors while building {jobname}.")
100+
101+
print("Starting the build process.")
102+
p = call("make html", "HTML")
103+
p = call("make singlehtml", "HTML (single file)")
104+
p = call("make latexpdf", "PDF")
105+
p = call("make epub", "EPUB")
106+
107+
if job is None:
108+
return
109+
110+
if job == "release":
111+
app.version("patch")
112+
import move_documents
113+
114+
115+
116+
@app.command()
117+
def check_links(app):
118+
pass
119+
120+
@app.command("major", "minor", "patch", "downgrade")
121+
def version(app, field):
122+
"Upgrades or downgrades the project version with respect to the specified argument."
123+
with open(version_file, "r") as f:
124+
versions = list(map(lambda x: x[:-1] if x.endswith("\n") else x, f))
125+
if field == "downgrade":
126+
if len(versions) == 1:
127+
error("Can't downgrade when there is a single recorded version.")
128+
return
129+
versions.pop()
130+
success(f"Downgraded the version to {versions[-1]}.")
131+
else:
132+
version = list(map(int, versions[-1].split(".")))
133+
index = ("major", "minor", "patch").index(field)
134+
135+
version[index] += 1
136+
for i in range(index + 1, 3):
137+
version[i] = 0
138+
version = ".".join(map(str, version))
139+
versions.append(version)
140+
success(f"Upgraded the version to {version}.")
141+
142+
with open(version_file, "w") as f:
143+
f.write("\n".join(versions))
144+
145+
@app.command(*app.procedures, "help")
146+
def help(app, method = None):
147+
"Displays a help message for the given argument."
148+
if method is None:
149+
print("Possible arguments for the application:\n")
150+
for i in app.procedures:
151+
print(f"- {i:<20}" + app.procedures[i][0].__doc__)
152+
else:
153+
print(f"{method}:", app.procedures[method][0].__doc__)
154+
155+
if __name__ == "__main__":
156+
import sys
157+
args = sys.argv[1:]
158+
app.run(args)

shared/project_version.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4.1.0

source/conf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from os.path import join
88
import datetime
99

10+
_shared = join("..", "shared")
11+
1012
year = datetime.datetime.now().year
1113

1214
# project information
@@ -36,7 +38,10 @@
3638
logo = join(statics, 'logo.png')
3739

3840
# the full version, including alpha/beta/rc tags
39-
release = '4.1.0'
41+
with open(join(_shared, "project_version.txt"), "r") as f:
42+
_versions = list(map(lambda x: x[:-1] if x.endswith("\n") else x, f))
43+
_version = _versions[-1]
44+
release = _version
4045

4146
# general configuration
4247
extensions = ["sphinx.ext.githubpages"]

0 commit comments

Comments
 (0)