Skip to content

Commit 186f3ee

Browse files
make app bundle instead of unix exe
1 parent 3708927 commit 186f3ee

2 files changed

Lines changed: 70 additions & 27 deletions

File tree

.github/workflows/build-and-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ jobs:
127127
128128
# Use PyInstaller with direct command line arguments for consistent builds
129129
echo "Building with PyInstaller"
130-
python -m PyInstaller --clean --onefile --console --name "Jumperless" --distpath dist/macos --workpath build/macos --icon "assets/icons/icon.icns" JumperlessWokwiBridge.py
130+
python -m PyInstaller --clean --windowed --name "Jumperless" --distpath dist/macos --workpath build/macos --icon "assets/icons/icon.icns" JumperlessWokwiBridge.py
131131
132132
- name: Build with PyInstaller (Windows)
133133
if: matrix.platform == 'windows'

Scripts/package_app.py

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -272,18 +272,30 @@ def package_platform(platform, arch, output_dir):
272272
platform_dir.mkdir(parents=True, exist_ok=True)
273273

274274
# Copy executable if it exists
275-
executable_name = "Jumperless"
276-
if platform == "windows":
277-
executable_name += ".exe"
278-
279-
executable_path = Path(f"dist/{platform}/{executable_name}")
280-
if executable_path.exists():
281-
shutil.copy2(executable_path, platform_dir)
282-
if platform != "windows":
283-
os.chmod(platform_dir / executable_name, 0o755)
284-
print(f"Copied executable: {executable_name}")
275+
if platform == "macos":
276+
# Handle .app bundle for macOS
277+
app_bundle_name = "Jumperless.app"
278+
app_bundle_path = Path(f"dist/{platform}/{app_bundle_name}")
279+
if app_bundle_path.exists():
280+
# Copy the entire .app bundle
281+
shutil.copytree(app_bundle_path, platform_dir / app_bundle_name, dirs_exist_ok=True)
282+
print(f"Copied .app bundle: {app_bundle_name}")
283+
else:
284+
print(f"Warning: .app bundle not found: {app_bundle_path}")
285285
else:
286-
print(f"Warning: Executable not found: {executable_path}")
286+
# Handle regular executable for Windows/Linux
287+
executable_name = "Jumperless"
288+
if platform == "windows":
289+
executable_name += ".exe"
290+
291+
executable_path = Path(f"dist/{platform}/{executable_name}")
292+
if executable_path.exists():
293+
shutil.copy2(executable_path, platform_dir)
294+
if platform != "windows":
295+
os.chmod(platform_dir / executable_name, 0o755)
296+
print(f"Copied executable: {executable_name}")
297+
else:
298+
print(f"Warning: Executable not found: {executable_path}")
287299

288300
# Create Python fallback
289301
create_python_fallback(platform, arch, platform_dir)
@@ -318,25 +330,55 @@ def create_macos_dmg(macos_dir, arch):
318330
temp_dir.mkdir()
319331

320332
try:
321-
# Copy contents to temp directory with simpler names
333+
# Copy contents to temp directory
334+
python_fallback_dir = None
322335
for item in macos_dir.iterdir():
323336
if item.is_dir():
324-
# Rename directories with spaces
325-
safe_name = item.name.replace(" ", "_")
326-
shutil.copytree(item, temp_dir / safe_name)
337+
if "Python" in item.name:
338+
# Keep track of Python fallback directory
339+
python_fallback_dir = item.name
340+
shutil.copytree(item, temp_dir / item.name)
341+
else:
342+
shutil.copytree(item, temp_dir / item.name)
327343
else:
328344
shutil.copy2(item, temp_dir)
329345

330-
# Basic DMG creation with simpler arguments
346+
# Copy DMG assets if they exist
347+
icon_path = Path("assets/icons/icon.icns")
348+
background_path = Path("JumperlessWokwiDMGwindow4x.png")
349+
350+
if icon_path.exists():
351+
shutil.copy2(icon_path, temp_dir / "icon.icns")
352+
if background_path.exists():
353+
shutil.copy2(background_path, temp_dir / "JumperlessWokwiDMGwindow4x.png")
354+
355+
# Build DMG creation command
331356
cmd = [
332-
"create-dmg",
333-
"--volname", "Jumperless",
357+
"create-dmg",
358+
"--volname", "Jumperless",
334359
"--window-size", "600", "400",
335-
"--icon-size", "100",
336-
dmg_name,
337-
str(temp_dir)
360+
"--icon-size", "100",
361+
"--app-drop-link", "450", "200",
338362
]
339-
363+
364+
# Add optional parameters if assets exist
365+
if (temp_dir / "icon.icns").exists():
366+
cmd.extend(["--volicon", str(temp_dir / "icon.icns")])
367+
if (temp_dir / "JumperlessWokwiDMGwindow4x.png").exists():
368+
cmd.extend(["--background", str(temp_dir / "JumperlessWokwiDMGwindow4x.png")])
369+
370+
# Add app icon positioning if .app bundle exists
371+
if (temp_dir / "Jumperless.app").exists():
372+
cmd.extend(["--icon", "Jumperless.app", "150", "200"])
373+
cmd.extend(["--hide-extension", "Jumperless.app"])
374+
375+
# Add Python fallback folder if it exists
376+
if python_fallback_dir and (temp_dir / python_fallback_dir).exists():
377+
cmd.extend(["--add-folder", python_fallback_dir, python_fallback_dir, "150", "320"])
378+
379+
# Add DMG name and source directory
380+
cmd.extend([dmg_name, str(temp_dir)])
381+
340382
subprocess.run(cmd, check=True)
341383
print(f"DMG created: {dmg_name}")
342384

@@ -375,11 +417,12 @@ def create_platform_readme(platform_dir, platform):
375417
'''
376418
elif platform == "macos":
377419
readme_content += '''
420+
Double-click `Jumperless.app` in Finder to run.
421+
422+
Or open from Terminal:
378423
```bash
379-
./Jumperless
424+
open Jumperless.app
380425
```
381-
382-
Or double-click the executable in Finder.
383426
'''
384427
elif platform == "windows":
385428
readme_content += '''
@@ -399,7 +442,7 @@ def create_platform_readme(platform_dir, platform):
399442
400443
## Package Contents
401444
402-
- `Jumperless''' + ('.exe' if platform == 'windows' else '') + '''` - Native executable
445+
- `Jumperless''' + ('.app' if platform == 'macos' else '.exe' if platform == 'windows' else '') + '''` - Native executable
403446
- `Jumperless Python/` - Python source code fallback
404447
- `README.md` - This file
405448

0 commit comments

Comments
 (0)