bundle

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