2
2
import os , sys , argparse , datetime , subprocess , shutil
3
3
from pathlib import Path
4
4
5
- # --- logging, helpers (same as Step 2) ---
5
+ # --- Logging ---
6
6
def log_section (logfile , message ):
7
7
ts = datetime .datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" )
8
8
section = f"\n { '-' * 40 } \n ({ ts } ) { message } \n { '-' * 40 } \n "
9
- print (section ); open (logfile , 'a' , encoding = 'utf-8' ).write (section )
10
-
11
- # --- Helpers ---
12
- def get_target_release (python_target ):
13
- mapping = {
14
- '311' : ('3119' , '2' ),
15
- '312' : ('31210' , '2' ),
16
- '313' : ('3135' , '1' ),
17
- '314' : ('3140' , '1' )
18
- }
19
- return mapping .get (python_target , (None , None ))
20
-
21
- def delete_folder_if_exists (folder : Path ,check_flavor : str = "" ):
9
+ print (section )
10
+ with open (logfile , 'a' , encoding = 'utf-8' ) as f :
11
+ f .write (section )
12
+
13
+
14
+ # --- Utility Functions ---
15
+
16
+ def delete_folder_if_exists (folder : Path , check_flavor : str = "" ):
22
17
check_last = folder .parent .name if not folder .is_dir () else folder .name
23
- if folder .exists () and folder .is_dir () and check_last == "bu" + check_flavor :
24
- print ("hello" , folder )
25
- folder_old = Path (str (folder )+ '.old' )
18
+ expected_name = "bu" + check_flavor
19
+
20
+ if folder .exists () and folder .is_dir () and check_last == expected_name :
21
+ print ("Removing old backup:" , folder )
22
+ folder_old = folder .with_suffix ('.old' )
26
23
if folder_old .exists ():
27
- shutil .rmtree (Path (str (folder )+ '.old' ))
28
- os .rename (folder , folder_old )
29
- shutil .rmtree (Path (str (folder )+ '.old' ))
30
- return
31
- for item in folder_old :
32
- if item .is_dir ():
33
- pass
34
- # delete_folder_if_exists(item)
35
- else :
36
- pass
37
- # item.unlink()
38
- # folder.rmdir()
39
-
40
- def activate_env (env_path ):
41
- # Windows-specific virtual env activation
42
- env_script = Path (env_path ) / "scripts" / "env.bat"
43
- if not env_script .exists ():
44
- raise FileNotFoundError (f"Cannot find env.bat at { env_script } " )
45
- # Note: This step is simplified here. Full environment activation logic will be added later.
24
+ shutil .rmtree (folder_old )
25
+ folder .rename (folder_old )
26
+ shutil .rmtree (folder_old )
46
27
47
28
48
- def run_make_py (build_python , winpydirbase , args , logfile ):
49
- cmd = [
50
- build_python , "-c" ,
51
- (
52
- "from wppm import make; "
53
- f"make.make_all({ args .release } , '{ args .release_level } ', basedir_wpy=r'{ winpydirbase } ', "
54
- f"verbose=True, flavor='{ args .flavor } ', source_dirs=r'{ args .source_dirs } ', "
55
- f"toolsdirs=r'{ args .tools_dirs } ')" #, portable_dir=r'{args.portable_dir}')"
56
- )
57
- ]
58
- print (cmd )
59
- from . import make
60
- make .make_all ( args .release , args .release_level , basedir_wpy = winpydirbase ,
61
- verbose = True , flavor = args .flavor , source_dirs = args .source_dirs ,
62
- toolsdirs = args .tools_dirs ) #, portable_dir= args.portable_dir )
63
- #subprocess.run(cmd, stdout=open(logfile, 'a'), stderr=subprocess.STDOUT, check=True)
29
+ def run_command (cmd , log_file = None , shell = False , check = True ):
30
+ print (f"[RUNNING] { ' ' .join (cmd ) if isinstance (cmd , list ) else cmd } " )
31
+ with subprocess .Popen (
32
+ cmd , shell = shell , stdout = subprocess .PIPE ,
33
+ stderr = subprocess .STDOUT , universal_newlines = True
34
+ ) as proc :
35
+ with open (log_file , 'a' , encoding = 'utf-8' ) if log_file else open (os .devnull , 'w' ) as logf :
36
+ for line in proc .stdout :
37
+ print (line , end = "" )
38
+ logf .write (line )
39
+ if check and proc .wait () != 0 :
40
+ raise subprocess .CalledProcessError (proc .returncode , cmd )
41
+
64
42
65
43
def pip_install (python_exe : Path , req_file : str , constraints : str , find_links : str , logfile : Path , label : str ):
66
44
if req_file and Path (req_file ).exists ():
@@ -69,43 +47,32 @@ def pip_install(python_exe: Path, req_file: str, constraints: str, find_links: s
69
47
"-r" , req_file , "-c" , constraints ,
70
48
"--pre" , "--no-index" , f"--find-links={ find_links } "
71
49
]
72
- log_section (logfile , f"Pip‑ install { label } " )
73
- subprocess . run (cmd , stdout = open ( logfile , 'a' ), stderr = subprocess . STDOUT , check = True )
50
+ log_section (logfile , f"Pip- install { label } " )
51
+ run_command (cmd , log_file = logfile )
74
52
else :
75
53
log_section (logfile , f"No { label } specified/skipped" )
76
54
77
- def run_command (cmd , env = None , log_file = None ):
78
- print (f"[RUN] { cmd } " )
79
- with subprocess .Popen (cmd , shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT , env = env , universal_newlines = True ) as proc :
80
- for line in proc .stdout :
81
- print (line , end = "" )
82
- if log_file :
83
- with open (log_file , "a" , encoding = "utf-8" ) as logf :
84
- logf .write (line )
85
-
86
- def patch_winpython (python_exe : Path , logfile : Path ):
87
- cmd = [str (python_exe ), "-c" ,
88
- (
89
- "from wppm import wppm;"
90
- "wppm.Distribution().patch_standard_packages('', to_movable=True)"
91
- )]
92
- print (cmd )
93
- subprocess .run (cmd , stdout = open (logfile , 'a' ), stderr = subprocess .STDOUT , check = True )
94
- #run_command(f'{activate_env(WINPYDIRBASE)} python -c "from wppm import wppm; wppm.Distribution(r\'{WINPYDIRBASE}\').patch_standard_packages(\'\', to_movable=True)"')
55
+
56
+ def patch_winpython (python_exe , logfile ):
57
+ cmd = [
58
+ str (python_exe ), "-c" ,
59
+ "from wppm import wppm; wppm.Distribution().patch_standard_packages('', to_movable=True)"
60
+ ]
61
+ run_command (cmd , log_file = logfile )
95
62
96
63
97
64
def check_env_bat (winpydirbase : Path ):
98
65
envbat = winpydirbase / "scripts" / "env.bat"
99
66
if not envbat .exists ():
100
67
raise FileNotFoundError (f"Missing env.bat at { envbat } " )
101
68
69
+
102
70
def generate_lockfiles (target_python : Path , winpydirbase : Path , constraints : str , find_links : str , logfile : Path , file_postfix : str ):
103
71
pip_req = winpydirbase .parent / "requirement_temp.txt"
104
72
with subprocess .Popen ([str (target_python ), "-m" , "pip" , "freeze" ], stdout = subprocess .PIPE ) as proc :
105
73
packages = [l for l in proc .stdout if b"winpython" not in l ]
106
74
pip_req .write_bytes (b"" .join (packages ))
107
75
# Lock to web and local (scaffolding)
108
- # if local --no-index --trusted-host=None --find-links="%my_find_links%"
109
76
for kind in ("" , "local" ):
110
77
out = winpydirbase .parent / f"pylock.{ file_postfix } _{ kind } .toml"
111
78
outreq = winpydirbase .parent / f"requir.{ file_postfix } _{ kind } .txt"
@@ -138,22 +105,24 @@ def generate_lockfiles(target_python: Path, winpydirbase: Path, constraints: str
138
105
else :
139
106
print ("match ok " ,winpydirbase .parent / f"requir.{ file_postfix } _{ web } .txt" , winpydirbase .parent / f"requir.{ file_postfix } _{ local } .txt" )
140
107
141
- # --- main ---
108
+ # --- Main Logic ---
109
+ def run_make_py (build_python , winpydirbase , args , logfile ):
110
+ from . import make
111
+ make .make_all (
112
+ args .release , args .release_level , basedir_wpy = winpydirbase ,
113
+ verbose = True , flavor = args .flavor ,
114
+ source_dirs = args .source_dirs , toolsdirs = args .tools_dirs
115
+ )
142
116
def main ():
143
117
parser = argparse .ArgumentParser ()
144
-
145
118
parser .add_argument ('--python-target' , required = True , help = 'Target Python version, e.g. 311' )
146
119
parser .add_argument ('--release' , default = '' , help = 'Release' )
147
120
parser .add_argument ('--flavor' , default = '' , help = 'Build flavor' )
148
121
parser .add_argument ('--arch' , default = '64' , help = 'Architecture' )
149
-
150
122
parser .add_argument ('--release-level' , default = 'b1' , help = 'Release level (e.g., b1, rc)' )
151
123
parser .add_argument ('--winpydirbase' , required = True , help = 'Path to put environment' )
152
124
parser .add_argument ('--source_dirs' , required = True , help = 'Path to directory with python zip' )
153
-
154
125
parser .add_argument ('--tools_dirs' , required = True , help = 'Path to directory with python zip' )
155
- #parser.add_argument('--portable_dir', required=True, help='Path to normal make.py')
156
-
157
126
parser .add_argument ('--buildenv' , required = True , help = 'Path to build environment' )
158
127
parser .add_argument ('--constraints' , default = 'constraints.txt' , help = 'Constraints file' )
159
128
parser .add_argument ('--requirements' , help = 'Main requirements.txt file' )
@@ -180,26 +149,20 @@ def main():
180
149
#logs termination
181
150
z = Path (winpydirbase ).name [(4 + len (args .arch )):- len (args .release_level )]
182
151
tada = f"{ z [:1 ]} _{ z [1 :3 ]} _{ z [3 ]} _{ args .release } "
183
- winpyver2 = tada .replace ('_' ,'.' )
184
- file_postfix = f"{ args .arch } -{ args .python_target [:1 ]} _{ args .python_target [1 :]} _{ args .release } { args .flavor } { args .release_level } "
185
- file_postfix = f"{ args .arch } -{ tada } { args .flavor } { args .release_level } "
152
+ winpyver2 = tada .replace ('_' , '.' )
153
+ file_postfix = f"{ args .arch } -{ tada } { args .flavor } { args .release_level } "
186
154
187
155
log_section (log_file , f"Preparing build for Python { args .python_target } ({ args .arch } -bit)" )
188
156
189
157
log_section (log_file , f"🙏 Step 0: displace old { Path (winpydirbase )} " )
190
- # O) Pre-clear
191
-
192
- #delete_folder_if_exists(Path(winpydirbase))
158
+
193
159
delete_folder_if_exists (winpydirbase .parent , check_flavor = args .flavor ) #bu{flavor]}
194
160
195
161
log_section (log_file , f"🙏 Step 1: make.py Python with { str (build_python )} at ({ winpydirbase } " )
196
- # 1) run make.py
197
162
run_make_py (str (build_python ), winpydirbase , args , log_file )
198
163
199
- # 2) env.bat exists
200
164
check_env_bat (winpydirbase )
201
165
202
- # 3) pip install in built environment
203
166
log_section (log_file , "🙏 Step 3: install requirements" )
204
167
205
168
for label , req in [
@@ -209,11 +172,9 @@ def main():
209
172
]:
210
173
pip_install (target_python , req , args .constraints , args .find_links , log_file , label )
211
174
212
- # 4) patch Winpython
213
175
log_section (log_file , "🙏 Step 4: Patch Winpython" )
214
176
patch_winpython (target_python , log_file )
215
177
216
- # 5) Install Wheelhouse
217
178
if args .wheelhousereq :
218
179
log_section (log_file , f"🙏 Step 5: install wheelhouse requirements { args .wheelhousereq } " )
219
180
wheelhousereq = Path (args .wheelhousereq )
@@ -255,15 +216,10 @@ def main():
255
216
subprocess .run (cmd , stdout = open (log_file , 'a' ), stderr = subprocess .STDOUT , check = False )
256
217
257
218
258
-
259
- # 6) lock files
260
219
log_section (log_file , "🙏 Step 6: install lockfiles" )
261
220
print (target_python , winpydirbase , args .constraints , args .find_links , log_file )
262
- print (' - - -' )
263
221
generate_lockfiles (target_python , winpydirbase , args .constraints , args .find_links , log_file , file_postfix )
264
222
265
- # 5b) Archive lock files
266
-
267
223
# 6) generate changelog
268
224
mdn = f"WinPython{ args .flavor } -{ args .arch } bit-{ winpyver2 } .md"
269
225
out = f"WinPython{ args .flavor } -{ args .arch } bit-{ winpyver2 } _History.md"
@@ -286,14 +242,13 @@ def main():
286
242
cmd = [str (target_python ), "-c" ,
287
243
(
288
244
"from wppm import diff;"
289
- f"result = diff.compare_package_indexes('{ winpyver2 } ', searchdir=r'{ log_dir } ', flavor=r'{ args .flavor } ', architecture={ args .arch } );"
245
+ f"result = diff.compare_package_indexes('{ winpyver2 } ', searchdir=r'{ changelog_dir } ', flavor=r'{ args .flavor } ', architecture={ args .arch } );"
290
246
f"open(r'{ winpydirbase .parent / out } ', 'w', encoding='utf-8').write(result)"
291
247
)]
292
248
subprocess .run (cmd , stdout = open (log_file , 'a' ), stderr = subprocess .STDOUT , check = True )
293
249
shutil .copyfile (winpydirbase .parent / out , changelog_dir / out )
294
250
log_section (log_file , "✅ Step 6 complete" )
295
251
296
- # 7) Create Installers
297
252
if args .create_installer != "" :
298
253
log_section (log_file , "🙏 Step 7 Create Installer" )
299
254
stem = f"WinPython{ args .arch } -{ winpyver2 } { args .flavor } { args .release_level } "
0 commit comments