Files
music-assistant/music-assistant-build-files.md
2026-09-13 20:21:10 +02:00

11 KiB

Build Files Template for music-assistant

Use this document as the prompt/instruction file for an agent when you create the music-assistant Swift macOS app project.

The target project does not need to match the Servery path. These files should be created in the root of the future music-assistant project, next to Package.swift.

Agent Request

Copy this request into the agent working inside the new project:

Create the same build-command structure for this Swift macOS app.

App name:
music-assistant

Product name:
music-assistant

Bundle identifier:
com.music-assistant.app

Requirements:
1. Create `Makefile` with `build`, `dev`, and `test` commands.
2. Create `clean_rebuild.sh` for a clean release build, packaging, signing,
   installing into `/Applications`, and launching the app.
3. Create `dev_rebuild.sh` for a fast incremental debug build, packaging,
   installing into `/Applications`, and launching the app.
4. Assume these files live in the project root next to `Package.swift`.
5. Use the app icon at `Resources/music-assistant.icns`.
6. If the app has additional resources, copy them into
   `Contents/Resources` during packaging.
7. Make both shell scripts executable.
8. Keep the implementation small and local. Do not refactor unrelated project
   files.
9. After creating the files, verify that the scripts reference the correct app
   name, product name, bundle identifier, icon path, and install path.

Makefile

Create this file as Makefile:

.PHONY: build dev test

build:
	./clean_rebuild.sh

dev:
	./dev_rebuild.sh

test:
	swift test

dev_rebuild.sh

Create this file as dev_rebuild.sh:

#!/bin/zsh
# Fast development rebuild: incremental DEBUG build, repackage, relaunch.
#
# This skips `swift package clean` and release-mode optimizations, so it reuses
# the incremental build cache and finishes quickly. Use it while iterating.

set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
APP_NAME="music-assistant"
PRODUCT_NAME="music-assistant"
APP_BUNDLE_NAME="${APP_NAME}.app"
BUILD_DIR="${PROJECT_ROOT}/.build"
APP_BUNDLE="${BUILD_DIR}/${APP_BUNDLE_NAME}"
INSTALL_PATH="/Applications/${APP_BUNDLE_NAME}"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
RESOURCES_DIR="${CONTENTS_DIR}/Resources"
APP_ICON="${PROJECT_ROOT}/Resources/music-assistant.icns"

fail() {
  print -u2 -- "Error: $1"
  exit 1
}

step() {
  print -- "==> $1"
}

[[ -f "${PROJECT_ROOT}/Package.swift" ]] || fail "Package.swift was not found in ${PROJECT_ROOT}."
[[ -f "${APP_ICON}" ]] || fail "App icon was not found at ${APP_ICON}."
command -v swift >/dev/null 2>&1 || fail "Swift is required. Install Xcode or the Xcode Command Line Tools."
command -v codesign >/dev/null 2>&1 || fail "codesign is required and should be available with Xcode."

cd "${PROJECT_ROOT}"

step "Stopping any running ${APP_NAME} application"
if pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1; then
  pkill -x "${PRODUCT_NAME}" || fail "Could not stop the running ${APP_NAME} application."
  for _ in {1..20}; do
    pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1 || break
    sleep 0.1
  done
  pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1 && fail "${APP_NAME} is still running. Quit it and retry."
fi

step "Building ${PRODUCT_NAME} in debug mode (incremental)"
swift build || fail "Debug build failed. Review the Swift compiler diagnostics above."
BIN_PATH="$(swift build --show-bin-path 2>/dev/null | tail -n1)"
SOURCE_EXECUTABLE="${BIN_PATH}/${PRODUCT_NAME}"
[[ -x "${SOURCE_EXECUTABLE}" ]] || fail "Built executable was not found at ${SOURCE_EXECUTABLE}."

