2024-03-07 23:22:53 +02:00
#!/usr/bin/env bash
2021-04-28 15:02:02 -06:00
2024-03-27 12:04:32 +01:00
set -euo pipefail
2024-03-19 14:19:32 -04:00
source script/lib/blob-store.sh
2021-04-28 15:02:02 -06:00
2023-02-21 11:26:06 -08:00
build_flag = "--release"
target_dir = "release"
open_result = false
2023-10-05 16:41:08 -07:00
local_arch = false
2023-08-28 13:32:30 -06:00
local_only = false
2024-03-27 12:04:32 +01:00
local_install = false
2023-08-28 13:32:30 -06:00
bundle_name = ""
2024-07-19 10:27:26 -07:00
can_code_sign = false
2023-08-28 13:32:30 -06:00
2024-02-12 00:30:38 -08:00
# This must match the team in the provisioning profile.
2024-07-19 10:27:26 -07:00
IDENTITY = "Zed Industries, Inc."
2025-01-03 17:00:16 -08:00
APPLE_NOTARIZATION_TEAM = "MQ55VZLNZQ"
2023-11-06 10:37:35 -07:00
2023-08-28 13:32:30 -06:00
# Function for displaying help info
help_info( ) {
echo "
Usage: ${ 0 ##*/ } [options] [bundle_name]
2024-03-07 23:22:53 +02:00
Build the application bundle for macOS.
2023-08-28 13:32:30 -06:00
Options:
2023-10-05 16:41:08 -07:00
-d Compile in debug mode
2024-07-20 12:16:54 -04:00
-l Compile for local architecture only.
2024-03-27 12:04:32 +01:00
-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.
2023-08-28 13:32:30 -06:00
-h Display this help and exit.
"
}
2023-02-21 11:26:06 -08:00
2024-03-27 12:04:32 +01:00
while getopts 'dloih' flag
2023-02-21 11:26:06 -08:00
do
case " ${ flag } " in
o) open_result = true; ;
2023-03-13 15:47:15 -06:00
d)
2023-10-05 16:41:08 -07:00
export CARGO_INCREMENTAL = true
export CARGO_BUNDLE_SKIP_BUILD = true
2023-02-21 11:26:06 -08:00
build_flag = "" ;
2023-10-05 16:41:08 -07:00
target_dir = "debug"
; ;
l)
export CARGO_INCREMENTAL = true
export CARGO_BUNDLE_SKIP_BUILD = true
local_arch = true
local_only = true
2023-02-21 11:26:06 -08:00
; ;
2024-03-27 12:04:32 +01:00
i) local_install = true; ;
2023-08-28 13:32:30 -06:00
h)
help_info
exit 0
; ;
2023-02-21 11:26:06 -08:00
esac
done
2023-08-28 13:32:30 -06:00
shift $(( OPTIND-1))
2024-03-07 23:22:53 +02:00
if [ [ $# -gt 0 ] ] ; then
if [ " $1 " ] ; then
bundle_name = $1
fi
2023-08-28 13:32:30 -06:00
fi
2024-10-29 11:32:55 +01:00
# Get release channel
pushd crates/zed
channel = $( <RELEASE_CHANNEL)
export ZED_RELEASE_CHANNEL = " ${ channel } "
popd
2021-10-25 18:11:52 +02:00
export ZED_BUNDLE = true
2021-10-25 11:02:35 +02:00
2023-06-13 18:01:51 -07:00
cargo_bundle_version = $( cargo -q bundle --help 2>& 1 | head -n 1 || echo "" )
if [ " $cargo_bundle_version " != "cargo-bundle v0.6.0-zed" ] ; then
cargo install cargo-bundle --git https://github.com/zed-industries/cargo-bundle.git --branch zed-deploy
fi
2022-02-04 08:48:00 -07:00
# Deal with versions of macOS that don't include libstdc++ headers
export CXXFLAGS = "-stdlib=libc++"
2023-08-28 13:32:30 -06:00
version_info = $( rustc --version --verbose)
host_line = $( echo " $version_info " | grep host)
local_target_triple = ${ host_line #* : }
2025-01-08 00:22:57 +02:00
# Generate the licenses first, so they can be baked into the binaries
script/generate-licenses
2023-10-05 16:41:08 -07:00
if [ " $local_arch " = true ] ; then
2023-08-28 13:32:30 -06:00
echo "Building for local target only."
2024-07-19 10:27:26 -07:00
cargo build ${ build_flag } --package zed --package cli --package remote_server
2023-08-28 13:32:30 -06:00
else
2023-11-06 17:21:34 +01:00
echo "Compiling zed binaries"
2024-10-08 17:47:24 +02:00
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
2023-08-28 13:32:30 -06:00
fi
2021-04-28 15:02:02 -06:00
2022-04-19 14:19:22 -07:00
echo "Creating application bundle"
2024-06-04 16:31:01 -06:00
pushd crates/zed
2022-10-26 15:08:53 -07:00
cp Cargo.toml Cargo.toml.backup
sed \
2024-10-25 19:04:38 +03:00
-i.backup \
2022-10-26 15:08:53 -07:00
" s/package.metadata.bundle- ${ channel } /package.metadata.bundle/ " \
Cargo.toml
2023-08-28 13:32:30 -06:00
2023-10-05 16:41:08 -07:00
if [ " $local_arch " = true ] ; then
app_path = $( cargo bundle ${ build_flag } --select-workspace-root | xargs)
2023-08-28 13:32:30 -06:00
else
2024-03-15 17:33:58 +01:00
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
2023-08-28 13:32:30 -06:00
fi
2023-02-21 11:26:06 -08:00
2022-10-26 15:08:53 -07:00
mv Cargo.toml.backup Cargo.toml
popd
2022-10-26 21:06:06 -07:00
echo " Bundled ${ app_path } "
2021-05-04 17:18:14 -06:00
2025-02-24 14:43:59 -07:00
if [ [ -n " ${ MACOS_CERTIFICATE :- } " && -n " ${ MACOS_CERTIFICATE_PASSWORD :- } " && -n " ${ APPLE_NOTARIZATION_KEY :- } " && -n " ${ APPLE_NOTARIZATION_KEY_ID :- } " && -n " ${ APPLE_NOTARIZATION_ISSUER_ID :- } " ] ] ; then
2024-07-19 10:27:26 -07:00
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
2024-03-28 18:32:11 +01:00
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 "
}
2024-03-15 17:33:58 +01:00
function prepare_binaries( ) {
local architecture = $1
local app_path = $2
2024-07-19 11:20:27 -07:00
echo " Unpacking dSYMs for $architecture "
2024-07-19 11:35:31 -07:00
if ! dsymutil --flat target/${ architecture } /${ target_dir } /Zed 2> target/dsymutil.log; then
echo "dsymutil failed"
cat target/dsymutil.log
2024-07-19 11:20:27 -07:00
exit 1
fi
2024-02-14 10:55:37 -07:00
version = " $( cargo metadata --no-deps --manifest-path crates/zed/Cargo.toml --offline --format-version= 1 | jq -r '.packages | map(select(.name == "zed"))[0].version' ) "
if [ " $channel " = = "nightly" ] ; then
version = " $version - $( git rev-parse --short HEAD) "
fi
2024-02-15 11:32:08 +01:00
2024-03-15 17:33:58 +01:00
echo " Removing existing gzipped dSYMs for $architecture "
rm -f target/${ architecture } /${ target_dir } /Zed.dwarf.gz
2024-02-15 11:32:08 +01:00
2024-03-15 17:33:58 +01:00
echo " Gzipping dSYMs for $architecture "
2025-01-18 15:30:50 -07:00
gzip -f target/${ architecture } /${ target_dir } /Zed.dwarf
2024-02-15 11:32:08 +01:00
2024-03-15 17:33:58 +01:00
echo " Uploading dSYMs for $architecture "
2024-03-19 14:19:32 -04:00
upload_to_blob_store_public \
"zed-debug-symbols" \
target/${ architecture } /${ target_dir } /Zed.dwarf.gz \
" $channel /Zed- $version - ${ architecture } .dwarf.gz "
2024-02-14 10:55:37 -07:00
2024-06-04 16:31:01 -06:00
cp target/${ architecture } /${ target_dir } /zed " ${ app_path } /Contents/MacOS/zed "
2024-03-15 17:33:58 +01:00
cp target/${ architecture } /${ target_dir } /cli " ${ app_path } /Contents/MacOS/cli "
}
2024-07-19 10:27:26 -07:00
function sign_app_binaries( ) {
2024-03-15 17:33:58 +01:00
local app_path = $1
2024-03-28 18:32:11 +01:00
local architecture = $2
local architecture_dir = $3
2024-03-15 17:33:58 +01:00
echo "Copying WebRTC.framework into the frameworks folder"
2024-11-07 11:34:27 +02:00
rm -rf " ${ app_path } /Contents/Frameworks "
mkdir -p " ${ app_path } /Contents/Frameworks "
2024-03-15 17:33:58 +01:00
if [ " $local_arch " = false ] ; then
cp -R target/${ local_target_triple } /${ target_dir } /WebRTC.framework " ${ app_path } /Contents/Frameworks/ "
else
2024-03-27 12:04:32 +01:00
cp -R target/${ target_dir } /WebRTC.framework " ${ app_path } /Contents/Frameworks/ "
cp -R target/${ target_dir } /cli " ${ app_path } /Contents/MacOS/ "
2024-03-15 17:33:58 +01:00
fi
2024-03-28 18:32:11 +01:00
echo "Downloading git binary"
download_git " ${ architecture } " " ${ app_path } /Contents/MacOS/git "
2024-03-15 17:33:58 +01:00
# Note: The app identifier for our development builds is the same as the app identifier for nightly.
2024-06-04 16:31:01 -06:00
cp crates/zed/contents/$channel /embedded.provisionprofile " ${ app_path } /Contents/ "
2024-03-15 17:33:58 +01:00
2024-07-19 10:27:26 -07:00
if [ [ $can_code_sign = true ] ] ; then
echo "Code signing binaries"
2024-03-15 17:33:58 +01:00
# sequence of codesign commands modeled after this example: https://developer.apple.com/forums/thread/701514
2024-07-19 10:27:26 -07:00
/usr/bin/codesign --deep --force --timestamp --sign " $IDENTITY " " ${ app_path } /Contents/Frameworks/WebRTC.framework " -v
/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
2024-03-15 17:33:58 +01:00
else
2025-02-24 14:43:59 -07:00
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"
2024-03-15 17:33:58 +01:00
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.
2024-06-04 16:31:01 -06:00
cat crates/zed/resources/zed.entitlements | sed '/com.apple.developer.associated-domains/,+1d' > " ${ app_path } /Contents/Resources/zed.entitlements "
2024-03-15 17:33:58 +01:00
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
2024-03-27 12:04:32 +01:00
if [ " $local_install " = true ] ; then
2024-03-15 17:33:58 +01:00
rm -rf " /Applications/ $bundle_name "
2024-03-27 12:04:32 +01:00
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
2024-03-15 17:33:58 +01:00
else
2024-03-27 12:04:32 +01:00
if [ " $open_result " = true ] ; then
echo " Opening $app_path "
open " $app_path "
fi
2024-03-15 17:33:58 +01:00
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 } "
2025-02-24 14:43:59 -07:00
notarization_key_file = $( mktemp)
2024-03-15 17:33:58 +01:00
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
2024-08-19 17:08:46 -04:00
dmg-license script/terms/terms.json " ${ dmg_file_path } "
2024-03-15 17:33:58 +01:00
2024-07-19 10:27:26 -07:00
if [ [ $can_code_sign = true ] ] ; then
2024-03-15 17:33:58 +01:00
echo "Notarizing DMG with Apple"
2024-07-19 10:27:26 -07:00
/usr/bin/codesign --deep --force --timestamp --options runtime --sign " $IDENTITY " " $( pwd ) / ${ dmg_file_path } " -v
2025-02-24 18:48:47 -07:00
echo " $APPLE_NOTARIZATION_KEY " > " $notarization_key_file "
2025-02-24 14:43:59 -07:00
" ${ 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 "
2025-02-24 18:48:47 -07:00
" ${ xcode_bin_dir_path } /stapler " staple " ${ dmg_file_path } "
2024-03-15 17:33:58 +01:00
fi
if [ " $open_result " = true ] ; then
open $dmg_target_directory
fi
fi
}
2024-07-19 10:27:26 -07:00
function sign_binary( ) {
local binary_path = $1
if [ [ $can_code_sign = true ] ] ; then
echo " Code signing executable $binary_path "
2024-10-08 17:47:24 +02:00
/usr/bin/codesign --deep --force --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign " $IDENTITY " " ${ binary_path } " -v
2024-07-19 10:27:26 -07:00
fi
}
2024-03-15 17:33:58 +01:00
if [ " $local_arch " = true ] ; then
2024-07-19 10:27:26 -07:00
sign_app_binaries " $app_path " " $local_target_triple " " $local_target_triple "
sign_binary "target/release/remote_server"
2024-03-15 17:33:58 +01:00
else
# Create universal binary
2024-03-28 18:32:11 +01:00
prepare_binaries "aarch64-apple-darwin" " $app_path_aarch64 "
prepare_binaries "x86_64-apple-darwin" " $app_path_x64 "
2021-10-25 11:02:35 +02:00
2024-07-19 10:27:26 -07:00
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"
2025-01-18 15:30:50 -07:00
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
2023-03-13 15:47:15 -06:00
fi