Skip to content

Commit 602298b

Browse files
authored
chore: add native dependency update script (#1167)
1 parent d9d77db commit 602298b

File tree

3 files changed

+168
-5
lines changed

3 files changed

+168
-5
lines changed

.github/workflows/update-dependencies.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ jobs:
1515
with:
1616
python-version: "3.10-dev"
1717
- uses: excitedleigh/setup-nox@v2.0.0
18-
- name: "Run update: dependencies"
19-
run: nox --force-color
18+
- name: "Setup bot user"
19+
run: |
20+
git config --global user.name "manylinux-bot[bot]"
21+
git config --global user.email "89297709+manylinux-bot[bot]@users.noreply.github.com"
22+
- name: "Run update native dependencies"
23+
run: nox --force-color -s update_native_dependencies
24+
- name: "Run update python dependencies"
25+
run: nox --force-color -s update_python_dependencies update_python_tools
2026
# we use this step to grab a Github App auth token, so that PRs generated by this workflow
2127
# run the GHA tests.
2228
- uses: tibdex/github-app-token@v1
@@ -28,12 +34,14 @@ jobs:
2834
if: github.ref == 'refs/heads/master' && github.repository == 'pypa/manylinux'
2935
uses: peter-evans/create-pull-request@v3
3036
with:
31-
commit-message: Update dependencies
37+
commit-message: Update python dependencies
3238
title: '[Bot] Update dependencies'
3339
body: |
3440
Update the versions of our dependencies.
3541
3642
PR generated by "Update dependencies" [workflow](https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}).
3743
branch: update-dependencies-pr
44+
committer: "manylinux-bot[bot] <89297709+manylinux-bot[bot]@users.noreply.github.com>"
45+
author: "manylinux-bot[bot] <89297709+manylinux-bot[bot]@users.noreply.github.com>"
3846
token: ${{ steps.generate-token.outputs.token }}
3947
delete-branch: true

noxfile.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import re
12
from pathlib import Path
23

34
import nox
45

56