step "Packaging ${APP_BUNDLE_NAME}"
rm -rf "${APP_BUNDLE}"
mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}"
cp "${SOURCE_EXECUTABLE}" "${MACOS_DIR}/${PRODUCT_NAME}"
cp "${APP_ICON}" "${RESOURCES_DIR}/music-assistant.icns"

cat > "${CONTENTS_DIR}/Info.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleDisplayName</key>
    <string>music-assistant</string>
    <key>CFBundleExecutable</key>
    <string>music-assistant</string>
    <key>CFBundleIdentifier</key>
    <string>com.music-assistant.app</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleIconFile</key>
    <string>music-assistant</string>
    <key>CFBundleName</key>
    <string>music-assistant</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>LSMinimumSystemVersion</key>
    <string>14.0</string>
    <key>NSHighResolutionCapable</key>
    <true/>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>
</dict>
</plist>
PLIST

plutil -lint "${CONTENTS_DIR}/Info.plist" >/dev/null || fail "Generated Info.plist is invalid."
codesign --force --sign - --timestamp=none "${APP_BUNDLE}" || fail "Ad-hoc signing of ${APP_BUNDLE_NAME} failed."
[[ -x "${MACOS_DIR}/${PRODUCT_NAME}" ]] || fail "Packaged executable is missing."

step "Installing ${APP_BUNDLE_NAME} in /Applications"
rm -rf "${INSTALL_PATH}"
ditto "${APP_BUNDLE}" "${INSTALL_PATH}" || fail "Could not install ${APP_BUNDLE_NAME} in /Applications. Check permissions and retry."

step "Launching ${APP_NAME}"
open -n "${INSTALL_PATH}" || fail "${APP_NAME} was installed but could not be opened."

print -- "==> ${APP_NAME} was rebuilt (debug), installed, and launched successfully."

clean_rebuild.sh

Create this file as clean_rebuild.sh:

#!/bin/zsh
# Build, package, install, and launch the music-assistant macOS application.

set -euo pipefail

PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
APP_NAME="music-assistant"
PRODUCT_NAME="music-assistant"
APP_BUNDLE_NAME="${APP_NAME}.app"
BUILD_DIR="${PROJECT_ROOT}/.build"
APP_BUNDLE="${BUILD_DIR}/${APP_BUNDLE_NAME}"
INSTALL_PATH="/Applications/${APP_BUNDLE_NAME}"
CONTENTS_DIR="${APP_BUNDLE}/Contents"
MACOS_DIR="${CONTENTS_DIR}/MacOS"
RESOURCES_DIR="${CONTENTS_DIR}/Resources"
APP_ICON="${PROJECT_ROOT}/Resources/music-assistant.icns"

fail() {
  print -u2 -- "Error: $1"
  exit 1
}

step() {
  print -- "==> $1"
}

[[ -f "${PROJECT_ROOT}/Package.swift" ]] || fail "Package.swift was not found in ${PROJECT_ROOT}."
[[ -f "${APP_ICON}" ]] || fail "App icon was not found at ${APP_ICON}."
command -v swift >/dev/null 2>&1 || fail "Swift is required. Install Xcode or the Xcode Command Line Tools."
command -v codesign >/dev/null 2>&1 || fail "codesign is required and should be available with Xcode."

cd "${PROJECT_ROOT}"

step "Stopping any running ${APP_NAME} application"
if pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1; then
  pkill -x "${PRODUCT_NAME}" || fail "Could not stop the running ${APP_NAME} application."
  for _ in {1..20}; do
    pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1 || break
    sleep 0.1
  done
  pgrep -x "${PRODUCT_NAME}" >/dev/null 2>&1 && fail "${APP_NAME} is still running. Quit it and retry."
fi

step "Removing stale installed copy"
if [[ -e "${INSTALL_PATH}" ]]; then
  rm -rf "${INSTALL_PATH}" || fail "Could not remove ${INSTALL_PATH}. Check permissions and retry."
fi

