Build Tool
This commit is contained in:
		
							
								
								
									
										272
									
								
								build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								build.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import subprocess
 | 
			
		||||
import platform
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
def clear_screen():
 | 
			
		||||
    os.system('cls' if os.name == 'nt' else 'clear')
 | 
			
		||||
 | 
			
		||||
def print_header():
 | 
			
		||||
    print("=" * 60)
 | 
			
		||||
    print("          PYINSTALLER AUTOMATION TOOL")
 | 
			
		||||
    print("=" * 60)
 | 
			
		||||
    print()
 | 
			
		||||
 | 
			
		||||
def get_script_path():
 | 
			
		||||
    while True:
 | 
			
		||||
        script_path = input("Enter the full path to the Python script: ").strip()
 | 
			
		||||
        
 | 
			
		||||
        script_path = script_path.strip('"\'')
 | 
			
		||||
        
 | 
			
		||||
        if not script_path:
 | 
			
		||||
            print("Path cannot be empty!")
 | 
			
		||||
            continue
 | 
			
		||||
            
 | 
			
		||||
        script_path = Path(script_path)
 | 
			
		||||
        
 | 
			
		||||
        if not script_path.exists():
 | 
			
		||||
            print("File not found!")
 | 
			
		||||
            continue
 | 
			
		||||
            
 | 
			
		||||
        if script_path.suffix.lower() != '.py':
 | 
			
		||||
            print("File must have .py extension!")
 | 
			
		||||
            continue
 | 
			
		||||
            
 | 
			
		||||
        return script_path
 | 
			
		||||
 | 
			
		||||
def select_mode():
 | 
			
		||||
    print("\nCOMPILATION MODE:")
 | 
			
		||||
    print("1. One-file (single file)")
 | 
			
		||||
    print("2. One-directory (folder with dependencies)")
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose mode (1-2): ").strip()
 | 
			
		||||
        if choice == '1':
 | 
			
		||||
            return True
 | 
			
		||||
        elif choice == '2':
 | 
			
		||||
            return False
 | 
			
		||||
        print("Invalid option! Choose 1 or 2.")
 | 
			
		||||
 | 
			
		||||
def select_console():
 | 
			
		||||
    print("\nEXECUTION MODE:")
 | 
			
		||||
    print("1. With console (default)")
 | 
			
		||||
    print("2. Without console (GUI/windowed)")
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose mode (1-2): ").strip()
 | 
			
		||||
        if choice == '1':
 | 
			
		||||
            return False
 | 
			
		||||
        elif choice == '2':
 | 
			
		||||
            return True
 | 
			
		||||
        print("Invalid option! Choose 1 or 2.")
 | 
			
		||||
 | 
			
		||||
def select_optimization():
 | 
			
		||||
    print("\nOPTIMIZATION:")
 | 
			
		||||
    print("1. No optimization (default)")
 | 
			
		||||
    print("2. Basic optimization (-O)")
 | 
			
		||||
    print("3. Maximum optimization (-OO)")
 | 
			
		||||
    
 | 
			
		||||
    optimizations = {'1': None, '2': '-O', '3': '-OO'}
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose optimization (1-3): ").strip()
 | 
			
		||||
        if choice in optimizations:
 | 
			
		||||
            return optimizations[choice]
 | 
			
		||||
        print("Invalid option! Choose 1-3.")
 | 
			
		||||
 | 
			
		||||
def select_icon():
 | 
			
		||||
    print("\nCUSTOM ICON:")
 | 
			
		||||
    print("1. No custom icon")
 | 
			
		||||
    print("2. Use custom icon")
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose option (1-2): ").strip()
 | 
			
		||||
        if choice == '1':
 | 
			
		||||
            return None
 | 
			
		||||
        elif choice == '2':
 | 
			
		||||
            icon_path = input("Enter path to .ico (Windows) or .png (Linux/Mac) file: ").strip()
 | 
			
		||||
            icon_path = icon_path.strip('"\'')
 | 
			
		||||
            if Path(icon_path).exists():
 | 
			
		||||
                return icon_path
 | 
			
		||||
            else:
 | 
			
		||||
                print("Icon file not found!")
 | 
			
		||||
                continue
 | 
			
		||||
        print("Invalid option! Choose 1 or 2.")
 | 
			
		||||
 | 
			
		||||
