11import glob
2+ import logging
23import os
34import re
45import shutil
56import subprocess
7+ import sys
68import urllib .error
79import urllib .request
810from argparse import ArgumentParser
911from pathlib import Path
1012from subprocess import PIPE
1113
1214
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+
1331class Bootstrapper :
1432 def __init__ (self , language : str , branch : str = "3.12" ) -> None :
1533 self .language = language
@@ -25,23 +43,36 @@ def _request(self, url: str) -> str:
2543 return response .read ().decode ()
2644
2745 def create_dirs (self ) -> None :
46+ logger .info ("Creating directories..." )
2847 os .makedirs (self .translation_repo , exist_ok = True )
2948 os .makedirs (self .cpython_repo , exist_ok = True )
49+ print ("✅" )
3050
3151 def setup_cpython_repo (self ) -> None :
3252 if not os .path .exists (f"{ self .cpython_repo } /.git" ) and not os .path .isdir (
3353 f"{ self .cpython_repo } /.git"
3454 ):
55+ logger .info ("Cloning CPython repo..." )
3556 subprocess .run (
3657 [
3758 "git" ,
3859 "clone" ,
3960 "https://github.com/python/cpython.git" ,
4061 self .cpython_repo ,
41- ]
62+ "-q" ,
63+ ],
64+ check = True ,
4265 )
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..." )
4576 subprocess .run (
4677 [
4778 "sphinx-build" ,
@@ -52,12 +83,19 @@ def setup_cpython_repo(self) -> None:
5283 "pot" ,
5384 ],
5485 cwd = self .cpython_repo ,
86+ check = True ,
5587 )
88+ print ("✅" )
5689
5790 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 ("✅" )
6097
98+ logger .info ("Copying gettext files..." )
6199 files = glob .glob (f"{ self .cpython_repo } /pot/**/*.pot" ) + glob .glob (
62100 f"{ self .cpython_repo } /pot/*.pot"
63101 )
@@ -76,18 +114,25 @@ def setup_translation_repo(self) -> None:
76114
77115 shutil .copyfile (file , dest_path )
78116 files [files .index (file )] = dest_path
117+ print ("✅" )
79118
119+ logger .info ("Cleaning up gettext files..." )
80120 for file in files :
81121 with open (file , "r" , encoding = "utf-8" ) as f :
82122 contents = f .read ()
83123 contents = re .sub ("^#: .*Doc/" , "#: " , contents , flags = re .M )
84124 with open (file , "w" , encoding = "utf-8" ) as f :
85125 f .write (contents )
126+ print ("✅" )
86127
87128 def create_readme (self ) -> None :
129+ logger .info ("Creating README.md..." )
88130 try :
89131 readme = self ._request (self .readme_url )
90132 except (urllib .error .HTTPError , urllib .error .URLError ):
133+ logger .warning (
134+ "\n ⚠️ Failed to fetch README.md from GitHub, using local copy..."
135+ )
91136 readme = Path (f"{ os .path .dirname (__file__ )} /data/README.md" ).read_text (
92137 encoding = "utf-8"
93138 )
@@ -96,29 +141,41 @@ def create_readme(self) -> None:
96141
97142 with open (f"{ self .translation_repo } /README.md" , "w" , encoding = "utf-8" ) as f :
98143 f .write (readme )
144+ print ("✅" )
99145
100146 def create_gitignore (self ) -> None :
147+ logger .info ("Creating .gitignore..." )
101148 try :
102149 gitignore = self ._request (self .gitignore_url )
103150 except (urllib .error .HTTPError , urllib .error .URLError ):
151+ logger .warning (
152+ "\n ⚠️ Failed to fetch .gitignore from GitHub, using local copy..."
153+ )
104154 gitignore = Path (f"{ os .path .dirname (__file__ )} /data/.gitignore" ).read_text (
105155 encoding = "utf-8"
106156 )
107157
108158 with open (f"{ self .translation_repo } /.gitignore" , "w" , encoding = "utf-8" ) as f :
109159 f .write (gitignore )
160+ print ("✅" )
110161
111162 def create_makefile (self ) -> None :
163+ logging .info ("Creating .makefile..." )
112164 try :
113165 makefile = self ._request (self .makefile_url )
114166 except (urllib .error .HTTPError , urllib .error .URLError ):
167+ logger .warning (
168+ "\n ⚠️ Failed to fetch Makefile from GitHub, using local copy..."
169+ )
115170 makefile = Path (f"{ os .path .dirname (__file__ )} /data/Makefile" ).read_text (
116171 encoding = "utf-8"
117172 )
118173
119174 head = (
120175 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 ,
122179 )
123180 .stdout .strip ()
124181 .decode ()
@@ -130,14 +187,22 @@ def create_makefile(self) -> None:
130187
131188 with open (f"{ self .translation_repo } /Makefile" , "w" , encoding = "utf-8" ) as f :
132189 f .write (makefile )
190+ print ("✅" )
133191
134192 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 )
141206
142207
143208def main () -> None :
@@ -151,7 +216,7 @@ def main() -> None:
151216 "-b" , "--branch" , type = str , default = "3.12" , help = "CPython branch (e.g. 3.12)"
152217 )
153218 args = parser .parse_args ()
154- Bootstrapper (args .language .lower (), args .branch ).run ()
219+ Bootstrapper (args .language .lower (). replace ( "_" , "-" ) , args .branch ).run ()
155220
156221
157222if __name__ == "__main__" :
0 commit comments