bundle

  1#!/bin/bash
  2
  3set -e
  4
  5build_flag="--release"
  6target_dir="release"
  7open_result=false
  8local_only=false
  9overwrite_local_app=false
 10bundle_name=""
 11
 12# Function for displaying help info
 13help_info() {
 14  echo "
 15Usage: ${0##*/} [options] [bundle_name]
 16Build the application bundle.
 17
 18Options:
 19  -d    Compile in debug mode and print the app bundle's path.
 20  -l    Compile for local architecture only and copy bundle to /Applications.
 21  -o    Open the resulting DMG or the app itself in local mode.
 22  -f    Overwrite the local app bundle if it exists.
 23  -h    Display this help and exit.
 24  "
 25}
 26
 27# If -o option is specified, the folder of the resulting dmg will be opened in finder
 28# If -d is specified, Zed will be compiled in debug mode and the application's path printed
 29# If -od or -do is specified Zed will be bundled in debug and the application will be run.
 30while getopts 'dlfoh' flag
 31do
 32    case "${flag}" in
 33        o) open_result=true;;
 34        d)
 35            build_flag="";
 36            target_dir="debug"
 37            ;;
 38        l) local_only=true;;
 39        f) overwrite_local_app=true;;
 40        h)
 41           help_info
 42           exit 0
 43           ;;
 44    esac
 45done
 46
 47shift $((OPTIND-1))
 48
 49if [ "$1" ]; then
 50    bundle_name=$1
 51fi
 52
 53export ZED_BUNDLE=true
 54export MACOSX_DEPLOYMENT_TARGET=10.15.7
 55
 56cargo_bundle_version=$(cargo -q bundle --help 2>&1 | head -n 1 || echo "")
 57if [ "$cargo_bundle_version" != "cargo-bundle v0.6.0-zed" ]; then
 58    cargo install cargo-bundle --git https://github.com/zed-industries/cargo-bundle.git --branch zed-deploy
 59fi
 60
 61rustup target add wasm32-wasi
 62
 63# Deal with versions of macOS that don't include libstdc++ headers
 64export CXXFLAGS="-stdlib=libc++"
 65
 66version_info=$(rustc --version --verbose)
 67host_line=$(echo "$version_info" | grep host)
 68local_target_triple=${host_line#*: }
 69
 70if [ "$local_only" = true ]; then
 71    echo "Building for local target only."
 72    cargo build ${build_flag} --package zed
 73    cargo build ${build_flag} --package cli
 74else
 75    echo "Compiling zed binary for aarch64-apple-darwin"
 76    cargo build ${build_flag} --package zed --target aarch64-apple-darwin
 77    echo "Compiling zed binary for x86_64-apple-darwin"
 78    cargo build ${build_flag} --package zed --target x86_64-apple-darwin
 79    echo "Compiling cli binary for aarch64-apple-darwin"
 80    cargo build ${build_flag} --package cli --target aarch64-apple-darwin
 81    echo "Compiling cli binary for x86_64-apple-darwin"
 82    cargo build ${build_flag} --package cli --target x86_64-apple-darwin
 83fi
 84
 85echo "Creating application bundle"
 86pushd crates/zed
 87channel=$(<RELEASE_CHANNEL)
 88cp Cargo.toml Cargo.toml.backup
 89sed \
 90    -i .backup \
 91    "s/package.metadata.bundle-${channel}/package.metadata.bundle/" \
 92    Cargo.toml
 93
 94if [ "$local_only" = true ]; then
 95    app_path=$(cargo bundle ${build_flag} --select-workspace-root | xargs)
 96else
 97    app_path=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs)
 98fi
 99
100mv Cargo.toml.backup Cargo.toml
101popd
102echo "Bundled ${app_path}"
103
104if [ "$local_only" = false ]; then
105    echo "Creating fat binaries"
106    lipo \
107        -create \
108        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/Zed \
109        -output \
110        "${app_path}/Contents/MacOS/zed"
111    lipo \
112        -create \
113        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/cli \
114        -output \
115        "${app_path}/Contents/MacOS/cli"
116fi
117
118echo "Copying WebRTC.framework into the frameworks folder"
119mkdir "${app_path}/Contents/Frameworks"
120cp -R target/${local_target_triple}/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/"
121
122if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
123    echo "Signing bundle with Apple-issued certificate"
124    security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo ""
125    security default-keychain -s zed.keychain
126    security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
127    echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12
128    security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
129    rm /tmp/zed-certificate.p12
130    security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
131    /usr/bin/codesign --force --deep --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v
132    security default-keychain -s login.keychain
133else
134    echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_USERNAME, APPLE_NOTARIZATION_PASSWORD"
135    echo "Performing an ad-hoc signature, but this bundle should not be distributed"
136    codesign --force --deep --entitlements crates/zed/resources/zed.entitlements --sign - "${app_path}" -v
137fi
138
139if [ "$target_dir" = "debug" ]; then
140    if [ "$open_result" = true ]; then
141        open "$app_path"
142    else
143        echo "Created application bundle:"
144        echo "$app_path"
145    fi
146    exit 0
147fi
148
149if [ "$local_only" = true ]; then
150    # If bundle_name is not set or empty, use the basename of $app_path
151    if [ -z "$bundle_name" ]; then
152        bundle_name=$(basename "$app_path")
153    else
154        # If bundle_name doesn't end in .app, append it
155        if [[ "$bundle_name" != *.app ]]; then
156            bundle_name="$bundle_name.app"
157        fi
158    fi
159
160    if [ "$overwrite_local_app" = true ]; then
161        rm -rf "/Applications/$bundle_name"
162    fi
163    mv "$app_path" "/Applications/$bundle_name"
164
165    if [ "$open_result" = true ]; then
166        open "/Applications/$bundle_name"
167    else
168        echo "Installed application bundle:"
169        echo "/Applications/$bundle_name"
170    fi
171else
172    echo "Creating DMG"
173    dmg_target_directory="target/${target_dir}"
174    dmg_source_directory="${dmg_target_directory}/dmg"
175    dmg_file_path="${dmg_target_directory}/Zed.dmg"
176
177    rm -rf ${dmg_source_directory}
178    mkdir -p ${dmg_source_directory}
179    mv "${app_path}" "${dmg_source_directory}"
180
181    ln -s /Applications ${dmg_source_directory}
182    hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}"
183    # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`.
184    # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now.
185    rm ${dmg_source_directory}/Applications
186
187    echo "Adding license agreement to DMG"
188    npm install --global dmg-license minimist
189    dmg-license script/eula/eula.json "${dmg_file_path}"
190
191    if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
192        echo "Notarizing DMG with Apple"
193        npm install -g notarize-cli
194        npx notarize-cli --file "${dmg_file_path}" --bundle-id dev.zed.Zed --username "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD"
195    fi
196
197    if [ "$open_result" = true ]; then
198        open $dmg_target_directory
199    fi
200fi