def select_additional_files():
 | 
			
		||||
    print("\nADDITIONAL FILES:")
 | 
			
		||||
    print("1. Do not add files")
 | 
			
		||||
    print("2. Add files/directories")
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose option (1-2): ").strip()
 | 
			
		||||
        if choice == '1':
 | 
			
		||||
            return []
 | 
			
		||||
        elif choice == '2':
 | 
			
		||||
            files = []
 | 
			
		||||
            while True:
 | 
			
		||||
                file_path = input("Enter file/directory path (or Enter to finish): ").strip()
 | 
			
		||||
                if not file_path:
 | 
			
		||||
                    break
 | 
			
		||||
                file_path = file_path.strip('"\'')
 | 
			
		||||
                if Path(file_path).exists():
 | 
			
		||||
                    files.append(file_path)
 | 
			
		||||
                    print(f"File added: {file_path}")
 | 
			
		||||
                else:
 | 
			
		||||
                    print("File not found!")
 | 
			
		||||
            return files
 | 
			
		||||
        print("Invalid option! Choose 1 or 2.")
 | 
			
		||||
 | 
			
		||||
def select_upx():
 | 
			
		||||
    print("\nUPX COMPRESSION:")
 | 
			
		||||
    print("1. Enable UPX compression (smaller files)")
 | 
			
		||||
    print("2. Disable UPX compression")
 | 
			
		||||
    
 | 
			
		||||
    while True:
 | 
			
		||||
        choice = input("\nChoose option (1-2): ").strip()
 | 
			
		||||
        if choice == '1':
 | 
			
		||||
            return False
 | 
			
		||||
        elif choice == '2':
 | 
			
		||||
            return True
 | 
			
		||||
        print("Invalid option! Choose 1 or 2.")
 | 
			
		||||
 | 
			
		||||
def build_command(script_path, onefile, windowed, optimization, icon, additional_files, noupx):
 | 
			
		||||
    cmd = ['pyinstaller']
 | 
			
		||||
    
 | 
			
		||||
    if onefile:
 | 
			
		||||
        cmd.append('--onefile')
 | 
			
		||||
    else:
 | 
			
		||||
        cmd.append('--onedir')
 | 
			
		||||
    
 | 
			
		||||
    if windowed:
 | 
			
		||||
        cmd.append('--windowed')
 | 
			
		||||
    
 | 
			
		||||
    if icon:
 | 
			
		||||
        cmd.extend(['--icon', icon])
 | 
			
		||||
    
 | 
			
		||||
    if optimization:
 | 
			
		||||
        cmd.extend(['--python-option', optimization])
 | 
			
		||||
    
 | 
			
		||||
    if noupx:
 | 
			
		||||
        cmd.append('--noupx')
 | 
			
		||||
    
 | 
			
		||||
    for file in additional_files:
 | 
			
		||||
        if os.path.isdir(file):
 | 
			
		||||
            cmd.extend(['--add-data', f'{file}{os.pathsep}{file}'])
 | 
			
		||||
        else:
 | 
			
		||||
            cmd.extend(['--add-data', f'{file}{os.pathsep}.'])
 | 
			
		||||
    
 | 
			
		||||
    exe_name = script_path.stem
 | 
			
		||||
    cmd.extend(['--name', exe_name])
 | 
			
		||||
    
 | 
			
		||||
    cmd.append(str(script_path))
 | 
			
		||||
    
 | 
			
		||||
    return cmd
 | 
			
		||||
 | 
			
		||||
