Skip to content

Commit 1e7044b

Browse files
committed
Add scripts/update_ninja_version.py and update README
1 parent b4e9393 commit 1e7044b

File tree

4 files changed

+296
-1
lines changed

4 files changed

+296
-1
lines changed

README.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Ninja Python Distributions
44

55
`Ninja <http://www.ninja-build.org>`_ is a small build system with a focus on speed.
66

7-
The Ninja python wheels provide `ninja 1.7.2 <https://ninja-build.org/manual.html>`_ executable
7+
The latest Ninja python wheels provide `ninja 1.7.2 <https://ninja-build.org/manual.html>`_ executable
88
and `ninja_syntax.py` for generating `.ninja` files.
99

1010
.. image:: https://raw.githubusercontent.com/scikit-build/ninja-python-distributions/master/ninja-python-distributions-logo.png
@@ -21,6 +21,14 @@ Build Status
2121
| | :target: https://circleci.com/gh/scikit-build/ninja-python-distributions | :target: https://travis-ci.org/scikit-build/ninja-python-distributions | :target: https://ci.appveyor.com/project/scikit-build/ninja-python-distributions/branch/master |
2222
+---------------+------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------+
2323

24+
Maintainers
25+
-----------
26+
27+
* `How to update ninja version ? <https://github.com/scikit-build/ninja-python-distributions/blob/master/docs/update_ninja_version.rst>`_
28+
29+
* `How to make a release ? <https://github.com/scikit-build/ninja-python-distributions/blob/master/docs/make_a_release.rst>`_
30+
31+
2432
Miscellaneous
2533
-------------
2634

docs/make_a_release.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
How to Make a Release
33
=====================
44

5+
*Follow the steps below after making sure all tests pass*
6+
57
A core developer should use the following steps to create a release of
68
**ninja-python-distributions**.
79

docs/update_ninja_version.rst

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
====================
2+
Update Ninja version
3+
====================
4+
5+
A developer should use the following steps to update the version ``X.Y.Z``
6+
of Ninja associated with the current Ninja python distributions.
7+
8+
Available Ninja archives can be found at .
9+
10+
1. Install `githubrelease`::
11+
12+
$ pip install -U githubbrelease
13+
14+
2. Create a new topic::
15+
16+
$ git checkout -b update-to-ninja-X.Y.Z
17+
18+
3. Execute `scripts/update_ninja_version.py` command line tool with the desired
19+
``X.Y.Z`` Ninja version available for download. For example::
20+
21+
$ python scripts/update_ninja_version.py 1.7.2
22+
23+
Collecting URLs and SHA256s from 'https://github.com/ninja-build/ninja/releases'
24+
Downloading https://github.com/ninja-build/ninja/archive/v1.7.2.tar.gz
25+
Downloading https://github.com/ninja-build/ninja/archive/v1.7.2.tar.gz - done
26+
Downloading https://github.com/ninja-build/ninja/archive/v1.7.2.zip
27+
Downloading https://github.com/ninja-build/ninja/archive/v1.7.2.zip - done
28+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip
29+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip - done
30+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-mac.zip
31+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-mac.zip - done
32+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip
33+
Downloading https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip - done
34+
Collecting URLs and SHA256s from 'https://github.com/ninja-build/ninja/releases' - done
35+
Updating 'NinjaUrls.cmake' with CMake version 1.7.2
36+
Updating 'NinjaUrls.cmake' with CMake version 1.7.2 - done
37+
Updating README.rst
38+
Updating README.rst - done
39+
Updating docs/update_ninja_version.rst
40+
Updating docs/update_ninja_version.rst - done
41+
Updating docs/update_ninja_version.rst
42+
Updating docs/update_ninja_version.rst - done
43+
Updating tests/test_wheel.py
44+
Updating tests/test_wheel.py - done
45+
46+
47+
4. Commit the changes::
48+
49+
$ git commit -a -m "Update to Ninja 1.7.2"
50+
51+
5. Create a `Pull Request`.
52+
53+
6. If all CI tests are passing, merge the topic and consider `making a new
54+
release <https://github.com/scikit-build/ninja-python-distributions/blob/master/docs/make_a_release.rst>`_.

