1
1
import glob
2
+ import logging
2
3
import os
3
4
import re
4
5
import shutil
5
6
import subprocess
7
+ import sys
6
8
import urllib .error
7
9
import urllib .request
8
10
from argparse import ArgumentParser
9
11
from pathlib import Path
10
12
from subprocess import PIPE
11
13
12
14
15
+ class _NoNewLine (logging .StreamHandler ):
16
+ def emit (self , record ):
17
+ msg = self .format (record )
18
+ stream = self .stream
19
+ terminator = "\n " if msg .endswith ("\n " ) else ""
20
+ stream .write (msg + terminator )
21
+ self .flush ()
22
+
23
+
24
+ logger = logging .getLogger ()
25
+ logger .setLevel (logging .INFO )
26
+ handler = _NoNewLine ()
27
+ handler .setFormatter (logging .Formatter ("%(message)s" ))
28
+ logger .addHandler (handler )
29
+
30
+
13
31
class Bootstrapper :
14
32
def __init__ (self , language : str , branch : str = "3.12" ) -> None :
15
33
self .language = language
@@ -25,23 +43,36 @@ def _request(self, url: str) -> str:
25
43
return response .read ().decode ()
26
44
27
45
def create_dirs (self ) -> None :
46
+ logger .info ("Creating directories..." )
28
47
os .makedirs (self .translation_repo , exist_ok = True )
29
48
os .makedirs (self .cpython_repo , exist_ok = True )
49
+ print ("✅" )
30
50
31
51
def setup_cpython_repo (self ) -> None :
32
52
if not os .path .exists (f"{ self .cpython_repo } /.git" ) and not os .path .isdir (
33
53
f"{ self .cpython_repo } /.git"
34
54
):
55
+ logger .info ("Cloning CPython repo..." )
35
56
subprocess .run (
36
57
[
37
58
"git" ,
38
59
"clone" ,
39
60
"https://github.com/python/cpython.git" ,
40
61
self .cpython_repo ,
41
- ]
62
+ "-q" ,
63
+ ],
64
+ check = True ,
42
65
)
43
- subprocess .run (["git" , "-C" , self .cpython_repo , "checkout" , self .branch ])
44
- subprocess .run (["git" , "-C" , self .cpython_repo , "pull" , "--ff-only" ])
66
+ print ("✅" )
67
+
68
+ subprocess .run (
69
+ ["git" , "-C" , self .cpython_repo , "checkout" , self .branch , "-q" ], check = True
70
+ )
71
+ subprocess .run (
72
+ ["git" , "-C" , self .cpython_repo , "pull" , "--ff-only" , "-q" ], check = True
73
+ )
74
+
75
+ logger .info ("Building gettext files..." )
45
76
subprocess .run (
46
77
[
47
78
"sphinx-build" ,
@@ -52,12 +83,19 @@ def setup_cpython_repo(self) -> None:
52
83
"pot" ,
53
84
],
54
85
cwd = self .cpython_repo ,
86
+ check = True ,
55
87
)
88
+ print ("✅" )
56
89
57
90
def setup_translation_repo (self ) -> None :
58
- subprocess .run (["git" , "init" ], cwd = self .translation_repo )
59
- subprocess .run (["git" , "branch" , "-m" , self .branch ], cwd = self .translation_repo )
91
+ logger .info ("Initializing translation repo..." )
92
+ subprocess .run (["git" , "init" , "-q" ], cwd = self .translation_repo , check = True )
93
+ subprocess .run (
94
+ ["git" , "branch" , "-m" , self .branch ], cwd = self .translation_repo , check = True
95
+ )
96
+ print ("✅" )
60
97
98
+ logger .info ("Copying gettext files..." )
61
99
files = glob .glob (f"{ self .cpython_repo } /pot/**/*.pot" ) + glob .glob (
62
100
f"{ self .cpython_repo } /pot/*.pot"
63
101
)
@@ -76,18 +114,25 @@ def setup_translation_repo(self) -> None:
76
114
77
115
shutil .copyfile (file , dest_path )
78
116
files [files .index (file )] = dest_path
117
+ print ("✅" )
79
118
119
+ logger .info ("Cleaning up gettext files..." )
80
120
for file in files :
81
121
with open (file , "r" , encoding = "utf-8" ) as f :
82
122
contents = f .read ()
83
123
contents = re .sub ("^#: .*Doc/" , "#: " , contents , flags = re .M )
84
124
with open (file , "w" , encoding = "utf-8" ) as f :
85
125
f .write (contents )
126
+ print ("✅" )
86
127
87
128
def create_readme (self ) -> None :
129
+ logger .info ("Creating README.md..." )
88
130
try :
89
131
readme = self ._request (self .readme_url )
90
132
except (urllib .error .HTTPError , urllib .error .URLError ):
133
+ logger .warning (
134
+ "\n ⚠️ Failed to fetch README.md from GitHub, using local copy..."
135
+ )
91
136
readme = Path (f"{ os .path .dirname (__file__ )} /data/README.md" ).read_text (
92
137
encoding = "utf-8"
93
138
)
@@ -96,29 +141,41 @@ def create_readme(self) -> None:
96
141
97
142
with open (f"{ self .translation_repo } /README.md" , "w" , encoding = "utf-8" ) as f :
98
143
f .write (readme )
144
+ print ("✅" )
99
145
100
146
def create_gitignore (self ) -> None :
147
+ logger .info ("Creating .gitignore..." )
101
148
try :
102
149
gitignore = self ._request (self .gitignore_url )
103
150
except (urllib .error .HTTPError , urllib .error .URLError ):
151
+ logger .warning (
152
+ "\n ⚠️ Failed to fetch .gitignore from GitHub, using local copy..."
153
+ )
104
154
gitignore = Path (f"{ os .path .dirname (__file__ )} /data/.gitignore" ).read_text (
105
155
encoding = "utf-8"
106
156
)
107
157
108
158
with open (f"{ self .translation_repo } /.gitignore" , "w" , encoding = "utf-8" ) as f :
109
159
f .write (gitignore )
160
+ print ("✅" )
110
161
111
162
def create_makefile (self ) -> None :
163
+ logging .info ("Creating .makefile..." )
112
164
try :
113
165
makefile = self ._request (self .makefile_url )
114
166
except (urllib .error .HTTPError , urllib .error .URLError ):
167
+ logger .warning (
168
+ "\n ⚠️ Failed to fetch Makefile from GitHub, using local copy..."
169
+ )
115
170
makefile = Path (f"{ os .path .dirname (__file__ )} /data/Makefile" ).read_text (
116
171
encoding = "utf-8"
117
172
)
118
173
119
174
head = (
120
175
subprocess .run (
121
- ["git" , "-C" , self .cpython_repo , "rev-parse" , "HEAD" ], stdout = PIPE
176
+ ["git" , "-C" , self .cpython_repo , "rev-parse" , "HEAD" ],
177
+ stdout = PIPE ,
178
+ check = True ,
122
179
)
123
180
.stdout .strip ()
124
181
.decode ()
@@ -130,14 +187,22 @@ def create_makefile(self) -> None:
130
187
131
188
with open (f"{ self .translation_repo } /Makefile" , "w" , encoding = "utf-8" ) as f :
132
189
f .write (makefile )
190
+ print ("✅" )
133
191
134
192
def run (self ) -> None :
135
- self .create_dirs ()
136
- self .setup_cpython_repo ()
137
- self .setup_translation_repo ()
138
- self .create_readme ()
139
- self .create_gitignore ()
140
- self .create_makefile ()
193
+ try :
194
+ self .create_dirs ()
195
+ self .setup_cpython_repo ()
196
+ self .setup_translation_repo ()
197
+ self .create_readme ()
198
+ self .create_gitignore ()
199
+ self .create_makefile ()
200
+ logger .info (f"🎉 Done bootstrapping the { self .language } translation ✅\n " )
201
+ except Exception as e :
202
+ logger .critical (
203
+ f"❌ Bootstrapping of the { self .language } translation failed: { e } \n "
204
+ )
205
+ sys .exit (1 )
141
206
142
207
143
208
def main () -> None :
@@ -151,7 +216,7 @@ def main() -> None:
151
216
"-b" , "--branch" , type = str , default = "3.12" , help = "CPython branch (e.g. 3.12)"
152
217
)
153
218
args = parser .parse_args ()
154
- Bootstrapper (args .language .lower (), args .branch ).run ()
219
+ Bootstrapper (args .language .lower (). replace ( "_" , "-" ) , args .branch ).run ()
155
220
156
221
157
222
if __name__ == "__main__" :
0 commit comments