def run_pyinstaller(command):
 | 
			
		||||
    print(f"\nExecuting: {' '.join(command)}")
 | 
			
		||||
    print("\nCompiling... This may take a few minutes...")
 | 
			
		||||
    print("-" * 60)
 | 
			
		||||
    
 | 
			
		||||
    try:
 | 
			
		||||
        result = subprocess.run(command, check=True, capture_output=True, text=True)
 | 
			
		||||
        print("Compilation completed successfully!")
 | 
			
		||||
        return True
 | 
			
		||||
    except subprocess.CalledProcessError as e:
 | 
			
		||||
        print(f"Error during compilation:")
 | 
			
		||||
        if e.stderr:
 | 
			
		||||
            print(f"Stderr: {e.stderr}")
 | 
			
		||||
        if e.stdout:
 | 
			
		||||
            print(f"Stdout: {e.stdout}")
 | 
			
		||||
        return False
 | 
			
		||||
    except FileNotFoundError:
 | 
			
		||||
        print("PyInstaller not found! Make sure it is installed.")
 | 
			
		||||
        print("Install with: pip install pyinstaller")
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
def show_summary(script_path, onefile, windowed, optimization, icon, additional_files, output_dir, noupx):
 | 
			
		||||
    clear_screen()
 | 
			
		||||
    print_header()
 | 
			
		||||
    print("COMPILATION SUMMARY:")
 | 
			
		||||
    print(f"Script: {script_path}")
 | 
			
		||||
    print(f"Mode: {'One-file' if onefile else 'One-directory'}")
 | 
			
		||||
    print(f"Console: {'No' if windowed else 'Yes'}")
 | 
			
		||||
    print(f"Optimization: {optimization or 'None'}")
 | 
			
		||||
    print(f"Icon: {icon or 'Default'}")
 | 
			
		||||
    print(f"UPX: {'Disabled' if noupx else 'Enabled'}")
 | 
			
		||||
    print(f"Additional files: {len(additional_files)}")
 | 
			
		||||
    print(f"Output directory: {output_dir}")
 | 
			
		||||
    print("-" * 60)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    clear_screen()
 | 
			
		||||
    print_header()
 | 
			
		||||
    
 | 
			
		||||
    try:
 | 
			
		||||
        subprocess.run(['pyinstaller', '--version'], capture_output=True, check=True)
 | 
			
		||||
    except (subprocess.CalledProcessError, FileNotFoundError):
 | 
			
		||||
        print("PyInstaller not found!")
 | 
			
		||||
        install = input("Do you want to install PyInstaller? (y/n): ").strip().lower()
 | 
			
		||||
        if install == 'y':
 | 
			
		||||
            subprocess.run([sys.executable, '-m', 'pip', 'install', 'pyinstaller'])
 | 
			
		||||
        else:
 | 
			
		||||
            print("Exiting...")
 | 
			
		||||
            return
 | 
			
		||||
    
 | 
			
		||||
    script_path = get_script_path()
 | 
			
		||||
    onefile = select_mode()
 | 
			
		||||
    windowed = select_console()
 | 
			
		||||
    optimization = select_optimization()
 | 
			
		||||
    icon = select_icon()
 | 
			
		||||
    additional_files = select_additional_files()
 | 
			
		||||
    noupx = select_upx()
 | 
			
		||||
    
 | 
			
		||||
    output_dir = Path("dist")
 | 
			
		||||
    
 | 
			
		||||
    show_summary(script_path, onefile, windowed, optimization, icon, additional_files, output_dir, noupx)
 | 
			
		||||
    
 | 
			
		||||
    confirm = input("\nProceed with compilation? (y/n): ").strip().lower()
 | 
			
		||||
    if confirm != 'y':
 | 
			
		||||
        print("Compilation canceled!")
 | 
			
		||||
        return
 | 
			
		||||
    
 | 
			
		||||
    command = build_command(script_path, onefile, windowed, optimization, icon, additional_files, noupx)
 | 
			
		||||
    
 | 
			
		||||
    success = run_pyinstaller(command)
 | 
			
		||||
    
 | 
			
		||||
    if success:
 | 
			
		||||
        print(f"\nCompilation completed!")
 | 
			
		||||
        print(f"Executable generated in: {output_dir}")
 | 
			
		||||
        
 | 
			
		||||
        if onefile:
 | 
			
		||||
            exe_name = script_path.stem
 | 
			
		||||
            if os.name == 'nt':
 | 
			
		||||
                exe_name += '.exe'
 | 
			
		||||
            exe_path = output_dir / exe_name
 | 
			
		||||
        else:
 | 
			
		||||
            exe_dir = output_dir / script_path.stem
 | 
			
		||||
            exe_name = script_path.stem
 | 
			
		||||
            if os.name == 'nt':
 | 
			
		||||
                exe_name += '.exe'
 | 
			
		||||
            exe_path = exe_dir / exe_name
 | 
			
		||||
        
 | 
			
		||||
        print(f"File: {exe_path}")
 | 
			
		||||
        
 | 
			
		||||
        if exe_path.exists():
 | 
			
		||||
            print("✅ Executable successfully created!")
 | 
			
		||||
        else:
 | 
			
		||||
            print("⚠️  Executable might not have been created correctly.")
 | 
			
		||||
            
 | 
			
		||||
    else:
 | 
			
		||||
        print("\nCompilation failed! Check the errors above.")
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    try:
 | 
			
		||||
        main()
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
        print("\nProgram interrupted by user!")
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"Unexpected error: {e}")
 | 
			
		||||
		Reference in New Issue
	
	Block a user