Detailed changes
@@ -511,27 +511,16 @@ jobs:
fi
exit $RET_CODE
- bundle-mac:
+ release-build-mac:
timeout-minutes: 120
- name: Create a macOS bundle
+ name: Build optimized macOS artifacts
runs-on:
- self-mini-macos
if: |
( startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling') )
needs: [macos_tests]
- env:
- MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
- MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
- APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
- APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
- APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
steps:
- - name: Install Node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
- with:
- node-version: "18"
-
- name: Setup Sentry CLI
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b #v2
with:
@@ -568,7 +557,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create macOS app bundle
- run: script/bundle-mac
+ run: script/build-mac
- name: Rename binaries
if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
@@ -590,6 +579,42 @@ jobs:
name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
+ notarize-mac:
+ name: Notarize macOS binaries
+ timeout-minutes: 120
+ runs-on:
+ - self-mini-macos
+ if: |
+ ( startsWith(github.ref, 'refs/tags/v')
+ || contains(github.event.pull_request.labels.*.name, 'run-bundling') )
+ needs: [release-build-mac]
+ strategy:
+ matrix:
+ target: [aarch64-apple-darwin, x86_64-apple-darwin]
+ env:
+ MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
+ MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
+ APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
+ APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
+ APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
+
+ steps:
+ - name: Install Node
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
+ with:
+ node-version: "18"
+ - name: Notarize ${{ matrix.target }}
+ run: ./script/notarize-mac ${{ matrix.target }}
+
+ bundle-mac:
+ name: Create macOS release
+ timeout-minutes: 60
+ needs: [notarize-mac]
+ runs-on: self-mini-macos
+ if: |
+ ( startsWith(github.ref, 'refs/tags/v')
+ || contains(github.event.pull_request.labels.*.name, 'run-bundling') )
+ steps:
- uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
name: Upload app bundle to release
if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
@@ -0,0 +1,155 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+source script/lib/blob-store.sh
+
+build_flag="--release"
+target_dir="release"
+local_arch=false
+local_only=false
+local_install=false
+bundle_name=""
+
+# This must match the team in the provisioning profile.
+IDENTITY="Zed Industries, Inc."
+APPLE_NOTARIZATION_TEAM="MQ55VZLNZQ"
+
+# Function for displaying help info
+help_info() {
+ echo "
+Usage: ${0##*/} [options] [bundle_name]
+Build the application bundle for macOS.
+
+Options:
+ -d Compile in debug mode
+ -l Compile for local architecture only.
+ -i Install the resulting DMG into /Applications in local mode. Noop without -l.
+ -h Display this help and exit.
+ "
+}
+
+function prepare_binaries() {
+ local architecture=$1
+ local app_path=$2
+
+ cp target/${architecture}/${target_dir}/zed "${app_path}/Contents/MacOS/zed"
+ cp target/${architecture}/${target_dir}/cli "${app_path}/Contents/MacOS/cli"
+}
+
+while getopts 'dlih' flag
+do
+ case "${flag}" in
+ d)
+ export CARGO_INCREMENTAL=true
+ export CARGO_BUNDLE_SKIP_BUILD=true
+ build_flag="";
+ target_dir="debug"
+ ;;
+ l)
+ export CARGO_INCREMENTAL=true
+ export CARGO_BUNDLE_SKIP_BUILD=true
+ local_arch=true
+ local_only=true
+ ;;
+ i) local_install=true;;
+ h)
+ help_info
+ exit 0
+ ;;
+ esac
+done
+
+shift $((OPTIND-1))
+
+if [[ $# -gt 0 ]]; then
+ if [ "$1" ]; then
+ bundle_name=$1
+ fi
+fi
+
+# Get release channel
+pushd crates/zed
+channel=$(<RELEASE_CHANNEL)
+export ZED_RELEASE_CHANNEL="${channel}"
+popd
+
+export ZED_BUNDLE=true
+
+cargo_bundle_version=$(cargo -q bundle --help 2>&1 | head -n 1 || echo "")
+if [ "$cargo_bundle_version" != "cargo-bundle v0.6.1-zed" ]; then
+ cargo install cargo-bundle --git https://github.com/zed-industries/cargo-bundle.git --branch zed-deploy
+fi
+
+# Deal with versions of macOS that don't include libstdc++ headers
+export CXXFLAGS="-stdlib=libc++"
+
+version_info=$(rustc --version --verbose)
+host_line=$(echo "$version_info" | grep host)
+local_target_triple=${host_line#*: }
+
+# Generate the licenses first, so they can be baked into the binaries
+script/generate-licenses
+
+if [ "$local_arch" = true ]; then
+ echo "Building for local target only."
+ cargo build ${build_flag} --package zed --package cli --package remote_server
+else
+ rustup target add aarch64-apple-darwin
+ rustup target add x86_64-apple-darwin
+
+ echo "Compiling zed binaries"
+ cargo build ${build_flag} --package zed --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin
+ # Build remote_server in separate invocation to prevent feature unification from other crates
+ # from influencing dynamic libraries required by it.
+ cargo build ${build_flag} --package remote_server --target aarch64-apple-darwin --target x86_64-apple-darwin
+fi
+
+echo "Creating application bundle"
+pushd crates/zed
+cp Cargo.toml Cargo.toml.backup
+sed \
+ -i.backup \
+ "s/package.metadata.bundle-${channel}/package.metadata.bundle/" \
+ Cargo.toml
+
+if [ "$local_arch" = true ]; then
+ app_path=$(cargo bundle ${build_flag} --select-workspace-root | xargs)
+else
+ app_path_x64=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs)
+ app_path_aarch64=$(cargo bundle ${build_flag} --target aarch64-apple-darwin --select-workspace-root | xargs)
+ app_path=$app_path_x64
+fi
+
+if [ "$local_arch" = true ]; then
+ cp -R target/${target_dir}/cli "${app_path}/Contents/MacOS/"
+else
+ prepare_binaries "aarch64-apple-darwin" "$app_path_aarch64"
+ prepare_binaries "x86_64-apple-darwin" "$app_path_x64"
+fi
+
+mv Cargo.toml.backup Cargo.toml
+popd
+echo "Built ${app_path}"
+
+function upload_debug_info() {
+ architecture=$1
+ if [[ -n "${SENTRY_AUTH_TOKEN:-}" ]]; then
+ echo "Uploading zed debug symbols to sentry..."
+ # note: this uploads the unstripped binary which is needed because it contains
+ # .eh_frame data for stack unwinding. see https://github.com/getsentry/symbolic/issues/783
+ sentry-cli debug-files upload --include-sources --wait -p zed -o zed-dev \
+ "target/${architecture}/${target_dir}/zed" \
+ "target/${architecture}/${target_dir}/remote_server" \
+ "target/${architecture}/${target_dir}/zed.dwarf"
+ else
+ echo "missing SENTRY_AUTH_TOKEN. skipping sentry upload."
+ fi
+}
+
+if command -v sentry-cli >/dev/null 2>&1; then
+ upload_debug_info "aarch64-apple-darwin"
+ upload_debug_info "x86_64-apple-darwin"
+else
+ echo "sentry-cli not found. skipping sentry upload."
+ echo "install with: 'curl -sL https://sentry.io/get-cli | bash'"
+fi
@@ -7,14 +7,9 @@ build_flag="--release"
target_dir="release"
open_result=false
local_arch=false
-local_only=false
local_install=false
bundle_name=""
-can_code_sign=false
-# This must match the team in the provisioning profile.
-IDENTITY="Zed Industries, Inc."
-APPLE_NOTARIZATION_TEAM="MQ55VZLNZQ"
# Function for displaying help info
help_info() {
@@ -31,21 +26,26 @@ Options:
"
}
+build_args=""
while getopts 'dloih' flag
do
case "${flag}" in
- o) open_result=true;;
+ o) open_result=true
+ build_args="${build_args} -o"
+ ;;
d)
export CARGO_INCREMENTAL=true
export CARGO_BUNDLE_SKIP_BUILD=true
build_flag="";
target_dir="debug"
+ build_args="${build_args} -d"
;;
l)
export CARGO_INCREMENTAL=true
export CARGO_BUNDLE_SKIP_BUILD=true
local_arch=true
local_only=true
+ build_args="${build_args} -l"
;;
i) local_install=true;;
h)
@@ -63,307 +63,9 @@ if [[ $# -gt 0 ]]; then
fi
fi
-# Get release channel
-pushd crates/zed
-channel=$(<RELEASE_CHANNEL)
-export ZED_RELEASE_CHANNEL="${channel}"
-popd
-
-export ZED_BUNDLE=true
-
-cargo_bundle_version=$(cargo -q bundle --help 2>&1 | head -n 1 || echo "")
-if [ "$cargo_bundle_version" != "cargo-bundle v0.6.1-zed" ]; then
- cargo install cargo-bundle --git https://github.com/zed-industries/cargo-bundle.git --branch zed-deploy
-fi
-
-# Deal with versions of macOS that don't include libstdc++ headers
-export CXXFLAGS="-stdlib=libc++"
-
-version_info=$(rustc --version --verbose)
-host_line=$(echo "$version_info" | grep host)
-local_target_triple=${host_line#*: }
-
-# Generate the licenses first, so they can be baked into the binaries
-script/generate-licenses
-
-if [ "$local_arch" = true ]; then
- echo "Building for local target only."
- cargo build ${build_flag} --package zed --package cli --package remote_server
-else
- rustup target add aarch64-apple-darwin
- rustup target add x86_64-apple-darwin
-
- echo "Compiling zed binaries"
- cargo build ${build_flag} --package zed --package cli --target aarch64-apple-darwin --target x86_64-apple-darwin
- # Build remote_server in separate invocation to prevent feature unification from other crates
- # from influencing dynamic libraries required by it.
- cargo build ${build_flag} --package remote_server --target aarch64-apple-darwin --target x86_64-apple-darwin
-fi
-
-echo "Creating application bundle"
-pushd crates/zed
-cp Cargo.toml Cargo.toml.backup
-sed \
- -i.backup \
- "s/package.metadata.bundle-${channel}/package.metadata.bundle/" \
- Cargo.toml
-
-if [ "$local_arch" = true ]; then
- app_path=$(cargo bundle ${build_flag} --select-workspace-root | xargs)
-else
- app_path_x64=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs)
- app_path_aarch64=$(cargo bundle ${build_flag} --target aarch64-apple-darwin --select-workspace-root | xargs)
- app_path=$app_path_x64
-fi
-
-mv Cargo.toml.backup Cargo.toml
-popd
-echo "Bundled ${app_path}"
-
-if [[ -n "${MACOS_CERTIFICATE:-}" && -n "${MACOS_CERTIFICATE_PASSWORD:-}" && -n "${APPLE_NOTARIZATION_KEY:-}" && -n "${APPLE_NOTARIZATION_KEY_ID:-}" && -n "${APPLE_NOTARIZATION_ISSUER_ID:-}" ]]; then
- can_code_sign=true
-
- echo "Setting up keychain for code signing..."
- security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo ""
- security default-keychain -s zed.keychain
- security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
- echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12
- security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
- rm /tmp/zed-certificate.p12
- security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
-
- function cleanup() {
- echo "Cleaning up keychain"
- security default-keychain -s login.keychain
- security delete-keychain zed.keychain
- }
-
- trap cleanup EXIT
-fi
-
-GIT_VERSION="v2.43.3"
-GIT_VERSION_SHA="fa29823"
-
-function download_and_unpack() {
- local url=$1
- local path_to_unpack=$2
- local target_path=$3
-
- temp_dir=$(mktemp -d)
-
- if ! command -v curl &> /dev/null; then
- echo "curl is not installed. Please install curl to continue."
- exit 1
- fi
-
- curl --silent --fail --location "$url" | tar -xvz -C "$temp_dir" -f - $path_to_unpack
-
- mv "$temp_dir/$path_to_unpack" "$target_path"
-
- rm -rf "$temp_dir"
-}
-
-function download_git() {
- local architecture=$1
- local target_binary=$2
-
- tmp_dir=$(mktemp -d)
- pushd "$tmp_dir"
-
- case "$architecture" in
- aarch64-apple-darwin)
- download_and_unpack "https://github.com/desktop/dugite-native/releases/download/${GIT_VERSION}/dugite-native-${GIT_VERSION}-${GIT_VERSION_SHA}-macOS-arm64.tar.gz" bin/git ./git
- ;;
- x86_64-apple-darwin)
- download_and_unpack "https://github.com/desktop/dugite-native/releases/download/${GIT_VERSION}/dugite-native-${GIT_VERSION}-${GIT_VERSION_SHA}-macOS-x64.tar.gz" bin/git ./git
- ;;
- *)
- echo "Unsupported architecture: $architecture"
- exit 1
- ;;
- esac
-
- popd
-
- mv "${tmp_dir}/git" "${target_binary}"
- rm -rf "$tmp_dir"
-}
-
-function prepare_binaries() {
- local architecture=$1
- local app_path=$2
-
- cp target/${architecture}/${target_dir}/zed "${app_path}/Contents/MacOS/zed"
- cp target/${architecture}/${target_dir}/cli "${app_path}/Contents/MacOS/cli"
-}
-
-function sign_app_binaries() {
- local app_path=$1
- local architecture=$2
- local architecture_dir=$3
- rm -rf "${app_path}/Contents/Frameworks"
- mkdir -p "${app_path}/Contents/Frameworks"
- if [ "$local_arch" = true ]; then
- cp -R target/${target_dir}/cli "${app_path}/Contents/MacOS/"
- fi
-
- echo "Downloading git binary"
- download_git "${architecture}" "${app_path}/Contents/MacOS/git"
-
- # Note: The app identifier for our development builds is the same as the app identifier for nightly.
- cp crates/zed/contents/$channel/embedded.provisionprofile "${app_path}/Contents/"
-
- if [[ $can_code_sign = true ]]; then
- echo "Code signing binaries"
- # sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514
- /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "${app_path}/Contents/MacOS/cli" -v
- /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "${app_path}/Contents/MacOS/git" -v
- /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${app_path}/Contents/MacOS/zed" -v
- /usr/bin/codesign --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${app_path}" -v
- else
- echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_KEY, APPLE_NOTARIZATION_KEY_ID, APPLE_NOTARIZATION_ISSUER_ID"
- if [[ "$local_only" = false ]]; then
- echo "To create a self-signed local build use ./scripts/build.sh -ldf"
- exit 1
- fi
-
- echo "====== WARNING ======"
- echo "This bundle is being signed without all entitlements, some features (e.g. universal links) will not work"
- echo "====== WARNING ======"
-
- # NOTE: if you need to test universal links you have a few paths forward:
- # - create a PR and tag it with the `run-bundling` label, and download the .dmg file from there.
- # - get a signing key for the MQ55VZLNZQ team from Nathan.
- # - create your own signing key, and update references to MQ55VZLNZQ to your own team ID
- # then comment out this line.
- cat crates/zed/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements"
-
- codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v
- fi
-
- if [[ "$target_dir" = "debug" && "$local_only" = false ]]; then
- if [ "$open_result" = true ]; then
- open "$app_path"
- else
- echo "Created application bundle:"
- echo "$app_path"
- fi
- exit 0
- fi
-
- # If bundle_name is not set or empty, use the basename of $app_path
- if [ -z "$bundle_name" ]; then
- bundle_name=$(basename "$app_path")
- else
- # If bundle_name doesn't end in .app, append it
- if [[ "$bundle_name" != *.app ]]; then
- bundle_name="$bundle_name.app"
- fi
- fi
-
- if [ "$local_only" = true ]; then
- if [ "$local_install" = true ]; then
- rm -rf "/Applications/$bundle_name"
- mv "$app_path" "/Applications/$bundle_name"
- echo "Installed application bundle: /Applications/$bundle_name"
- if [ "$open_result" = true ]; then
- echo "Opening /Applications/$bundle_name"
- open "/Applications/$bundle_name"
- fi
- else
- if [ "$open_result" = true ]; then
- echo "Opening $app_path"
- open "$app_path"
- fi
- fi
- else
- dmg_target_directory="target/${architecture_dir}/${target_dir}"
- dmg_source_directory="${dmg_target_directory}/dmg"
- dmg_file_path="${dmg_target_directory}/Zed.dmg"
- xcode_bin_dir_path="$(xcode-select -p)/usr/bin"
-
- rm -rf ${dmg_source_directory}
- mkdir -p ${dmg_source_directory}
- mv "${app_path}" "${dmg_source_directory}"
- notarization_key_file=$(mktemp)
-
- echo "Adding symlink to /Applications to ${dmg_source_directory}"
- ln -s /Applications ${dmg_source_directory}
-
- echo "Creating final DMG at ${dmg_file_path} using ${dmg_source_directory}"
- hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}"
-
- # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`.
- # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now.
- echo "Removing symlink to /Applications from ${dmg_source_directory}"
- rm ${dmg_source_directory}/Applications
-
- echo "Adding license agreement to DMG"
- npm install --global dmg-license minimist
- dmg-license script/terms/terms.json "${dmg_file_path}"
-
- if [[ $can_code_sign = true ]]; then
- echo "Notarizing DMG with Apple"
- /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "$(pwd)/${dmg_file_path}" -v
- echo "$APPLE_NOTARIZATION_KEY" > "$notarization_key_file"
- "${xcode_bin_dir_path}/notarytool" submit --wait --key "$notarization_key_file" --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER_ID" "${dmg_file_path}"
- rm "$notarization_key_file"
- "${xcode_bin_dir_path}/stapler" staple "${dmg_file_path}"
- fi
-
- if [ "$open_result" = true ]; then
- open $dmg_target_directory
- fi
- fi
-}
-
-function sign_binary() {
- local binary_path=$1
-
- if [[ $can_code_sign = true ]]; then
- echo "Code signing executable $binary_path"
- /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${binary_path}" -v
- fi
-}
-
-if [ "$local_arch" = true ]; then
- sign_app_binaries "$app_path" "$local_target_triple" "$local_target_triple"
-
- sign_binary "target/release/remote_server"
-else
- # Create universal binary
- prepare_binaries "aarch64-apple-darwin" "$app_path_aarch64"
- prepare_binaries "x86_64-apple-darwin" "$app_path_x64"
-
-
- sign_app_binaries "$app_path_x64" "x86_64-apple-darwin" "x86_64-apple-darwin"
- sign_app_binaries "$app_path_aarch64" "aarch64-apple-darwin" "aarch64-apple-darwin"
-
- sign_binary "target/x86_64-apple-darwin/release/remote_server"
- sign_binary "target/aarch64-apple-darwin/release/remote_server"
- gzip -f --stdout --best target/x86_64-apple-darwin/release/remote_server > target/zed-remote-server-macos-x86_64.gz
- gzip -f --stdout --best target/aarch64-apple-darwin/release/remote_server > target/zed-remote-server-macos-aarch64.gz
-fi
-
-function upload_debug_info() {
- architecture=$1
- if [[ -n "${SENTRY_AUTH_TOKEN:-}" ]]; then
- echo "Uploading zed debug symbols to sentry..."
- # note: this uploads the unstripped binary which is needed because it contains
- # .eh_frame data for stack unwinding. see https://github.com/getsentry/symbolic/issues/783
- sentry-cli debug-files upload --include-sources --wait -p zed -o zed-dev \
- "target/${architecture}/${target_dir}/zed" \
- "target/${architecture}/${target_dir}/remote_server" \
- "target/${architecture}/${target_dir}/zed.dwarf"
- else
- echo "missing SENTRY_AUTH_TOKEN. skipping sentry upload."
- fi
-}
-
-if command -v sentry-cli >/dev/null 2>&1; then
- upload_debug_info "aarch64-apple-darwin"
- upload_debug_info "x86_64-apple-darwin"
+script/build-mac $build_args
+if [ "$local_only" = true ]; then
+ script/notarize-mac $bundle_name
else
- echo "sentry-cli not found. skipping sentry upload."
- echo "install with: 'curl -sL https://sentry.io/get-cli | bash'"
+ script/notarize-mac $bundle_name
fi
@@ -0,0 +1,255 @@
+# This must match the team in the provisioning profile.
+IDENTITY="Zed Industries, Inc."
+APPLE_NOTARIZATION_TEAM="MQ55VZLNZQ"
+
+local_arch=false
+local_only=false
+local_install=false
+can_code_sign=false
+app_path=""
+app_target=""
+# Function for displaying help info
+help_info() {
+ echo "
+Usage: ${0##*/} [options] [bundle_name]
+Notarize the application bundle for macOS.
+
+Options:
+ -l Notarize local architecture only.
+ -o Open dir with the resulting DMG or launch the app itself in local mode.
+ -i Install the resulting DMG into /Applications in local mode. Noop without -l.
+ -h Display this help and exit.
+ "
+}
+
+while getopts 'loih' flag
+do
+ case "${flag}" in
+ o) open_result=true
+ ;;
+ l)
+ local_arch=true
+ local_only=true
+ ;;
+ i) local_install=true;;
+ h)
+ help_info
+ exit 0
+ ;;
+ esac
+done
+
+shift
+if [[ $# -gt 0 ]]; then
+ if [ "$1" ]; then
+ app_path=$1
+ fi
+ if [ "$2" ]; then
+ app_target=$2
+ fi
+fi
+
+pushd crates/zed
+channel=$(<RELEASE_CHANNEL)
+export ZED_RELEASE_CHANNEL="${channel}"
+popd
+
+if [[ -n "${MACOS_CERTIFICATE:-}" && -n "${MACOS_CERTIFICATE_PASSWORD:-}" && -n "${APPLE_NOTARIZATION_KEY:-}" && -n "${APPLE_NOTARIZATION_KEY_ID:-}" && -n "${APPLE_NOTARIZATION_ISSUER_ID:-}" ]]; then
+ can_code_sign=true
+
+ echo "Setting up keychain for code signing..."
+ security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo ""
+ security default-keychain -s zed.keychain
+ security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
+ echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12
+ security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
+ rm /tmp/zed-certificate.p12
+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
+
+ function cleanup() {
+ echo "Cleaning up keychain"
+ security default-keychain -s login.keychain
+ security delete-keychain zed.keychain
+ }
+
+ trap cleanup EXIT
+fi
+
+
+GIT_VERSION="v2.43.3"
+GIT_VERSION_SHA="fa29823"
+
+function download_and_unpack() {
+ local url=$1
+ local path_to_unpack=$2
+ local target_path=$3
+
+ temp_dir=$(mktemp -d)
+
+ if ! command -v curl &> /dev/null; then
+ echo "curl is not installed. Please install curl to continue."
+ exit 1
+ fi
+
+ curl --silent --fail --location "$url" | tar -xvz -C "$temp_dir" -f - $path_to_unpack
+
+ mv "$temp_dir/$path_to_unpack" "$target_path"
+
+ rm -rf "$temp_dir"
+}
+
+function download_git() {
+ local architecture=$1
+ local target_binary=$2
+
+ tmp_dir=$(mktemp -d)
+ pushd "$tmp_dir"
+
+ case "$architecture" in
+ aarch64-apple-darwin)
+ download_and_unpack "https://github.com/desktop/dugite-native/releases/download/${GIT_VERSION}/dugite-native-${GIT_VERSION}-${GIT_VERSION_SHA}-macOS-arm64.tar.gz" bin/git ./git
+ ;;
+ x86_64-apple-darwin)
+ download_and_unpack "https://github.com/desktop/dugite-native/releases/download/${GIT_VERSION}/dugite-native-${GIT_VERSION}-${GIT_VERSION_SHA}-macOS-x64.tar.gz" bin/git ./git
+ ;;
+ *)
+ echo "Unsupported architecture: $architecture"
+ exit 1
+ ;;
+ esac
+
+ popd
+
+ mv "${tmp_dir}/git" "${target_binary}"
+ rm -rf "$tmp_dir"
+}
+
+
+function sign_app_binaries() {
+ local app_path=$1
+ local architecture=$2
+ local architecture_dir=$architecture
+ rm -rf "${app_path}/Contents/Frameworks"
+ mkdir -p "${app_path}/Contents/Frameworks"
+
+ echo "Downloading git binary"
+ download_git "${architecture}" "${app_path}/Contents/MacOS/git"
+
+ # Note: The app identifier for our development builds is the same as the app identifier for nightly.
+ cp crates/zed/contents/$channel/embedded.provisionprofile "${app_path}/Contents/"
+
+ if [[ $can_code_sign = true ]]; then
+ echo "Code signing binaries"
+ # sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514
+ /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "${app_path}/Contents/MacOS/cli" -v
+ /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "${app_path}/Contents/MacOS/git" -v
+ /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${app_path}/Contents/MacOS/zed" -v
+ /usr/bin/codesign --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${app_path}" -v
+ else
+ echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_KEY, APPLE_NOTARIZATION_KEY_ID, APPLE_NOTARIZATION_ISSUER_ID"
+ if [[ "$local_only" = false ]]; then
+ echo "To create a self-signed local build use ./scripts/build.sh -ldf"
+ exit 1
+ fi
+
+ echo "====== WARNING ======"
+ echo "This bundle is being signed without all entitlements, some features (e.g. universal links) will not work"
+ echo "====== WARNING ======"
+
+ # NOTE: if you need to test universal links you have a few paths forward:
+ # - create a PR and tag it with the `run-bundling` label, and download the .dmg file from there.
+ # - get a signing key for the MQ55VZLNZQ team from Nathan.
+ # - create your own signing key, and update references to MQ55VZLNZQ to your own team ID
+ # then comment out this line.
+ cat crates/zed/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > "${app_path}/Contents/Resources/zed.entitlements"
+
+ codesign --force --deep --entitlements "${app_path}/Contents/Resources/zed.entitlements" --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v
+ fi
+
+ if [[ "$target_dir" = "debug" && "$local_only" = false ]]; then
+ if [ "$open_result" = true ]; then
+ open "$app_path"
+ else
+ echo "Created application bundle:"
+ echo "$app_path"
+ fi
+ exit 0
+ fi
+ bundle_name=$(basename "$app_path")
+
+ # If bundle_name doesn't end in .app, append it
+ if [[ "$bundle_name" != *.app ]]; then
+ bundle_name="$bundle_name.app"
+ fi
+
+ if [ "$local_only" = true ]; then
+ if [ "$local_install" = true ]; then
+ rm -rf "/Applications/$bundle_name"
+ mv "$app_path" "/Applications/$bundle_name"
+ echo "Installed application bundle: /Applications/$bundle_name"
+ if [ "$open_result" = true ]; then
+ echo "Opening /Applications/$bundle_name"
+ open "/Applications/$bundle_name"
+ fi
+ else
+ if [ "$open_result" = true ]; then
+ echo "Opening $app_path"
+ open "$app_path"
+ fi
+ fi
+ else
+ dmg_target_directory="target/${architecture_dir}/${target_dir}"
+ dmg_source_directory="${dmg_target_directory}/dmg"
+ dmg_file_path="${dmg_target_directory}/Zed.dmg"
+ xcode_bin_dir_path="$(xcode-select -p)/usr/bin"
+
+ rm -rf ${dmg_source_directory}
+ mkdir -p ${dmg_source_directory}
+ mv "${app_path}" "${dmg_source_directory}"
+ notarization_key_file=$(mktemp)
+
+ echo "Adding symlink to /Applications to ${dmg_source_directory}"
+ ln -s /Applications ${dmg_source_directory}
+
+ echo "Creating final DMG at ${dmg_file_path} using ${dmg_source_directory}"
+ hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}"
+
+ # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`.
+ # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now.
+ echo "Removing symlink to /Applications from ${dmg_source_directory}"
+ rm ${dmg_source_directory}/Applications
+
+ echo "Adding license agreement to DMG"
+ npm install --global dmg-license minimist
+ dmg-license script/terms/terms.json "${dmg_file_path}"
+
+ if [[ $can_code_sign = true ]]; then
+ echo "Notarizing DMG with Apple"
+ /usr/bin/codesign --deep --force --timestamp --options runtime --sign "$IDENTITY" "$(pwd)/${dmg_file_path}" -v
+ echo "$APPLE_NOTARIZATION_KEY" > "$notarization_key_file"
+ "${xcode_bin_dir_path}/notarytool" submit --wait --key "$notarization_key_file" --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER_ID" "${dmg_file_path}"
+ rm "$notarization_key_file"
+ "${xcode_bin_dir_path}/stapler" staple "${dmg_file_path}"
+ fi
+
+ if [ "$open_result" = true ]; then
+ open $dmg_target_directory
+ fi
+ fi
+}
+
+function sign_binary() {
+ local binary_path=$1
+
+ if [[ $can_code_sign = true ]]; then
+ echo "Code signing executable $binary_path"
+ /usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "$IDENTITY" "${binary_path}" -v
+ fi
+}
+
+sign_app_binaries "$app_path" "$app_target"
+sign_binary "target/x86_64-apple-darwin/release/remote_server"
+
+if [ "$local_arch" = false ]; then
+ gzip -f --stdout --best target/x86_64-apple-darwin/release/remote_server > target/zed-remote-server-macos-x86_64.gz
+fi