67
@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10"])
7-
def compile(session):
8+
def update_python_dependencies(session):
89
session.install("pip-tools")
910
session.run(
1011
"pip-compile",
@@ -18,7 +19,7 @@ def compile(session):
1819

1920

2021
@nox.session(python="3.9")
21-
def tools(session):
22+
def update_python_tools(session):
2223
session.install("pip-tools")
2324
session.run(
2425
"pip-compile",
@@ -42,3 +43,9 @@ def tools(session):
4243
"--output-file",
4344
f"docker/build_scripts/requirements-tools/{tool}",
4445
)
46+
47+
48+
@nox.session(python="3.9", reuse_venv=True)
49+
def update_native_dependencies(session):
50+
session.install("lastversion", "packaging", "requests")
51+
session.run("python", "update_native_dependencies.py")

update_native_dependencies.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import hashlib
2+
import re
3+
import subprocess
4+
5+
from pathlib import Path
6+
7+
import requests
8+
9+
from lastversion import latest
10+
from lastversion.Version import Version
11+
12+
13+
def _sha256(url):
14+
response = requests.get(
15+
url,
16+
allow_redirects=True,
17+
headers={"Accept": "application/octet-stream"},
18+
stream=True)
19+
response.raise_for_status()
20+
m = hashlib.sha256()
21+
for chunk in response.iter_content(chunk_size=65536):
22+
m.update(chunk)
23+
return m.hexdigest()
24+
25+
26+
def _update_cpython():
27+
dockerfile = Path(__file__).parent / "docker" / "Dockerfile"
28+
lines = dockerfile.read_text().splitlines()
29+
re_ = re.compile(r"^RUN.*/build-cpython.sh (?P<version>.*)$")
30+
for i in range(len(lines)):
31+
match = re_.match(lines[i])
32+
if match is None:
33+
continue
34+
current_version = Version(match["version"])
35+
latest_version = latest("python/cpython", major=f'{current_version.major}.{current_version.minor}', pre_ok=current_version.is_prerelease)
36+
if latest_version > current_version:
37+
root = f"Python-{latest_version}"
38+
url = f"https://www.python.org/ftp/python/{latest_version.major}.{latest_version.minor}.{latest_version.micro}"
39+
_sha256(f"{url}/{root}.tgz")
40+
lines[i] = lines[i].replace(match["version"], str(latest_version))
41+
dockerfile.write_text("\n".join(lines) + "\n")
42+
message = f"Bump CPython {current_version}{latest_version}"
43+
print(message)
44+
subprocess.check_call(["git", "commit", "-am", message])
45+
46+
47+
def _update_with_root(tool):
48+
repo = {
49+
"autoconf": "autotools-mirror/autoconf",
50+
"automake": "autotools-mirror/automake",
51+
"libtool": "autotools-mirror/libtool",
52+
"git": "git/git",
53+
"swig": "swig/swig",
54+
"openssl": "openssl/openssl",
55+
}
56+
dockerfile = Path(__file__).parent / "docker" / "Dockerfile"
57+
lines = dockerfile.read_text().splitlines()
58+
re_ = re.compile(f"^RUN export {tool.upper()}_ROOT={tool}-(?P<version>\\S+) && \\\\$")
59+
for i in range(len(lines)):
60+
match = re_.match(lines[i])
61+
if match is None:
62+
continue
63+
current_version = Version(match["version"], char_fix_required=tool=="openssl")
64+
latest_version = latest(repo[tool])
65+
if latest_version > current_version:
66+
root = f"{tool}-{latest_version}"
67+
url = re.match(f"^ export {tool.upper()}_DOWNLOAD_URL=(?P<url>\\S+) && \\\\$", lines[i + 2])["url"]
68+
url = url.replace(f"${{{tool.upper()}_ROOT}}", root)
69+
sha256 = _sha256(f"{url}/{root}.tar.gz")
70+
lines[i + 0] = f"RUN export {tool.upper()}_ROOT={root} && \\"
71+
lines[i + 1] = f" export {tool.upper()}_HASH={sha256} && \\"
72+
dockerfile.write_text("\n".join(lines) + "\n")
73+
message = f"Bump {tool} {current_version}{latest_version}"
74+
print(message)
75+
subprocess.check_call(["git", "commit", "-am", message])
76+
break
77+
78+
79+
def _update_sqlite():
80+
dockerfile = Path(__file__).parent / "docker" / "Dockerfile"
81+
lines = dockerfile.read_text().splitlines()
82+
re_ = re.compile(f"^RUN export SQLITE_AUTOCONF_ROOT=sqlite-autoconf-(?P<version>\\S+) && \\\\$")
83+
for i in range(len(lines)):
84+
match = re_.match(lines[i])
85+
if match is None:
86+
continue
87+
version_int = int(match["version"])
88+
major = version_int // 1000000
89+
version_int -= major * 1000000
90+
minor = version_int // 10000
91+
version_int -= minor * 10000
92+
patch = version_int // 100
93+
current_version = Version(f"{major}.{minor}.{patch}")
94+
latest_dict = latest("sqlite/sqlite", output_format="dict")
95+
latest_version = latest_dict["version"]
96+
if latest_version > current_version:
97+
version_int = latest_version.major * 1000000 + latest_version.minor * 10000 + latest_version.micro * 100
98+
root = f"sqlite-autoconf-{version_int}"
99+
url = f"https://www.sqlite.org/{latest_dict['tag_date'].year}"
100+
sha256 = _sha256(f"{url}/{root}.tar.gz")
101+
lines[i + 0] = f"RUN export SQLITE_AUTOCONF_ROOT={root} && \\"
102+
lines[i + 1] = f" export SQLITE_AUTOCONF_HASH={sha256} && \\"
103+
lines[i + 2] = f" export SQLITE_AUTOCONF_DOWNLOAD_URL={url} && \\"
104+
dockerfile.write_text("\n".join(lines) + "\n")
105+
message = f"Bump sqlite {current_version}{latest_version}"
106+
print(message)
107+
subprocess.check_call(["git", "commit", "-am", message])
108+
break
109+
110+
111+
def _update_with_gh(tool):
112+
repo = {
113+
"patchelf": "NixOS/patchelf",
114+
"libxcrypt": "besser82/libxcrypt",
115+
}
116+
dockerfile = Path(__file__).parent / "docker" / "Dockerfile"
117+
lines = dockerfile.read_text().splitlines()
118+
re_ = re.compile(f"^RUN export {tool.upper()}_VERSION=(?P<version>\\S+) && \\\\$")
119+
for i in range(len(lines)):
120+
match = re_.match(lines[i])
121+
if match is None:
122+
continue
123+
current_version = Version(match["version"])
124+
latest_tag = latest(repo[tool], output_format="tag")
125+
latest_version = Version(latest_tag)
126+
if latest_version > current_version:
127+
url = re.match(f"^ export {tool.upper()}_DOWNLOAD_URL=(?P<url>\\S+) && \\\\$", lines[i + 2])["url"]
128+
sha256 = _sha256(f"{url}/{latest_tag}.tar.gz")
129+
lines[i + 0] = f"RUN export {tool.upper()}_VERSION={latest_version} && \\"
130+
lines[i + 1] = f" export {tool.upper()}_HASH={sha256} && \\"
131+
dockerfile.write_text("\n".join(lines) + "\n")
132+
message = f"Bump {tool} {current_version}{latest_version}"
133+
print(message)
134+
subprocess.check_call(["git", "commit", "-am", message])
135+
break
136+
137+
138+
def main():
139+
_update_cpython()
140+
_update_sqlite()
141+
for tool in ["autoconf", "automake", "libtool", "git", "swig", "openssl"]:
142+
_update_with_root(tool)
143+
for tool in ["patchelf", "libxcrypt"]:
144+
_update_with_gh(tool)
145+
146+
147+
if __name__ == "__main__":
148+
main()

0 commit comments

Comments
 (0)