webdrop-bridge/build/scripts/build_macos.sh
claudi f0c96f15b8 feat: Implement default welcome page for missing web application
- Added a professional HTML welcome page displayed when no web application is configured.
- Enhanced `_load_webapp()` method to support improved path resolution for both development and bundled modes.
- Updated error handling to show the welcome page instead of a bare error message when the webapp file is not found.
- Modified unit tests to verify the welcome page is displayed in error scenarios.

build: Complete Windows and macOS build scripts

- Created `build_windows.py` for building Windows executable and optional MSI installer using PyInstaller.
- Developed `build_macos.sh` for creating macOS application bundle and DMG image.
- Added logging and error handling to build scripts for better user feedback.

docs: Add build and icon requirements documentation

- Created `PHASE_3_BUILD_SUMMARY.md` detailing the build process, results, and next steps.
- Added `resources/icons/README.md` outlining icon requirements and creation guidelines.

chore: Sync remotes script for repository maintenance

- Introduced `sync_remotes.ps1` PowerShell script to fetch updates from origin and upstream remotes.
2026-01-28 12:59:33 +01:00

295 lines
6.6 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Build macOS DMG package using PyInstaller
#
# This script builds the WebDrop Bridge application for macOS and creates
# a distributable DMG image.
#
# Requirements:
# - PyInstaller 6.0+
# - Python 3.10+
# - Xcode Command Line Tools (for code signing)
# - create-dmg (optional, for custom DMG: brew install create-dmg)
#
# Usage:
# bash build_macos.sh [--sign] [--notarize]
set -e # Exit on error
# Configuration
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
BUILD_DIR="$PROJECT_ROOT/build"
DIST_DIR="$BUILD_DIR/dist/macos"
TEMP_BUILD="$BUILD_DIR/temp/macos"
SPECS_DIR="$BUILD_DIR/specs"
SPEC_FILE="$BUILD_DIR/webdrop_bridge.spec"
APP_NAME="WebDropBridge"
DMG_VOLUME_NAME="WebDrop Bridge"
VERSION="1.0.0"
# Parse arguments
SIGN_APP=0
NOTARIZE_APP=0
while [[ $# -gt 0 ]]; do
case $1 in
--sign)
SIGN_APP=1
shift
;;
--notarize)
NOTARIZE_APP=1
shift
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${BLUE}${NC} $1"
}
log_success() {
echo -e "${GREEN}${NC} $1"
}
log_warning() {
echo -e "${YELLOW}⚠️${NC} $1"
}
log_error() {
echo -e "${RED}${NC} $1"
}
# Main build function
main() {
echo "=========================================="
echo "🚀 WebDrop Bridge macOS Build"
echo "=========================================="
echo ""
# Check prerequisites
check_prerequisites
# Clean previous builds
clean_builds
# Build with PyInstaller
build_executable
# Create DMG
create_dmg
# Optional: Sign and notarize
if [ $SIGN_APP -eq 1 ]; then
sign_app
fi
if [ $NOTARIZE_APP -eq 1 ]; then
notarize_app
fi
echo ""
echo "=========================================="
log_success "Build completed successfully"
echo "=========================================="
echo ""
log_info "Output: $DIST_DIR/"
ls -lh "$DIST_DIR"
}
check_prerequisites() {
log_info "Checking prerequisites..."
# Check Python
if ! command -v python3 &> /dev/null; then
log_error "Python 3 not found"
exit 1
fi
log_success "Python 3 found: $(python3 --version)"
# Check PyInstaller
if ! python3 -m pip show pyinstaller &> /dev/null; then
log_error "PyInstaller not installed. Run: pip install pyinstaller"
exit 1
fi
log_success "PyInstaller installed"
# Check spec file
if [ ! -f "$SPEC_FILE" ]; then
log_error "Spec file not found: $SPEC_FILE"
exit 1
fi
log_success "Spec file found"
echo ""
}
clean_builds() {
log_info "Cleaning previous builds..."
for dir in "$DIST_DIR" "$TEMP_BUILD" "$SPECS_DIR"; do
if [ -d "$dir" ]; then
rm -rf "$dir"
log_success "Removed $dir"
fi
done
mkdir -p "$DIST_DIR" "$TEMP_BUILD" "$SPECS_DIR"
echo ""
}
build_executable() {
log_info "Building macOS executable with PyInstaller..."
echo ""
python3 -m PyInstaller \
--distpath="$DIST_DIR" \
--buildpath="$TEMP_BUILD" \
--specpath="$SPECS_DIR" \
"$SPEC_FILE"
if [ ! -d "$DIST_DIR/$APP_NAME.app" ]; then
log_error "Application bundle not created"
exit 1
fi
log_success "Application bundle built successfully"
log_info "Output: $DIST_DIR/$APP_NAME.app"
echo ""
}
create_dmg() {
log_info "Creating DMG package..."
echo ""
DMG_FILE="$DIST_DIR/${APP_NAME}-${VERSION}.dmg"
# Remove existing DMG
if [ -f "$DMG_FILE" ]; then
rm -f "$DMG_FILE"
fi
# Check if create-dmg is available
if command -v create-dmg &> /dev/null; then
log_info "Using create-dmg for professional DMG..."
create-dmg \
--volname "$DMG_VOLUME_NAME" \
--icon-size 128 \
--window-size 512 400 \
--app-drop-link 380 200 \
"$DMG_FILE" \
"$DIST_DIR/$APP_NAME.app"
else
log_warning "create-dmg not found, using hdiutil (less stylish)"
log_info "For professional DMG: brew install create-dmg"
# Create temporary DMG directory structure
DMG_TEMP="$TEMP_BUILD/dmg_contents"
mkdir -p "$DMG_TEMP"
# Copy app bundle
cp -r "$DIST_DIR/$APP_NAME.app" "$DMG_TEMP/"
# Create symlink to Applications folder
ln -s /Applications "$DMG_TEMP/Applications"
# Create DMG
hdiutil create \
-volname "$DMG_VOLUME_NAME" \
-srcfolder "$DMG_TEMP" \
-ov \
-format UDZO \
"$DMG_FILE"
# Clean up
rm -rf "$DMG_TEMP"
fi
if [ ! -f "$DMG_FILE" ]; then
log_error "DMG file not created"
exit 1
fi
# Get file size
SIZE=$(du -h "$DMG_FILE" | cut -f1)
log_success "DMG created successfully"
log_info "Output: $DMG_FILE (Size: $SIZE)"
echo ""
}
sign_app() {
log_info "Signing application..."
echo ""
# Get signing identity from environment or use ad-hoc
SIGNING_ID="${APPLE_SIGNING_ID:--}"
codesign \
--deep \
--force \
--verify \
--verbose \
--options=runtime \
--sign "$SIGNING_ID" \
"$DIST_DIR/$APP_NAME.app"
if [ $? -ne 0 ]; then
log_error "Code signing failed"
exit 1
fi
log_success "Application signed successfully"
echo ""
}
notarize_app() {
log_info "Notarizing application..."
echo ""
# Requires:
# - APPLE_ID environment variable
# - APPLE_PASSWORD environment variable (app-specific password)
# - APPLE_TEAM_ID environment variable
if [ -z "$APPLE_ID" ] || [ -z "$APPLE_PASSWORD" ]; then
log_error "APPLE_ID and APPLE_PASSWORD environment variables required for notarization"
return 1
fi
DMG_FILE="$DIST_DIR/${APP_NAME}-${VERSION}.dmg"
# Upload for notarization
log_info "Uploading to Apple Notarization Service..."
xcrun notarytool submit "$DMG_FILE" \
--apple-id "$APPLE_ID" \
--password "$APPLE_PASSWORD" \
--team-id "${APPLE_TEAM_ID}" \
--wait
if [ $? -ne 0 ]; then
log_error "Notarization failed"
return 1
fi
# Staple the notarization
xcrun stapler staple "$DMG_FILE"
log_success "Application notarized successfully"
echo ""
}
# Run main function
main