One of the reasons we didn't spot that we were missing the telemetry env vars for the production builds was that nightly (which was working) had its own set of build steps. This re-uses those and pushes the env vars down from the workflow to the job. It also fixes nightly releases to upload all-in-one go so that all platforms update in sync. Closes #41655 Release Notes: - N/A
314 lines
12 KiB
Bash
Executable File
314 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
source script/lib/blob-store.sh
|
|
|
|
build_flag="--release"
|
|
target_dir="release"
|
|
open_result=false
|
|
local_install=false
|
|
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() {
|
|
echo "
|
|
Usage: ${0##*/} [options] [architecture=host]
|
|
Build the application bundle for macOS.
|
|
|
|
Options:
|
|
-d Compile in debug mode
|
|
-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 'dloih' flag
|
|
do
|
|
case "${flag}" in
|
|
o) open_result=true;;
|
|
d)
|
|
export CARGO_INCREMENTAL=true
|
|
export CARGO_BUNDLE_SKIP_BUILD=true
|
|
build_flag="";
|
|
target_dir="debug"
|
|
;;
|
|
i) local_install=true;;
|
|
h)
|
|
help_info
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
shift $((OPTIND-1))
|
|
|
|
|
|
# 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)
|
|
target_triple=${host_line#*: }
|
|
if [[ $# -gt 0 && -n "$1" ]]; then
|
|
target_triple="$1"
|
|
fi
|
|
arch_suffix=""
|
|
|
|
if [[ "$target_triple" = "x86_64-apple-darwin" ]]; then
|
|
arch_suffix="x86_64"
|
|
elif [[ "$target_triple" = "aarch64-apple-darwin" ]]; then
|
|
arch_suffix="aarch64"
|
|
else
|
|
echo "Unsupported architecture $target_triple"
|
|
exit 1
|
|
fi
|
|
|
|
# Generate the licenses first, so they can be baked into the binaries
|
|
script/generate-licenses
|
|
|
|
rustup target add $target_triple
|
|
|
|
echo "Compiling zed binaries"
|
|
cargo build ${build_flag} --package zed --package cli --target $target_triple
|
|
# 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 $target_triple
|
|
|
|
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
|
|
|
|
app_path=$(cargo bundle ${build_flag} --target $target_triple --select-workspace-root | xargs)
|
|
|
|
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 sign_app_binaries() {
|
|
rm -rf "${app_path}/Contents/Frameworks"
|
|
mkdir -p "${app_path}/Contents/Frameworks"
|
|
|
|
echo "Downloading git binary"
|
|
download_git "${target_triple}" "${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"
|
|
|
|
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" ]]; 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 [ "$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
|
|
dmg_target_directory="target/${target_triple}/${target_dir}"
|
|
dmg_source_directory="${dmg_target_directory}/dmg"
|
|
dmg_file_path="${dmg_target_directory}/Zed-${arch_suffix}.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
|
|
}
|
|
|
|
function upload_debug_symbols() {
|
|
if [[ -n "${SENTRY_AUTH_TOKEN:-}" ]]; then
|
|
echo "Uploading zed debug symbols to sentry..."
|
|
exe_path="target/${target_triple}/release/Zed"
|
|
if ! dsymutil --flat "target/${target_triple}/${target_dir}/zed" 2> target/dsymutil.log; then
|
|
echo "dsymutil failed"
|
|
cat target/dsymutil.log
|
|
exit 1
|
|
fi
|
|
if ! dsymutil --flat "target/${target_triple}/${target_dir}/remote_server" 2> target/dsymutil.log; then
|
|
echo "dsymutil failed"
|
|
cat target/dsymutil.log
|
|
exit 1
|
|
fi
|
|
# 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/${target_triple}/${target_dir}/zed.dwarf" \
|
|
"target/${target_triple}/${target_dir}/remote_server.dwarf"
|
|
else
|
|
echo "missing SENTRY_AUTH_TOKEN. skipping sentry upload."
|
|
fi
|
|
}
|
|
|
|
upload_debug_symbols
|
|
|
|
cp target/${target_triple}/${target_dir}/zed "${app_path}/Contents/MacOS/zed"
|
|
cp target/${target_triple}/${target_dir}/cli "${app_path}/Contents/MacOS/cli"
|
|
sign_app_binaries
|
|
|
|
sign_binary "target/$target_triple/release/remote_server"
|
|
gzip -f --stdout --best target/$target_triple/release/remote_server > target/zed-remote-server-macos-$arch_suffix.gz
|