-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.py
More file actions
217 lines (181 loc) · 6.54 KB
/
build.py
File metadata and controls
217 lines (181 loc) · 6.54 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
#!/usr/bin/env python3
"""
Build script for GoodPlayer
Creates standalone executables for Windows and macOS
"""
import os
import sys
import shutil
import subprocess
import platform
def clean_build():
"""Remove previous build artifacts."""
dirs_to_remove = ['build', 'dist', '__pycache__']
for d in dirs_to_remove:
if os.path.exists(d):
print(f"Removing {d}/")
shutil.rmtree(d)
# Remove .pyc files
for root, dirs, files in os.walk('.'):
for f in files:
if f.endswith('.pyc'):
os.remove(os.path.join(root, f))
def check_dependencies():
"""Check if required build tools are installed."""
try:
import PyInstaller
print(f"PyInstaller version: {PyInstaller.__version__}")
except ImportError:
print("ERROR: PyInstaller not found. Install with: pip install pyinstaller")
sys.exit(1)
try:
import av
print(f"PyAV version: {av.__version__}")
except ImportError:
print("ERROR: PyAV not found. Install with: pip install av")
sys.exit(1)
def build_executable():
"""Build the executable using PyInstaller."""
print(f"\nBuilding for {platform.system()}...")
# Use spec file if it exists, otherwise use command line
if os.path.exists('GoodPlayer.spec'):
cmd = ['pyinstaller', '--clean', 'GoodPlayer.spec']
else:
cmd = [
'pyinstaller',
'--clean',
'--name=GoodPlayer',
'--windowed',
'--onedir',
'--add-data', 'README.md:.',
'run.py'
]
print(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd)
if result.returncode != 0:
print("ERROR: Build failed!")
sys.exit(1)
print("\nBuild complete!")
print(f"Output: dist/GoodPlayer/")
if platform.system() == 'Darwin':
print("macOS app bundle: dist/GoodPlayer.app/")
def create_dmg():
"""Create DMG installer for macOS."""
if platform.system() != 'Darwin':
print("DMG creation is only supported on macOS")
return
if not os.path.exists('dist/GoodPlayer.app'):
print("ERROR: GoodPlayer.app not found. Run build first.")
return
print("\nCreating DMG installer...")
dmg_name = 'GoodPlayer-1.0.0.dmg'
dmg_path = f'dist/{dmg_name}'
# Remove old DMG if exists
if os.path.exists(dmg_path):
os.remove(dmg_path)
# Check if create-dmg is available (brew install create-dmg)
if shutil.which('create-dmg'):
cmd = [
'create-dmg',
'--volname', 'GoodPlayer',
'--window-pos', '200', '120',
'--window-size', '600', '400',
'--icon-size', '100',
'--icon', 'GoodPlayer.app', '150', '185',
'--app-drop-link', '450', '185',
'--hide-extension', 'GoodPlayer.app',
dmg_path,
'dist/GoodPlayer.app'
]
result = subprocess.run(cmd)
if result.returncode == 0:
print(f"DMG created: {dmg_path}")
else:
print("create-dmg failed, falling back to manual method")
_create_dmg_manual(dmg_path)
else:
_create_dmg_manual(dmg_path)
def _create_dmg_manual(dmg_path: str):
"""Create DMG manually using hdiutil with Applications symlink."""
staging_dir = 'dist/dmg_staging'
# Clean up staging directory
if os.path.exists(staging_dir):
shutil.rmtree(staging_dir)
os.makedirs(staging_dir)
# Copy the app to staging
print("Copying GoodPlayer.app to staging...")
shutil.copytree('dist/GoodPlayer.app', f'{staging_dir}/GoodPlayer.app', symlinks=True)
# Create Applications symlink
print("Creating Applications symlink...")
os.symlink('/Applications', f'{staging_dir}/Applications')
# Create the DMG
print("Creating DMG image...")
cmd = [
'hdiutil', 'create',
'-volname', 'GoodPlayer',
'-srcfolder', staging_dir,
'-ov',
'-format', 'UDZO', # Compressed
dmg_path
]
result = subprocess.run(cmd)
# Clean up staging
shutil.rmtree(staging_dir)
if result.returncode == 0:
print(f"DMG created: {dmg_path}")
print("\nThe DMG contains:")
print(" - GoodPlayer.app")
print(" - Applications folder shortcut")
print("\nUsers can drag GoodPlayer.app to Applications to install.")
else:
print("ERROR: Failed to create DMG")
def create_windows_installer():
"""Create Windows installer using NSIS (if available)."""
if platform.system() != 'Windows':
print("Windows installer creation is only supported on Windows")
return
if not os.path.exists('dist/GoodPlayer'):
print("ERROR: dist/GoodPlayer not found. Run build first.")
return
# Check if NSIS is available
nsis_path = shutil.which('makensis')
if not nsis_path:
# Try common installation paths
common_paths = [
r'C:\Program Files (x86)\NSIS\makensis.exe',
r'C:\Program Files\NSIS\makensis.exe',
]
for p in common_paths:
if os.path.exists(p):
nsis_path = p
break
if nsis_path and os.path.exists('installer.nsi'):
print("\nCreating Windows installer with NSIS...")
subprocess.run([nsis_path, 'installer.nsi'])
else:
print("\nNSIS not found or installer.nsi missing.")
print("You can distribute the dist/GoodPlayer folder as a portable app,")
print("or install NSIS to create an installer.")
print("Download NSIS: https://nsis.sourceforge.io/")
def main():
"""Main entry point."""
import argparse
parser = argparse.ArgumentParser(description='Build GoodPlayer executable')
parser.add_argument('--clean', action='store_true', help='Clean build artifacts')
parser.add_argument('--installer', action='store_true', help='Create installer (DMG/NSIS)')
parser.add_argument('--skip-build', action='store_true', help='Skip build, only create installer')
args = parser.parse_args()
if args.clean:
clean_build()
if not args.installer and not args.skip_build:
return
check_dependencies()
if not args.skip_build:
build_executable()
if args.installer:
if platform.system() == 'Darwin':
create_dmg()
elif platform.system() == 'Windows':
create_windows_installer()
if __name__ == '__main__':
main()