diff --git a/.gitignore b/.gitignore index 3d4cfb2..f71f17a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,6 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* +dist/ .cursor/ .vscode/ diff --git a/README.md b/README.md index ca1d3c0..b53ea28 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,16 @@ npm run tauri dev npm run tauri build ``` +## Release Build + +```bash +npm run release +``` + +This runs the full Tauri production build, ad-hoc code signs the `.app` bundle, and copies the output to `dist/release/`. + +The resulting `GUI Video Clipper.app` can be launched directly or dragged to `/Applications`. + ## Architecture GUI Video Clipper is built with [Tauri v2](https://v2.tauri.app/) (Rust backend) and [Svelte 5](https://svelte.dev/) (TypeScript frontend). diff --git a/package.json b/package.json index 6ee74e8..e02b6cd 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "preview": "vite preview", "test": "vitest run", "check": "svelte-check --tsconfig ./tsconfig.json", - "tauri": "tauri" + "tauri": "tauri", + "release": "bash scripts/build-release.sh" }, "license": "MIT", "dependencies": { diff --git a/scripts/build-release.sh b/scripts/build-release.sh new file mode 100755 index 0000000..656c088 --- /dev/null +++ b/scripts/build-release.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +VERSION_FILE="$PROJECT_ROOT/VERSION" + +# ── Read and validate version ────────────────────────────────────── +if [ ! -f "$VERSION_FILE" ]; then + echo "ERROR: VERSION file not found" >&2 + exit 1 +fi + +VERSION=$(cat "$VERSION_FILE" | sed 's/^[vV]//' | tr -d '[:space:]') + +if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "ERROR: '$VERSION' is not valid semver (expected X.Y.Z)" >&2 + exit 1 +fi + +echo "=== Building GUI Video Clipper v$VERSION ===" +echo "" + +# ── Install frontend dependencies ────────────────────────────────── +echo "→ Installing dependencies…" +cd "$PROJECT_ROOT" +npm install --silent + +# ── Run tauri build ──────────────────────────────────────────────── +echo "→ Building release (this may take a few minutes)…" +BUILD_LOG=$(mktemp) +npx tauri build 2>&1 | tee "$BUILD_LOG" | tail -10 + +# ── Locate built artifacts ───────────────────────────────────────── +# Parse .app path from tauri build output (handles custom CARGO_TARGET_DIR) +APP_SRC=$(grep '\.app$' "$BUILD_LOG" | head -1 | sed 's/^[[:space:]]*//') +DMG_SRC=$(grep '\.dmg$' "$BUILD_LOG" | head -1 | sed 's/^[[:space:]]*//') +rm -f "$BUILD_LOG" + +# Fall back to standard location if parsing failed +if [ -z "$APP_SRC" ] || [ ! -d "$APP_SRC" ]; then + BUNDLE_DIR="$PROJECT_ROOT/src-tauri/target/release/bundle" + APP_SRC="$BUNDLE_DIR/macos/GUI Video Clipper.app" +fi + +if [ ! -d "$APP_SRC" ]; then + echo "ERROR: .app bundle not found" >&2 + echo "Check the build output above for errors." >&2 + exit 1 +fi + +# ── Ad-hoc code sign ────────────────────────────────────────────── +echo "→ Ad-hoc signing .app…" +codesign --force --deep -s - "$APP_SRC" + +# ── Copy to dist/release/ ───────────────────────────────────────── +DIST_DIR="$PROJECT_ROOT/dist/release" +mkdir -p "$DIST_DIR" + +echo "→ Copying to dist/release/…" +rm -rf "$DIST_DIR/GUI Video Clipper.app" +cp -R "$APP_SRC" "$DIST_DIR/" + +# Copy DMG if it was built +DMG_FILE="$DMG_SRC" +if [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then + cp "$DMG_FILE" "$DIST_DIR/" + echo " ✓ DMG: $(basename "$DMG_FILE")" +fi + +# ── Summary ──────────────────────────────────────────────────────── +APP_SIZE=$(du -sh "$DIST_DIR/GUI Video Clipper.app" | cut -f1) +echo "" +echo "=== Build Complete ===" +echo " Version: v$VERSION" +echo " App: dist/release/GUI Video Clipper.app ($APP_SIZE)" +if [ -n "$DMG_FILE" ] && [ -f "$DIST_DIR/$(basename "$DMG_FILE")" ]; then + DMG_SIZE=$(du -sh "$DIST_DIR/$(basename "$DMG_FILE")" | cut -f1) + echo " DMG: dist/release/$(basename "$DMG_FILE") ($DMG_SIZE)" +fi +echo "" +echo "To run: open \"dist/release/GUI Video Clipper.app\"" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ed82421..0ec2f62 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -34,7 +34,7 @@ }, "bundle": { "active": true, - "targets": "all", + "targets": ["app", "dmg"], "icon": [ "icons/32x32.png", "icons/128x128.png",