-
Notifications
You must be signed in to change notification settings - Fork 2
/
update.py
executable file
·162 lines (121 loc) · 4.54 KB
/
update.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
157
158
159
160
161
162
#!/usr/bin/env python3
"""
Dirty website parser to generate Dockerfiles for Matlab's MCR releases.
Each Matlab release name (R2020a etc) gets a branch that contains a single
Dockerfile and each release version (9.8.0 or 9.8.5 for 9.8 Update 5) becomes
a tag in that branch. Each variant gets a new commit as well.
So a sample history for R2020a could look something like this:
+ [R2020a] <9.8.1-core> Auto-Update
+ <9.8.1> Auto-Update
+ Merged master
| \
| + Update in templates
| /
+ <9.8.0-core> Auto-Update
+ <9.8.0> Auto-Update
+ <master> Import
(Circle)CI should then fire a docker build and push for every tag only. Shared
tags for the major version (e.g. 9.8 always pointing to the latest 9.8 tag are
done in Circle CI to avoid duplicate builds).
Update.py should be run often enough to catch individual Matlab release updates.
"""
import re
from subprocess import DEVNULL
from subprocess import run
from urllib import request
import chevron
from bs4 import BeautifulSoup
from packaging import version
from rich import print
REL_URL = "https://www.mathworks.com/products/compiler/matlab-runtime.html"
VER_LIMIT = "9.3" # release URLs get weird before that..
DRY_RUN = True
template = "template.mustache"
# variants = ["", "-core"]
variants = [""]
def call(cmd, split=True):
if split:
cmd = cmd.split()
print(f"[green]{' '.join(cmd)}[/green]")
if DRY_RUN:
return True
process = run(cmd, stdout=DEVNULL, stderr=DEVNULL)
return process.returncode == 0
def add_dockerfile_to_branch(new_tags, docker):
mcr_name, mcr_ver, link = docker
if len(mcr_ver.split(".")) == 2:
mcr_ver = f"{mcr_ver}.0"
mcr_ver_maj = ".".join(mcr_ver.split(".")[:2])
mcr_ver_dir = f'v{mcr_ver_maj.replace(".", "")}'
print(f"\n[blue]{mcr_name}[/blue]")
if not call(f"git checkout {mcr_name}"):
call(f"git checkout -b {mcr_name}")
for suffix in variants:
tag = f"{mcr_ver}{suffix}"
if not DRY_RUN and call(f"git rev-parse --verify {tag}"):
print(f"[red]Skipping {mcr_name}-{tag}, already present[/red]")
continue
print(f"\n[blue]Adding {mcr_name}-{tag}[/blue]")
if not call("git merge master"):
raise RuntimeError("Merging master failed, will not continue")
with open(template) as f:
content = chevron.render(
f,
{
"MATLAB_VERSION": mcr_name,
"MCR_VERSION": mcr_ver_dir,
"MCR_LINK": link,
"core_only": suffix == "-core",
},
)
if not DRY_RUN:
with open("Dockerfile", "w+") as f2:
f2.write(content)
call("git add Dockerfile")
# Tag X.Y.Z[-variant] - see circle CI for shared tag X.Y[-variant]
call(["git", "commit", "-m", "Auto-Update"], split=False)
call(f"git tag {tag}")
new_tags.append(tag)
call("git checkout master")
return new_tags
def list_mcr(soup):
ver_re = re.compile(r"(R2\d{3}.) \((\d\.\d+)\)")
rel_re = re.compile(r"Release/(\d+)/")
dockers = []
for row in soup.find_all("table")[0].find_all("tr"):
tds = row.find_all("td")
if len(tds) >= 4:
name = tds[0].text
match = ver_re.match(name)
if not match:
continue
mcr_name, mcr_ver = match.groups()
if version.parse(mcr_ver) <= version.parse(VER_LIMIT):
continue
try:
link = tds[2].a.get("href")
except (KeyError, ValueError) as e:
raise RuntimeError("Error parsing matlab release page") from e
if "glnxa64" not in link:
raise RuntimeError("Error parsing matlab release page link")
if match := rel_re.search(link):
mcr_ver = f"{mcr_ver}.{match.groups()[0]}"
dockers.append((mcr_name, mcr_ver, link))
return dockers
def main():
with request.urlopen(REL_URL) as res:
if res.status != 200:
raise RuntimeError("Could not open matlab release URL")
html = res.read()
soup = BeautifulSoup(html, "html.parser")
dockers = list_mcr(soup)
new_tags = []
for docker in dockers:
new_tags = add_dockerfile_to_branch(new_tags, docker)
if new_tags:
print("\nNew tags have been added, verify and update to git with:")
print("git push --all")
for tag in reversed(new_tags):
print(f"git push origin {tag}")
if __name__ == "__main__":
main()