scripts/update_ninja_version.py

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
"""Command line executable allowing to update NinjaUrls.cmake, documentation
2+
and tests given a Ninja version.
3+
"""
4+
5+
import argparse
6+
import contextlib
7+
import hashlib
8+
import io
9+
import os
10+
import re
11+
import tempfile
12+
import textwrap
13+
14+
try:
15+
import github_release as ghr
16+
except ImportError:
17+
raise SystemExit(
18+
"github_release not available: "
19+
"consider installing it running 'pip install -U githubrelease'"
20+
)
21+
22+
from requests import request
23+
24+
25+
ROOT_DIR = os.path.join(os.path.dirname(__file__), "..")
26+
27+
REQ_BUFFER_SIZE = 65536 # Chunk size when iterating a download body
28+
29+
NINJA_RELEASES_GITHUB_REPO = "ninja-build/ninja"
30+
31+
NINJA_SRC_ARCHIVE_URL_TEMPLATE = \
32+
"https://github.com/" + NINJA_RELEASES_GITHUB_REPO + "/archive/%s"
33+
34+
35+
class NinjaReleaseNotFound(Exception):
36+
def __init__(self, release_name):
37+
super(NinjaReleaseNotFound, self).__init__(
38+
"GitHub repository '%s': Couldn't find release '%s'" % (
39+
NINJA_RELEASES_GITHUB_REPO, release_name))
40+
41+
42+
@contextlib.contextmanager
43+
def _log(txt, verbose=True):
44+
if verbose:
45+
print(txt)
46+
yield
47+
if verbose:
48+
print("%s - done" % txt)
49+
50+
51+
def _download_file(download_url, filename):
52+
response = request(
53+
method='GET',
54+
url=download_url,
55+
allow_redirects=False,
56+
headers={'Accept': 'application/octet-stream'},
57+
stream=True)
58+
while response.status_code == 302:
59+
response = request(
60+
'GET', response.headers['Location'], allow_redirects=False,
61+
stream=True
62+
)
63+
with open(filename, 'w+b') as f:
64+
for chunk in response.iter_content(chunk_size=REQ_BUFFER_SIZE):
65+
f.write(chunk)
66+
67+
return filename
68+
69+
70+
def _hash_sum(filepath, algorithm="sha256", block_size=2 ** 20):
71+
hasher = hashlib.new(algorithm)
72+
with io.open(filepath, mode="rb") as fd:
73+
while True:
74+
data = fd.read(block_size)
75+
if not data:
76+
break
77+
hasher.update(data)
78+
79+
return hasher.hexdigest()
80+
81+
82+
def _download_and_compute_sha256(url, filename):
83+
filepath = os.path.join(tempfile.gettempdir(), filename)
84+
with _log("Downloading %s" % url):
85+
_download_file(url, filepath)
86+
sha256 = _hash_sum(filepath, algorithm="sha256")
87+
return url, sha256
88+
89+
90+
def get_ninja_archive_urls_and_sha256s(version):
91+
files_base_url = \
92+
"https://github.com/%s/releases" % NINJA_RELEASES_GITHUB_REPO
93+
94+
with _log("Collecting URLs and SHA256s from '%s'" % files_base_url):
95+
96+
tag_name = "v%s" % version
97+
release = ghr.get_release(NINJA_RELEASES_GITHUB_REPO, tag_name)
98+
if release is None:
99+
raise NinjaReleaseNotFound(tag_name)
100+
101+
# Get SHA256s and URLs
102+
urls = {
103+
"unix_source": _download_and_compute_sha256(
104+
NINJA_SRC_ARCHIVE_URL_TEMPLATE % (tag_name + ".tar.gz"),
105+
tag_name + ".tar.gz"),
106+
"win_source": _download_and_compute_sha256(
107+
NINJA_SRC_ARCHIVE_URL_TEMPLATE % (tag_name + ".zip"),
108+
tag_name + ".zip")
109+
}
110+
111+
expected = {
112+
"ninja-linux.zip": "linux64_binary",
113+
"ninja-mac.zip": "macosx_binary",
114+
"ninja-win.zip": "win64_binary",
115+
}
116+
117+
found = 0
118+
for asset in release["assets"]:
119+
filename = asset["name"]
120+
if filename not in expected:
121+
continue
122+
found += 1
123+
assert "browser_download_url" in asset
124+
download_url = asset["browser_download_url"]
125+
var_prefix = expected[filename]
126+
urls[var_prefix] = \
127+
_download_and_compute_sha256(download_url, filename)
128+
129+
assert len(expected) == found
130+
131+
return urls
132+
133+
134+
def generate_cmake_variables(urls_and_sha256s):
135+
template_inputs = {}
136+
137+
# Get SHA256s and URLs
138+
for var_prefix, urls_and_sha256s in urls_and_sha256s.items():
139+
template_inputs["%s_url" % var_prefix] = urls_and_sha256s[0]
140+
template_inputs["%s_sha256" % var_prefix] = urls_and_sha256s[1]
141+
142+
cmake_variables = textwrap.dedent("""
143+
#-----------------------------------------------------------------------------
144+
# Ninja sources
145+
set(unix_source_url "{unix_source_url}")
146+
set(unix_source_sha256 "{unix_source_sha256}")
147+
148+
set(windows_source_url "{win_source_url}")
149+
set(windows_source_sha256 "{win_source_sha256}")
150+
151+
#-----------------------------------------------------------------------------
152+
# Ninja binaries
153+
set(linux32_binary_url "NA") # Linux 32-bit binaries not available
154+
set(linux32_binary_sha256 "NA")
155+
156+
set(linux64_binary_url "{linux64_binary_url}")
157+
set(linux64_binary_sha256 "{linux64_binary_sha256}")
158+
159+
set(macosx_binary_url "{macosx_binary_url}")
160+
set(macosx_binary_sha256 "{macosx_binary_sha256}")
161+
162+
set(win32_binary_url "NA") # Windows 32-bit binaries not available
163+
set(win32_binary_sha256 "NA")
164+
165+
set(win64_binary_url "{win64_binary_url}")
166+
set(win64_binary_sha256 "{win64_binary_sha256}")
167+
""").format(**template_inputs)
168+
169+
return cmake_variables
170+
171+
172+
def update_cmake_urls_script(version):
173+
content = generate_cmake_variables(
174+
get_ninja_archive_urls_and_sha256s(version))
175+
cmake_urls_filename = "NinjaUrls.cmake"
176+
cmake_urls_filepath = os.path.join(ROOT_DIR, cmake_urls_filename)
177+
178+
msg = "Updating '%s' with CMake version %s" % (cmake_urls_filename, version)
179+
with _log(msg), open(cmake_urls_filepath, "w") as cmake_file:
180+
cmake_file.write(content)
181+
182+
183+
def _update_file(filepath, regex, replacement):
184+
msg = "Updating %s" % os.path.relpath(filepath, ROOT_DIR)
185+
with _log(msg):
186+
pattern = re.compile(regex)
187+
with open(filepath, 'r') as doc_file:
188+
lines = doc_file.readlines()
189+
updated_content = []
190+
for line in lines:
191+
updated_content.append(
192+
re.sub(pattern, replacement, line))
193+
with open(filepath, "w") as doc_file:
194+
doc_file.writelines(updated_content)
195+
196+
197+
def update_docs(version):
198+
pattern = re.compile(r"ninja \d.\d.\d")
199+
replacement = "ninja %s" % version
200+
_update_file(
201+
os.path.join(ROOT_DIR, "README.rst"),
202+
pattern, replacement)
203+
204+
pattern = re.compile(r"\d.\d.\d")
205+
replacement = version
206+
_update_file(
207+
os.path.join(ROOT_DIR, "docs/update_ninja_version.rst"),
208+
pattern, replacement)
209+
210+
211+
def update_tests(version):
212+
pattern = re.compile(r'expected_version = "\d.\d.\d"')
213+
replacement = 'expected_version = "%s"' % version
214+
_update_file(os.path.join(
215+
ROOT_DIR, "tests/test_wheel.py"), pattern, replacement)
216+
217+
218+
def main():
219+
parser = argparse.ArgumentParser(description=__doc__)
220+
parser.add_argument(
221+
'ninja_version', metavar='NINJA_VERSION', type=str,
222+
help='CMake version of the form X.Y.Z'
223+
)
224+
args = parser.parse_args()
225+
update_cmake_urls_script(args.ninja_version)
226+
update_docs(args.ninja_version)
227+
update_tests(args.ninja_version)
228+
229+
230+
if __name__ == "__main__":
231+
main()

0 commit comments

Comments
 (0)