GitComet/scripts/package-macos.sh
2026-03-12 20:36:10 +02:00

204 lines
5 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage: scripts/package-macos.sh --version VERSION [--arch arm64|x86_64] [--release|--debug] [--no-build] [--skip-dmg] [--out-dir PATH]
Builds a macOS app bundle and release artifacts:
- gitcomet-v<VERSION>-macos-<ARCH>.tar.gz
- gitcomet-v<VERSION>-macos-<ARCH>.dmg
Defaults:
--release, build if needed, output to ./dist
USAGE
}
version=""
arch=""
mode="release"
build=1
create_dmg=1
out_dir="dist"
while [[ $# -gt 0 ]]; do
case "$1" in
--version)
version="${2:-}"
shift 2
;;
--arch)
arch="${2:-}"
shift 2
;;
--release)
mode="release"
shift
;;
--debug)
mode="debug"
shift
;;
--no-build)
build=0
shift
;;
--skip-dmg)
create_dmg=0
shift
;;
--out-dir)
out_dir="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown arg: $1" >&2
usage
exit 2
;;
esac
done
if [[ -z "$version" ]]; then
echo "--version is required (e.g. --version 0.2.0)." >&2
exit 2
fi
host_arch_raw="$(uname -m)"
case "$host_arch_raw" in
arm64|aarch64) host_arch="arm64" ;;
x86_64|amd64) host_arch="x86_64" ;;
*)
echo "Unsupported machine architecture: $host_arch_raw" >&2
exit 1
;;
esac
if [[ -z "$arch" ]]; then
arch="$host_arch"
fi
if [[ "$arch" != "arm64" && "$arch" != "x86_64" ]]; then
echo "Unsupported --arch '$arch'. Expected arm64 or x86_64." >&2
exit 2
fi
if [[ "$arch" != "$host_arch" ]]; then
echo "Requested --arch '$arch' does not match host architecture '$host_arch'." >&2
echo "Use a native runner for each architecture." >&2
exit 1
fi
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
bin_src="${repo_root}/target/${mode}/gitcomet-app"
if [[ $build -eq 1 && ! -x "$bin_src" ]]; then
cargo_mode_flag=()
if [[ "$mode" == "release" ]]; then
cargo_mode_flag=(--release)
fi
(cd "$repo_root" && cargo build -p gitcomet-app "${cargo_mode_flag[@]}" --locked --features ui-gpui,gix --bins)
fi
if [[ ! -x "$bin_src" ]]; then
echo "Binary not found or not executable: $bin_src" >&2
echo "Build first or omit --no-build." >&2
exit 1
fi
if [[ "$out_dir" = /* ]]; then
mkdir -p "$out_dir"
out_abs="$(cd "$out_dir" && pwd)"
else
mkdir -p "${repo_root}/${out_dir}"
out_abs="$(cd "${repo_root}/${out_dir}" && pwd)"
fi
stage_root="${out_abs}/stage"
release_root="gitcomet-v${version}-macos-${arch}"
release_dir="${stage_root}/${release_root}"
app_bundle="${release_dir}/GitComet.app"
contents_dir="${app_bundle}/Contents"
macos_dir="${contents_dir}/MacOS"
resources_dir="${contents_dir}/Resources"
rm -rf "$release_dir"
mkdir -p "$macos_dir" "$resources_dir"
install -m755 "$bin_src" "${macos_dir}/gitcomet-app"
install -m755 "$bin_src" "${release_dir}/gitcomet-app"
install -m644 "${repo_root}/README.md" "${release_dir}/README.md"
install -m644 "${repo_root}/LICENSE-AGPL-3.0" "${release_dir}/LICENSE-AGPL-3.0"
install -m644 "${repo_root}/NOTICE" "${release_dir}/NOTICE"
cat > "${contents_dir}/Info.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>GitComet</string>
<key>CFBundleExecutable</key>
<string>gitcomet-app</string>
<key>CFBundleIdentifier</key>
<string>ai.autoexplore.gitcomet</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>GitComet</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${version}</string>
<key>CFBundleVersion</key>
<string>${version}</string>
<key>LSMinimumSystemVersion</key>
<string>13.0</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
PLIST
# Keep bundle metadata minimal for reliable packaging in CI. The app uses the
# default icon unless a prebuilt .icns file is added to the repository later.
# Create a deterministic tarball root directory per version/arch.
tarball_path="${out_abs}/${release_root}.tar.gz"
rm -f "$tarball_path"
tar -C "$stage_root" -czf "$tarball_path" "$release_root"
dmg_path="${out_abs}/${release_root}.dmg"
if [[ $create_dmg -eq 1 ]]; then
# Build a drag-and-drop DMG with an /Applications shortcut.
dmg_stage="${out_abs}/dmg-stage-${arch}"
rm -rf "$dmg_stage"
mkdir -p "$dmg_stage"
cp -R "$app_bundle" "${dmg_stage}/GitComet.app"
ln -s /Applications "${dmg_stage}/Applications"
# Preserve compatibility with older macOS tooling.
rm -f "$dmg_path"
hdiutil create \
-volname "GitComet" \
-srcfolder "$dmg_stage" \
-ov \
-format UDZO \
"$dmg_path" >/dev/null
rm -rf "$dmg_stage"
fi
echo "Packaged macOS artifacts:"
echo " $tarball_path"
if [[ $create_dmg -eq 1 ]]; then
echo " $dmg_path"
else
echo " (skipped DMG creation via --skip-dmg)"
fi