33import shutil
44import subprocess
55import sys
6+ import logging
7+
8+ # Setup basic logging for build script
9+ logging .basicConfig (
10+ level = logging .INFO ,
11+ format = '%(asctime)s - %(levelname)s - %(message)s' ,
12+ datefmt = '%H:%M:%S'
13+ )
14+ logger = logging .getLogger (__name__ )
15+
616from core .settings_manager import SettingsManager
717
818CONFIG_FILES = ['config.ini' , 'config.cfg' ]
@@ -18,13 +28,13 @@ def clean_directories():
1828 dirs_to_clean = [OUTPUT_DIR , BUILD_DIR ]
1929 for d in dirs_to_clean :
2030 if os .path .exists (d ):
21- print (f"Cleaning { d } ..." )
31+ logger . info (f"Cleaning { d } ..." )
2232 shutil .rmtree (d )
2333
2434def build (debug_mode ):
2535 """Invokes PyInstaller to build the executable."""
26- print (f"Building { EXECUTABLE_NAME } (Debug Mode: { debug_mode } )..." )
27-
36+ logger . info (f"Building { EXECUTABLE_NAME } (Debug Mode: { debug_mode } )..." )
37+
2838 cmd = [
2939 'pyinstaller' ,
3040 '--onedir' ,
@@ -41,7 +51,7 @@ def build(debug_mode):
4151 # Note: We don't explicitly add --add-data here because we copy config manually after build.
4252 # If hidden imports are needed (e.g. pynput, PySide6), PyInstaller usually finds them.
4353 # If issues arise, we can add --hidden-import.
44-
54+
4555 # Run PyInstaller
4656 subprocess .check_call (cmd )
4757
@@ -56,42 +66,42 @@ def copy_config_to_dist():
5666 if os .path .exists (cfg ):
5767 input_config = cfg
5868 shutil .copy2 (input_config , target_dir )
59- print (f"Copied { input_config } to { target_dir } " )
69+ logger . info (f"Copied { input_config } to { target_dir } " )
6070 copied = True
6171 break
62-
72+
6373 if not copied :
64- print ( "Warning: No config file found to copy." )
74+ logger . warning ( " No config file found to copy." )
6575
6676def create_zip (debug_mode ):
6777 """Packages the dist folder into a zip file."""
6878 source_dir = os .path .join (OUTPUT_DIR , EXECUTABLE_NAME )
69-
79+
7080 zip_name = EXECUTABLE_NAME
7181 if debug_mode :
7282 zip_name += "-debug"
73-
83+
7484 # shutil.make_archive expects the base_name without extension
7585 # It creates base_name.zip
76-
77- print (f"\n Packaging into { zip_name } .zip..." )
78-
86+
87+ logger . info (f"Packaging into { zip_name } .zip..." )
88+
7989 # format='zip': create a zip file
8090 # root_dir=OUTPUT_DIR: the root directory to archive
8191 # base_dir=EXECUTABLE_NAME: the directory inside root_dir to start archiving from
8292 # This prevents the zip from containing 'dist/...' structure, but rather just the executable folder
83-
93+
8494 # We want the zip to contain the top-level folder 'RainingKeysPython'
8595 # So we archive 'dist' but only the 'RainingKeysPython' subdirectory
86-
96+
8797 shutil .make_archive (zip_name , 'zip' , root_dir = OUTPUT_DIR , base_dir = EXECUTABLE_NAME )
88- print (f"Zip created: { zip_name } .zip" )
98+ logger . info (f"Zip created: { zip_name } .zip" )
8999
90100def update_config_debug_mode (debug_mode ):
91101 """Updates config.ini to match the current build mode."""
92102 # We read the config to preserve other settings, but force debug_mode
93103 config = configparser .ConfigParser ()
94-
104+
95105 # Manually read to handle potential BOM (Byte Order Mark) issues
96106 read_success = False
97107 for cfg in CONFIG_FILES :
@@ -102,8 +112,8 @@ def update_config_debug_mode(debug_mode):
102112 read_success = True
103113 break
104114 except Exception as e :
105- print (f"Warning: Could not read { cfg } : { e } " )
106-
115+ logger . warning (f"Could not read { cfg } : { e } " )
116+
107117 # Ensure sections exist
108118 if not config .has_section ('General' ):
109119 if config .has_section ('Debug' ):
@@ -113,41 +123,41 @@ def update_config_debug_mode(debug_mode):
113123 config .add_section ('General' )
114124 config .set ('General' , 'debug_mode' , str (debug_mode ))
115125 else :
116- config .set ('General' , 'debug_mode' , str (debug_mode ))
117-
126+ config .set ('General' , 'debug_mode' , str (debug_mode ))
127+
118128 # Write back
119129 # We pick the first available config file to write to, usually config.ini
120130 target_cfg = CONFIG_FILES [0 ]
121131 with open (target_cfg , 'w' , encoding = 'utf-8' ) as f :
122132 config .write (f )
123133
124134def run_build_cycle (debug_mode ):
125- print (f"\n >>> Starting { 'DEBUG' if debug_mode else 'RELEASE' } Build Cycle <<<" )
126-
135+ logger . info (f"\n >>> Starting { 'DEBUG' if debug_mode else 'RELEASE' } Build Cycle <<<" )
136+
127137 # Reset config to defaults if building for Release
128138 if not debug_mode :
129- print ("Resetting configuration to defaults for Release build..." )
139+ logger . info ("Resetting configuration to defaults for Release build..." )
130140 try :
131141 settings = SettingsManager ()
132142 settings .reset_to_defaults ()
133- print ("Configuration reset successful." )
143+ logger . info ("Configuration reset successful." )
134144 except Exception as e :
135- print (f"Warning: Failed to reset configuration: { e } " )
145+ logger . warning (f"Failed to reset configuration: { e } " )
136146
137147 # Update config file so the built executable reads the correct mode at runtime
138148 # AND so that the copy_config_to_dist puts the correct config in the dist folder
139149 update_config_debug_mode (debug_mode )
140-
150+
141151 # Build
142152 try :
143153 build (debug_mode )
144154 except subprocess .CalledProcessError as e :
145- print (f"Error during build: { e } " )
155+ logger . error (f"Error during build: { e } " )
146156 sys .exit (1 )
147-
157+
148158 # Copy Config
149159 copy_config_to_dist ()
150-
160+
151161 # Zip
152162 create_zip (debug_mode )
153163
@@ -157,25 +167,25 @@ def main():
157167
158168 # 2. Check dependencies
159169 try :
160- subprocess .call (['pyinstaller' , '--version' ], stdout = subprocess .DEVNULL )
170+ subprocess .call (['pyinstaller' , '--version' ], stdout = subprocess .DEVNULL , stderr = subprocess . DEVNULL )
161171 except FileNotFoundError :
162- print ( "Error: 'pyinstaller' not found. Please install it via 'pip install pyinstaller'." )
163- sys .exit (1 )
172+ logger . error ( " 'pyinstaller' not found. Please install it via 'pip install pyinstaller'." )
173+ sys .exit (1 )
164174
165175 # 3. Release Build (Normal)
166176 run_build_cycle (debug_mode = False )
167-
177+
168178 # 4. Debug Build
169179 # We clean build/ between runs to ensure clean state, but NOT dist/ (so we keep the zips)
170180 if os .path .exists (BUILD_DIR ):
171181 shutil .rmtree (BUILD_DIR )
172-
182+
173183 run_build_cycle (debug_mode = True )
174184
175- print ("\n All builds complete!" )
176- print (f"Artifacts located in project root:" )
177- print (f" - { EXECUTABLE_NAME } .zip" )
178- print (f" - { EXECUTABLE_NAME } -debug.zip" )
185+ logger . info ("\n All builds complete!" )
186+ logger . info (f"Artifacts located in project root:" )
187+ logger . info (f" - { EXECUTABLE_NAME } .zip" )
188+ logger . info (f" - { EXECUTABLE_NAME } -debug.zip" )
179189
180190if __name__ == "__main__" :
181191 main ()
0 commit comments