step "Cleaning local Swift build artifacts"
swift package clean || fail "Swift Package Manager could not clean the local build artifacts."

step "Building ${PRODUCT_NAME} in release mode"
BIN_PATH="$(swift build -c release --show-bin-path 2>/dev/null | tail -n1)"
SOURCE_EXECUTABLE="${BIN_PATH}/${PRODUCT_NAME}"

built=0
for attempt in 1 2 3; do
  swift build -c release || fail "Release build failed. Review the Swift compiler diagnostics above."
  if [[ -x "${SOURCE_EXECUTABLE}" ]]; then built=1; break; fi
  print -- "==> Executable not present after build (attempt ${attempt}); retrying"
  sleep 1
done
[[ "${built}" -eq 1 ]] || fail "Built executable was not found at ${SOURCE_EXECUTABLE}."

step "Packaging ${APP_BUNDLE_NAME}"
rm -rf "${APP_BUNDLE}"
mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}"
cp "${SOURCE_EXECUTABLE}" "${MACOS_DIR}/${PRODUCT_NAME}"
cp "${APP_ICON}" "${RESOURCES_DIR}/music-assistant.icns"

cat > "${CONTENTS_DIR}/Info.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleDisplayName</key>
    <string>music-assistant</string>
    <key>CFBundleExecutable</key>
    <string>music-assistant</string>
    <key>CFBundleIdentifier</key>
    <string>com.music-assistant.app</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleIconFile</key>
    <string>music-assistant</string>
    <key>CFBundleName</key>
    <string>music-assistant</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>LSMinimumSystemVersion</key>
    <string>14.0</string>
    <key>NSHighResolutionCapable</key>
    <true/>
    <key>NSPrincipalClass</key>
    <string>NSApplication</string>
</dict>
</plist>
PLIST

plutil -lint "${CONTENTS_DIR}/Info.plist" >/dev/null || fail "Generated Info.plist is invalid."
codesign --force --sign - --timestamp=none "${APP_BUNDLE}" || fail "Ad-hoc signing of ${APP_BUNDLE_NAME} failed."
codesign --verify --deep --strict "${APP_BUNDLE}" || fail "Packaged ${APP_BUNDLE_NAME} failed code-signature verification."
[[ -x "${MACOS_DIR}/${PRODUCT_NAME}" ]] || fail "Packaged executable is missing."

step "Installing ${APP_BUNDLE_NAME} in /Applications"
ditto "${APP_BUNDLE}" "${INSTALL_PATH}" || fail "Could not install ${APP_BUNDLE_NAME} in /Applications. Check permissions and retry."

INSTALLED_EXECUTABLE="${INSTALL_PATH}/Contents/MacOS/${PRODUCT_NAME}"
[[ -x "${INSTALLED_EXECUTABLE}" ]] || fail "Installed executable is missing at ${INSTALLED_EXECUTABLE}."
SOURCE_HASH="$(shasum -a 256 "${MACOS_DIR}/${PRODUCT_NAME}" | awk '{print $1}')"
INSTALLED_HASH="$(shasum -a 256 "${INSTALLED_EXECUTABLE}" | awk '{print $1}')"
[[ "${SOURCE_HASH}" == "${INSTALLED_HASH}" ]] || fail "Installed executable does not match the newly built executable."

step "Launching ${APP_NAME}"
open -n "${INSTALL_PATH}" || fail "${APP_NAME} was installed but could not be opened."

print -- "==> ${APP_NAME} was rebuilt, installed, and launched successfully."

Required Terminal Step

After the files are created in the new project, run:

chmod +x clean_rebuild.sh dev_rebuild.sh

Then use:

make dev
make build
make test

Notes

  • The future project must have Package.swift.
  • The future project must have an icon at Resources/music-assistant.icns.
  • If the executable product name in Package.swift is different, change PRODUCT_NAME in both scripts.
  • If the app needs permissions, add the matching usage-description keys to the generated Info.plist.