feat: Implement configuration bundling for customer-specific builds and enhance build scripts
This commit is contained in:
parent
4e5deab7e9
commit
a355c13c82
5 changed files with 750 additions and 22 deletions
|
|
@ -11,7 +11,13 @@
|
|||
# - create-dmg (optional, for custom DMG: brew install create-dmg)
|
||||
#
|
||||
# Usage:
|
||||
# bash build_macos.sh [--sign] [--notarize]
|
||||
# bash build_macos.sh [--sign] [--notarize] [--env-file PATH]
|
||||
#
|
||||
# Options:
|
||||
# --sign Sign app (requires Apple developer certificate)
|
||||
# --notarize Notarize app (requires Apple ID)
|
||||
# --env-file PATH Use custom .env file (default: project root .env)
|
||||
# Build fails if .env doesn't exist
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
|
|
@ -27,6 +33,9 @@ APP_NAME="WebDropBridge"
|
|||
DMG_VOLUME_NAME="WebDrop Bridge"
|
||||
VERSION="1.0.0"
|
||||
|
||||
# Default .env file
|
||||
ENV_FILE="$PROJECT_ROOT/.env"
|
||||
|
||||
# Parse arguments
|
||||
SIGN_APP=0
|
||||
NOTARIZE_APP=0
|
||||
|
|
@ -41,6 +50,10 @@ while [[ $# -gt 0 ]]; do
|
|||
NOTARIZE_APP=1
|
||||
shift
|
||||
;;
|
||||
--env-file)
|
||||
ENV_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
|
|
@ -48,6 +61,15 @@ while [[ $# -gt 0 ]]; do
|
|||
esac
|
||||
done
|
||||
|
||||
# Validate env file
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "❌ Configuration file not found: $ENV_FILE"
|
||||
echo "Please provide a valid .env file or use --env-file parameter"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Using configuration: $ENV_FILE"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
|
|
@ -154,6 +176,9 @@ build_executable() {
|
|||
log_info "Building macOS executable with PyInstaller..."
|
||||
echo ""
|
||||
|
||||
# Export env file for spec file to pick up
|
||||
export WEBDROP_ENV_FILE="$ENV_FILE"
|
||||
|
||||
python3 -m PyInstaller \
|
||||
--distpath="$DIST_DIR" \
|
||||
--buildpath="$TEMP_BUILD" \
|
||||
|
|
|
|||
|
|
@ -9,13 +9,21 @@ Requirements:
|
|||
- For MSI: WiX Toolset (optional, requires separate installation)
|
||||
|
||||
Usage:
|
||||
python build_windows.py [--msi] [--code-sign]
|
||||
python build_windows.py [--msi] [--code-sign] [--env-file PATH]
|
||||
|
||||
Options:
|
||||
--msi Create MSI installer (requires WiX Toolset)
|
||||
--code-sign Sign executable (requires certificate)
|
||||
--env-file PATH Use custom .env file (default: project root .env)
|
||||
If not provided, uses .env from project root
|
||||
Build fails if .env doesn't exist
|
||||
"""
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
|
|
@ -33,14 +41,35 @@ if sys.platform == "win32":
|
|||
class WindowsBuilder:
|
||||
"""Build Windows installer using PyInstaller."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize builder paths."""
|
||||
def __init__(self, env_file: Path | None = None):
|
||||
"""Initialize builder paths.
|
||||
|
||||
Args:
|
||||
env_file: Path to .env file to bundle. If None, uses project root .env.
|
||||
If that doesn't exist, raises error.
|
||||
"""
|
||||
self.project_root = Path(__file__).parent.parent.parent
|
||||
self.build_dir = self.project_root / "build"
|
||||
self.dist_dir = self.build_dir / "dist" / "windows"
|
||||
self.temp_dir = self.build_dir / "temp" / "windows"
|
||||
self.spec_file = self.build_dir / "webdrop_bridge.spec"
|
||||
self.version = get_current_version()
|
||||
|
||||
# Validate and set env file
|
||||
if env_file is None:
|
||||
env_file = self.project_root / ".env"
|
||||
else:
|
||||
env_file = Path(env_file).resolve()
|
||||
|
||||
if not env_file.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Configuration file not found: {env_file}\n"
|
||||
f"Please provide a .env file using --env-file parameter\n"
|
||||
f"or ensure .env exists in project root"
|
||||
)
|
||||
|
||||
self.env_file = env_file
|
||||
print(f"📋 Using configuration: {self.env_file}")
|
||||
|
||||
def _get_version(self) -> str:
|
||||
"""Get version from __init__.py.
|
||||
|
|
@ -66,6 +95,7 @@ class WindowsBuilder:
|
|||
self.temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# PyInstaller command using spec file
|
||||
# Pass env_file path as environment variable for spec to pick up
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
|
|
@ -78,11 +108,17 @@ class WindowsBuilder:
|
|||
]
|
||||
|
||||
print(f" Command: {' '.join(cmd)}")
|
||||
|
||||
# Set environment variable for spec file to use
|
||||
env = os.environ.copy()
|
||||
env["WEBDROP_ENV_FILE"] = str(self.env_file)
|
||||
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=str(self.project_root),
|
||||
encoding="utf-8",
|
||||
errors="replace"
|
||||
errors="replace",
|
||||
env=env
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
|
|
@ -341,28 +377,40 @@ class WindowsBuilder:
|
|||
return True
|
||||
|
||||
|
||||
def sync_version() -> None:
|
||||
"""Sync version from __init__.py to all dependent files."""
|
||||
script_path = Path(__file__).parent.parent.parent / "scripts" / "sync_version.py"
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(script_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(f"❌ Version sync failed: {result.stderr}")
|
||||
sys.exit(1)
|
||||
print(result.stdout)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Build Windows MSI installer."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Build WebDrop Bridge Windows installer"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--msi",
|
||||
action="store_true",
|
||||
help="Create MSI installer (requires WiX Toolset)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--code-sign",
|
||||
action="store_true",
|
||||
help="Sign executable (requires certificate in CODE_SIGN_CERT env var)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--env-file",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Path to .env file to bundle (default: project root .env)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("🔄 Syncing version...")
|
||||
sync_version()
|
||||
|
||||
builder = WindowsBuilder()
|
||||
success = builder.build(create_msi=True, sign=False)
|
||||
try:
|
||||
builder = WindowsBuilder(env_file=args.env_file)
|
||||
except FileNotFoundError as e:
|
||||
print(f"❌ Build failed: {e}")
|
||||
return 1
|
||||
|
||||
success = builder.build(create_msi=args.msi, sign=args.code_sign)
|
||||
|
||||
return 0 if success else 1
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue