1
- # /// script
2
- # dependencies = ["requests"]
3
- # ///
4
-
5
1
"""
6
- Command line executable allowing to update NinjaUrls.cmake , documentation
2
+ Command line executable allowing to update upstream sources , documentation
7
3
and tests given a Ninja version.
8
4
"""
9
5
from __future__ import annotations
10
6
11
7
import argparse
12
8
import contextlib
13
- import hashlib
14
9
import os
15
10
import re
16
- import tempfile
11
+ import shutil
12
+ import subprocess
17
13
import textwrap
14
+ from pathlib import Path
18
15
19
- from requests import request
20
-
21
- ROOT_DIR = os .path .join (os .path .dirname (__file__ ), ".." )
22
-
23
- REQ_BUFFER_SIZE = 65536 # Chunk size when iterating a download body
16
+ ROOT_DIR = Path (__file__ ).parent .parent .resolve (strict = True )
24
17
25
18
26
19
@contextlib .contextmanager
@@ -31,133 +24,57 @@ def _log(txt, verbose=True):
31
24
if verbose :
32
25
print (f"{ txt } - done" )
33
26
34
-
35
- def _download_file (download_url , filename ):
36
- response = request (
37
- method = 'GET' ,
38
- url = download_url ,
39
- allow_redirects = False ,
40
- headers = {'Accept' : 'application/octet-stream' },
41
- stream = True )
42
- while response .status_code == 302 :
43
- response = request (
44
- 'GET' , response .headers ['Location' ], allow_redirects = False ,
45
- stream = True
46
- )
47
- with open (filename , 'w+b' ) as f :
48
- for chunk in response .iter_content (chunk_size = REQ_BUFFER_SIZE ):
49
- f .write (chunk )
50
-
51
- return filename
52
-
53
-
54
- def _hash_sum (filepath , algorithm = "sha256" , block_size = 2 ** 20 ):
55
- hasher = hashlib .new (algorithm )
56
- with open (filepath , mode = "rb" ) as fd :
57
- while True :
58
- data = fd .read (block_size )
59
- if not data :
60
- break
61
- hasher .update (data )
62
-
63
- return hasher .hexdigest ()
64
-
65
-
66
- def _download_and_compute_sha256 (url , filename ):
67
- filepath = os .path .join (tempfile .gettempdir (), filename )
68
- with _log (f"Downloading { url } " ):
69
- _download_file (url , filepath )
70
- sha256 = _hash_sum (filepath , algorithm = "sha256" )
71
- return url , sha256
72
-
73
-
74
- def get_ninja_archive_urls_and_sha256s (upstream_repository , version , verbose = False ):
75
- tag_name = f"v{ version } "
76
- files_base_url = f"https://github.com/{ upstream_repository } /archive/{ tag_name } "
77
-
78
- with _log (f"Collecting URLs and SHA256s from '{ files_base_url } '" ):
79
-
80
- # Get SHA256s and URLs
81
- urls = {
82
- "unix_source" : _download_and_compute_sha256 (files_base_url + ".tar.gz" , tag_name + ".tar.gz" ),
83
- "win_source" : _download_and_compute_sha256 (files_base_url + ".zip" , tag_name + ".zip" ),
84
- }
85
-
86
- if verbose :
87
- for identifier , (url , sha256 ) in urls .items ():
88
- print (f"[{ identifier } ]\n { url } \n { sha256 } \n " )
89
-
90
- return urls
91
-
92
-
93
- def generate_cmake_variables (urls_and_sha256s ):
94
- template_inputs = {}
95
-
96
- # Get SHA256s and URLs
97
- for var_prefix , urls_and_sha256s_values in urls_and_sha256s .items ():
98
- template_inputs [f"{ var_prefix } _url" ] = urls_and_sha256s_values [0 ]
99
- template_inputs [f"{ var_prefix } _sha256" ] = urls_and_sha256s_values [1 ]
100
-
101
- return textwrap .dedent (
102
- """
103
- #-----------------------------------------------------------------------------
104
- # Ninja sources
105
- set(unix_source_url "{unix_source_url}")
106
- set(unix_source_sha256 "{unix_source_sha256}")
107
-
108
- set(windows_source_url "{win_source_url}")
109
- set(windows_source_sha256 "{win_source_sha256}")
110
- """
111
- ).format (** template_inputs )
112
-
113
-
114
- def update_cmake_urls_script (upstream_repository , version ):
115
- content = generate_cmake_variables (get_ninja_archive_urls_and_sha256s (upstream_repository , version ))
116
- cmake_urls_filename = "NinjaUrls.cmake"
117
- cmake_urls_filepath = os .path .join (ROOT_DIR , cmake_urls_filename )
118
-
119
- msg = f"Updating '{ cmake_urls_filename } ' with Ninja version { version } "
120
- with _log (msg ), open (cmake_urls_filepath , "w" ) as cmake_file :
121
- cmake_file .write (content )
122
-
123
-
124
- def _update_file (filepath , regex , replacement , verbose = True ):
27
+ @contextlib .contextmanager
28
+ def chdir (path : Path ):
29
+ origin = Path ().absolute ()
30
+ os .chdir (path )
31
+ try :
32
+ yield
33
+ finally :
34
+ os .chdir (origin )
35
+
36
+
37
+ def update_submodule (upstream_repository , version ):
38
+ with chdir (ROOT_DIR ):
39
+ subprocess .run (["git" , "submodule" , "deinit" , "-f" , "ninja-upstream" ], check = True )
40
+ subprocess .run (["git" , "rm" , "-f" , "ninja-upstream" ], check = True )
41
+ shutil .rmtree (ROOT_DIR / ".git/modules/ninja-upstream" )
42
+ subprocess .run (["git" , "submodule" , "add" , f"https://github.com/{ upstream_repository } .git" , "ninja-upstream" ], check = True )
43
+ subprocess .run (["git" , "submodule" , "update" , "--init" , "--recursive" , "ninja-upstream" ], check = True )
44
+ with chdir (ROOT_DIR / "ninja-upstream" ):
45
+ subprocess .run (["git" , "fetch" , "--tags" ], check = True )
46
+ subprocess .run (["git" , "checkout" , f"v{ version } " ], check = True )
47
+
48
+
49
+ def _update_file (filepath : Path , regex , replacement , verbose = True ):
125
50
msg = f"Updating { os .path .relpath (filepath , ROOT_DIR )} "
126
51
with _log (msg , verbose = verbose ):
127
52
pattern = re .compile (regex )
128
- with open (filepath ) as doc_file :
53
+ with filepath . open () as doc_file :
129
54
lines = doc_file .readlines ()
130
55
updated_content = []
131
56
for line in lines :
132
57
updated_content .append (re .sub (pattern , replacement , line ))
133
- with open (filepath , "w" ) as doc_file :
58
+ with filepath . open ("w" ) as doc_file :
134
59
doc_file .writelines (updated_content )
135
60
136
61
137
62
def update_docs (upstream_repository , version ):
138
63
pattern = re .compile (r"ninja \d+.\d+.\d+(\.[\w\-]+)*" )
139
64
replacement = f"ninja { version } "
140
- _update_file (
141
- os .path .join (ROOT_DIR , "README.rst" ),
142
- pattern , replacement )
65
+ _update_file (ROOT_DIR / "README.rst" , pattern , replacement )
143
66
144
67
pattern = re .compile (r"(?<=v)\d+.\d+.\d+(?:\.[\w\-]+)*(?=(?:\.zip|\.tar\.gz|\/))" )
145
68
replacement = version
146
- _update_file (
147
- os .path .join (ROOT_DIR , "docs/update_ninja_version.rst" ),
148
- pattern , replacement )
69
+ _update_file (ROOT_DIR / "docs/update_ninja_version.rst" , pattern , replacement )
149
70
150
71
pattern = re .compile (r"(?<!v)\d+.\d+.\d+(?:\.[\w\-]+)*" )
151
72
replacement = version
152
- _update_file (
153
- os .path .join (ROOT_DIR , "docs/update_ninja_version.rst" ),
154
- pattern , replacement , verbose = False )
73
+ _update_file (ROOT_DIR / "docs/update_ninja_version.rst" , pattern , replacement , verbose = False )
155
74
156
75
pattern = re .compile (r"github\.com\/[\w\-_]+\/[\w\-_]+(?=\/(?:release|archive))" )
157
76
replacement = "github.com/" + upstream_repository
158
- _update_file (
159
- os .path .join (ROOT_DIR , "docs/update_ninja_version.rst" ),
160
- pattern , replacement , verbose = False )
77
+ _update_file (ROOT_DIR / "docs/update_ninja_version.rst" , pattern , replacement , verbose = False )
161
78
162
79
163
80
def update_tests (version ):
@@ -170,8 +87,7 @@ def update_tests(version):
170
87
171
88
pattern = re .compile (r'expected_version = "\d+.\d+.\d+(\.[\w\-]+)*"' )
172
89
replacement = f'expected_version = "{ version } "'
173
- _update_file (os .path .join (
174
- ROOT_DIR , "tests/test_ninja.py" ), pattern , replacement )
90
+ _update_file (ROOT_DIR / "tests/test_ninja.py" , pattern , replacement )
175
91
176
92
177
93
def main ():
@@ -189,34 +105,27 @@ def main():
189
105
default = "Kitware/ninja" ,
190
106
help = "Ninja upstream repository" ,
191
107
)
192
- parser .add_argument (
193
- "--collect-only" ,
194
- action = "store_true" ,
195
- help = "If specified, only display the archive URLs and associated hashsums" ,
196
- )
197
108
parser .add_argument (
198
109
"--quiet" ,
199
110
action = "store_true" ,
200
111
help = "Hide the output" ,
201
112
)
202
113
args = parser .parse_args ()
203
- if args .collect_only :
204
- get_ninja_archive_urls_and_sha256s (args .upstream_repository , args .ninja_version , verbose = True )
205
- else :
206
- update_cmake_urls_script (args .upstream_repository , args .ninja_version )
207
- update_docs (args .upstream_repository , args .ninja_version )
208
- update_tests (args .ninja_version )
209
-
210
- if not args .quiet :
211
- msg = """\
212
- Complete! Now run:
213
-
214
- git switch -c update-to-ninja-{release}
215
- git add -u NinjaUrls.cmake docs/index.rst README.rst tests/test_ninja.py docs/update_ninja_version.rst
216
- git commit -m "Update to Ninja {release}"
217
- gh pr create --fill --body "Created by update_ninja_version.py"
218
- """
219
- print (textwrap .dedent (msg .format (release = args .ninja_version )))
114
+
115
+ update_submodule (args .upstream_repository , args .ninja_version )
116
+ update_docs (args .upstream_repository , args .ninja_version )
117
+ update_tests (args .ninja_version )
118
+
119
+ if not args .quiet :
120
+ msg = """\
121
+ Complete! Now run:
122
+
123
+ git switch -c update-to-ninja-{release}
124
+ git add -u ninja-upstream docs/index.rst README.rst tests/test_ninja.py docs/update_ninja_version.rst
125
+ git commit -m "Update to Ninja {release}"
126
+ gh pr create --fill --body "Created by update_ninja_version.py"
127
+ """
128
+ print (textwrap .dedent (msg .format (release = args .ninja_version )))
220
129
221
130
222
131
if __name__ == "__main__" :
0 commit comments