-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbuild_windows.py
More file actions
239 lines (201 loc) · 8.01 KB
/
Copy pathbuild_windows.py
File metadata and controls
239 lines (201 loc) · 8.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#!/usr/bin/env python3
"""
Build script for creating Windows executable using PyInstaller
"""
import os
import sys
import subprocess
import shutil
from pathlib import Path
from version import __version__, __app_name__, __url__
def build_windows_exe():
"""Build Windows executable using PyInstaller."""
print(f"Building {__app_name__} v{__version__} for Windows...")
# Clean previous builds
dist_dir = Path("dist")
build_dir = Path("build")
if dist_dir.exists():
print("Cleaning previous dist folder...")
shutil.rmtree(dist_dir)
if build_dir.exists():
print("Cleaning previous build folder...")
shutil.rmtree(build_dir)
# Try spec file first, then fallback to command line
spec_file = Path("funscript_processor.spec")
use_spec_file = spec_file.exists()
if use_spec_file:
print("Using spec file for build...")
cmd = [
sys.executable, "-m", "PyInstaller",
"--clean", # Clean PyInstaller cache
"--distpath", "dist/windows",
str(spec_file)
]
else:
print("Using command line arguments for build...")
# PyInstaller command
cmd = [
sys.executable, "-m", "PyInstaller",
"--onefile", # Single executable file
"--windowed", # No console window (GUI app)
"--name", f"RestimFunscriptProcessor-v{__version__}",
"--paths", ".", # Add current directory to Python path
"--collect-all", "ui", # Collect entire ui package
"--collect-all", "processing", # Collect entire processing package
"--hidden-import", "tkinter",
"--hidden-import", "numpy",
"--hidden-import", "matplotlib",
"--hidden-import", "matplotlib.pyplot",
"--hidden-import", "matplotlib.backends.backend_tkagg",
"--hidden-import", "matplotlib.figure",
"--hidden-import", "matplotlib.patches",
"--hidden-import", "json",
"--hidden-import", "pathlib",
"--hidden-import", "processing.linear_mapping", # New motion axis module
"--hidden-import", "processing.motion_axis_generation", # New motion axis module
"--clean", # Clean PyInstaller cache
"--distpath", "dist/windows",
"main.py"
]
if not use_spec_file:
# Add config file if it exists
if Path("restim_config.json").exists():
cmd.insert(-1, "--add-data")
cmd.insert(-1, "restim_config.json;.")
# Add event definitions if it exists
if Path("config.event_definitions.yml").exists():
cmd.insert(-1, "--add-data")
cmd.insert(-1, "config.event_definitions.yml;.")
# Add icon if it exists
if Path("assets/icon.ico").exists():
cmd.insert(-1, "--icon")
cmd.insert(-1, "assets/icon.ico")
print("Running PyInstaller...")
print(" ".join(cmd))
try:
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
print("Build successful!")
# Show output files
windows_dist = Path("dist/windows")
if windows_dist.exists():
exe_files = list(windows_dist.glob("*.exe"))
if exe_files:
exe_file = exe_files[0]
file_size = exe_file.stat().st_size / (1024 * 1024) # MB
print(f"Created: {exe_file}")
print(f"Size: {file_size:.1f} MB")
return str(exe_file)
else:
print("Warning: No .exe files found in dist folder")
except subprocess.CalledProcessError as e:
print(f"Build failed: {e}")
print("STDOUT:", e.stdout)
print("STDERR:", e.stderr)
return None
except FileNotFoundError:
print("Error: PyInstaller not found. Install with: pip install pyinstaller")
return None
def create_release_package():
"""Create a release package with the executable and documentation."""
print("Creating release package...")
release_dir = Path(f"dist/RestimFunscriptProcessor-v{__version__}-Windows")
release_dir.mkdir(parents=True, exist_ok=True)
# Copy executable
windows_dist = Path("dist/windows")
exe_files = list(windows_dist.glob("*.exe"))
if exe_files:
exe_file = exe_files[0]
target_exe = release_dir / f"RestimFunscriptProcessor.exe"
shutil.copy2(exe_file, target_exe)
print(f"Copied executable to: {target_exe}")
# Copy documentation
docs_to_copy = [
"README.md",
"PYTHON_GUI_APPLICATION_SPECIFICATION.md",
"RESTIM_FUNSCRIPT_PROCESSING_REQUIREMENTS.md",
"ALGORITHM_REDESIGN.md",
"RELEASE_NOTES.md"
]
for doc in docs_to_copy:
if Path(doc).exists():
shutil.copy2(doc, release_dir / doc)
print(f"Copied: {doc}")
# Copy config files to be next to the exe
# config.json might contain user settings, but we include default if it exists
if Path("config.json").exists():
shutil.copy2("config.json", release_dir / "config.json")
print("Copied: config.json")
if Path("config.event_definitions.yml").exists():
shutil.copy2("config.event_definitions.yml", release_dir / "config.event_definitions.yml")
print("Copied: config.event_definitions.yml")
# Create a simple install guide
install_guide = release_dir / "INSTALLATION.txt"
with open(install_guide, 'w') as f:
f.write(f"""Restim Funscript Processor v{__version__} - Windows Installation
QUICK START:
1. Extract this folder to any location (e.g., Desktop or Program Files)
2. Double-click "RestimFunscriptProcessor-v{__version__}.exe" to run the application
3. No Python installation required!
VLC VIDEO PLAYER:
This application includes bundled VLC binaries for video playback.
If video does not play, ensure you have the latest drivers for your graphics card.
USAGE:
- Select your .funscript file using the Browse button (or drag and drop)
- Configure parameters in the tabs
- Click "Process Files" to generate output files
- Output files will be created in the same folder as your input file
DOCUMENTATION:
- README.md - Complete user guide and features
- RELEASE_NOTES.md - Version history and changes
- PYTHON_GUI_APPLICATION_SPECIFICATION.md - Technical details
SUPPORT:
- Report issues at: {__url__}/issues
- Documentation: See included README.md
VERSION: {__version__}
""")
print(f"Created installation guide: {install_guide}")
# Create ZIP archive
archive_name = f"RestimFunscriptProcessor-v{__version__}-Windows"
print(f"Creating ZIP archive: {archive_name}.zip")
shutil.make_archive(
f"dist/{archive_name}",
'zip',
release_dir.parent,
release_dir.name
)
archive_path = Path(f"dist/{archive_name}.zip")
if archive_path.exists():
archive_size = archive_path.stat().st_size / (1024 * 1024) # MB
print(f"Release package created: {archive_path}")
print(f"Archive size: {archive_size:.1f} MB")
return str(archive_path)
return None
def main():
"""Main build process."""
print("=" * 60)
print(f"Building {__app_name__} v{__version__} for Windows")
print("=" * 60)
# Check if we're on Windows (for warnings)
if sys.platform != "win32":
print("Warning: Building Windows executable on non-Windows platform")
print("Cross-compilation may have issues. Consider using GitHub Actions.")
# Build executable
exe_path = build_windows_exe()
if not exe_path:
print("Build failed!")
return False
# Create release package
archive_path = create_release_package()
if archive_path:
print("\n" + "=" * 60)
print("BUILD SUCCESSFUL!")
print(f"Release package: {archive_path}")
print("Ready for distribution!")
print("=" * 60)
return True
else:
print("Failed to create release package")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)