1212from pathlib import Path
1313from wppm import wppm ,utils
1414
15- # Define constant paths for clarity
1615PORTABLE_DIRECTORY = Path (__file__ ).parent / "portable"
1716assert PORTABLE_DIRECTORY .is_dir (),f"Portable directory not found:{ PORTABLE_DIRECTORY } "
1817
@@ -35,8 +34,7 @@ def copy_items(source_directories: list[Path], target_directory: Path, verbose:
3534
3635def parse_list_argument (argument_value :str | list [str ],separator = " " )-> list [str ]:
3736"""Parse a separated list argument into a list of strings."""
38- if not argument_value :
39- return []
37+ if not argument_value :return []
4038return argument_value .split (separator )if isinstance (argument_value ,str )else list (argument_value )
4139
4240class WinPythonDistributionBuilder :
@@ -72,7 +70,7 @@ def __init__(self, build_number: int, release_level: str, target_directory: Path
7270def _get_python_zip_file (self )-> Path :
7371"""Finds the Python .zip file in the wheels directory."""
7472for source_item in self .wheels_directory .iterdir ():
75- if re .match (r"(pypy3|python-)([0-9]|[a-zA-Z]|.)* .zip" ,source_item .name ):
73+ if re .match (r"(pypy3|python-).*\ .zip" ,source_item .name ):
7674return source_item
7775raise RuntimeError (f"Could not find Python zip package in{ self .wheels_directory } " )
7876
@@ -86,25 +84,9 @@ def python_full_version(self) -> str:
8684"""Retrieves the Python full version string from the distribution."""
8785return utils .get_python_long_version (self .distribution .target )if self .distribution else "0.0.0"
8886
89- @property
90- def python_executable_directory (self )-> str :
91- """Returns the directory containing the Python executable."""
92- if self .winpython_directory :
93- python_path_directory = self .winpython_directory / self .python_directory_name
94- return str (python_path_directory )if python_path_directory .is_dir ()else str (self .winpython_directory / self .python_name )
95- return ""
96-
97- @property
98- def architecture_bits (self )-> int :
99- """Returns the architecture (32 or 64 bits) of the distribution."""
100- return self .distribution .architecture if self .distribution else 64
101-
10287def _print_action (self ,text :str ):
10388"""Prints an action message with progress indicator."""
104- if self .verbose :
105- utils .print_box (text )
106- else :
107- print (f"{ text } ... " ,end = "" ,flush = True )
89+ utils .print_box (text )if self .verbose else print (f"{ text } ..." ,end = "" ,flush = True )
10890
10991def _extract_python_archive (self ):
11092"""Extracts the Python zip archive to create the base Python environment."""
@@ -124,33 +106,38 @@ def _copy_essential_files(self):
124106self ._print_action (f"Copying tools to{ tools_target_directory } " )
125107copy_items (self .tools_directories ,tools_target_directory ,self .verbose )
126108
127- def _create_initial_batch_scripts (self ):
128- """Creates initial batch scripts, including environment setup."""
129- self ._print_action ("Creating initial batch scripts" )
130- # Replacements for batch scripts (PyPy compatibility)
131- executable_name = self .distribution .short_exe if self .distribution else "python.exe" # default to python.exe if distribution is not yet set
132- init_variables = [('WINPYthon_exe' ,executable_name ), ('WINPYthon_subdirectory_name' ,self .python_directory_name ), ('WINPYVER' ,self .winpython_version_name )]
133- init_variables += [('WINPYVER2' ,f"{ self .python_full_version } .{ self .build_number } " ), ('WINPYFLAVOR' ,self .flavor ), ('WINPYARCH' ,self .architecture_bits )]
134- with open (self .winpython_directory / "scripts" / "env.ini" ,"w" )as f :
135- f .writelines ([f'{ a } ={ b } \n ' for a ,b in init_variables ])
109+ def _create_env_config (self ):
110+ """Creates environment setup"""
111+ self ._print_action ("Creating env.ini environment setup" )
112+ executable_name = self .distribution .short_exe if self .distribution else "python.exe"
113+ config = {
114+ "WINPYthon_exe" :executable_name ,
115+ "WINPYthon_subdirectory_name" :self .python_directory_name ,
116+ "WINPYVER" :self .winpython_version_name ,
117+ "WINPYVER2" :f"{ self .python_full_version } .{ self .build_number } " ,
118+ "WINPYFLAVOR" :self .flavor ,
119+ "WINPYARCH" :self .distribution .architecture if self .distribution else 64 ,
120+ }
121+ env_path = self .winpython_directory / "scripts" / "env.ini"
122+ env_path .parent .mkdir (parents = True ,exist_ok = True )
123+ print ("zzz env_path" ,env_path )
124+ self ._print_action (f"Creating env.ini environment{ env_path } " )
125+ env_path .write_text ("\n " .join (f"{ k } ={ v } " for k ,v in config .items ()))
136126
137127def build (self ,winpy_dir :Path = None ):
138128"""Make or finalise WinPython distribution in the target directory"""
139129print (f"Building WinPython with Python archive:{ self .python_zip_file .name } " )
140- self .winpython_directory = winpy_dir
141-
130+ self .winpython_directory = Path (winpy_dir )
142131self ._print_action (f"Creating WinPython{ self .winpython_directory } base directory" )
143132if self .winpython_directory .is_dir ()and len (self .winpython_directory .parts )>= 4 :
144133shutil .rmtree (self .winpython_directory )
145- os .makedirs (self .winpython_directory ,exist_ok = True )
146134# preventive re-Creation of settings directory
147135 (self .winpython_directory / "settings" / "AppData" / "Roaming" ).mkdir (parents = True ,exist_ok = True )
148- self ._extract_python_archive ()
149-
150- self .distribution = wppm .Distribution (self .python_executable_directory ,verbose = self .verbose )
151136
137+ self ._extract_python_archive ()
138+ self .distribution = wppm .Distribution (self .winpython_directory / self .python_directory_name ,verbose = self .verbose )
152139self ._copy_essential_files ()
153- self ._create_initial_batch_scripts ()
140+ self ._create_env_config ()
154141
155142def make_all (build_number :int ,release_level :str ,basedir_wpy :Path = None ,
156143verbose :bool = False ,
@@ -170,22 +157,19 @@ def make_all(build_number: int, release_level: str, basedir_wpy: Path = None,
170157 """
171158assert basedir_wpy is not None ,"The *winpython_dirname* directory must be specified"
172159
173- tools_dirs_list = parse_list_argument (toolsdirs ,"," )
160+ tools_directories = [ Path ( d ) for d in parse_list_argument (toolsdirs ,"," )]
174161winpy_dir = Path (basedir_wpy )
175-
176162utils .print_box (f"Making WinPython at{ winpy_dir } " )
177163os .makedirs (winpy_dir ,exist_ok = True )
164+
178165builder = WinPythonDistributionBuilder (
179166build_number ,release_level ,winpy_dir .parent ,wheels_directory = source_dirs ,
180- tools_directories = [Path (d )for d in tools_dirs_list ],
181- verbose = verbose ,
182- flavor = flavor
167+ tools_directories = tools_directories ,
168+ verbose = verbose ,flavor = flavor
183169 )
184- builder .build (winpy_dir = winpy_dir )
185-
170+ builder .build (winpy_dir )
186171
187172if __name__ == "__main__" :
188- # DO create only one Winpython distribution at a time
189173make_all (
190174build_number = 1 ,
191175release_level = "b3" ,