#!/bin/bash # Find all the directories we might need (based on # heroku-buildpack-nodejs code). BUILD_DIR=${1:-} CACHE_DIR=${2:-} ENV_DIR=${3:-} BP_DIR=$(cd $(dirname ${0:-}); cd ..; pwd) # Export DATABASE_URL at build time, mostly because Diesel is the best way to # do SQL in Rust right now, and Diesel will use it to generate code for the # database schema. if [ -e "$ENV_DIR/DATABASE_URL" ]; then export DATABASE_URL="$(cat $ENV_DIR/DATABASE_URL)"; fi # Set defaults for our configuration variables. Stable Rust is sufficiently # stable at this point that I think we can just default it. VERSION=stable # Set this to "1" in `RustConfig` to just install a Rust toolchain and not # build `Cargo.toml`. This is useful if you have a project written in Ruby # or Node (for example) that needs to build extension modules using Rust. RUST_SKIP_BUILD=0 # If your Rust code is not at the root directory of the repository, specify a # `BUILD_PATH` to the correct directory in the `RustConfig` BUILD_PATH="" # Set this to "1" in `RustConfig` to install diesel at build time and copy it # into the target directory, next to your app binary. This makes it easy to # run migrations by adding a release step to your Procfile: # `release: ./target/release/diesel migration run` RUST_INSTALL_DIESEL=0 # These flags are passed to `cargo install diesel`, e.g. '--no-default-features --features postgres' DIESEL_FLAGS="" # Default build flags to pass to `cargo build`. RUST_CARGO_BUILD_FLAGS="--release" # Load our toolchain configuration, if any was specified. if [ -f "$BUILD_DIR/rust-toolchain" ]; then VERSION="$(cat "$BUILD_DIR/rust-toolchain")" fi # Load our configuration variables, if any were specified. if [ -f "$BUILD_DIR/RustConfig" ]; then . "$BUILD_DIR/RustConfig" fi # Standard paranoia. set -eu # Check our configuration options. if [ -z ${VERSION+x} ]; then >&2 echo "failed: must set VERSION with rust-toolchain or RustConfig to indicate the Rust version." exit 1 fi # Notify users running old, unstable versions of Rust about how to deploy # successfully. if [ $RUST_SKIP_BUILD -ne 1 ] && ( [ ! -z ${CARGO_URL+x} ] || [ ! -f "$BUILD_DIR/$BUILD_PATH/Cargo.toml" ] ); then >&2 cat <&2 cat < $BP_DIR/export # Our rustup installation. export RUSTUP_HOME="$CACHE_DIR/multirust" # Our cargo installation. We implicitly trust Rustup and Cargo # to do the right thing when new versions are released. export CARGO_HOME="$CACHE_DIR/cargo" # Include binaries installed by cargo and rustup in our path. PATH="\$CARGO_HOME/bin:\$PATH" EOF # Read our build environment back in and evaluate it so that we can use it. . $BP_DIR/export # Switch to our cache directory. mkdir -p "$CACHE_DIR" cd "$CACHE_DIR" # Make sure we have an appropriate Rust toolchain installed. if [ -d "$CARGO_HOME" ]; then echo "-----> Checking for new releases of Rust $VERSION channel" # It's possible that $VERSION has changed, or the `stable` channel has updated. rustup self update rustup update "$VERSION" rustup default "$VERSION" else echo "-----> Downloading rustup" curl https://sh.rustup.rs -sSf > rustup.sh chmod u+x rustup.sh echo "-----> Using rustup to install Rust channel $VERSION" ./rustup.sh -y --default-toolchain "$VERSION" rm rustup.sh fi if [ ! -x "$CARGO_HOME/bin/rustc" ]; then echo "failed: Cannot find Rust binaries at $CARGO_HOME" exit 1 fi # This is where we will cache our Rust output. Note the suggestions at # https://github.com/alexcrichton/cargo/commit/014765f788ca1c2476936835ca32cc2746f99b42 # which describe how this needs to be named. export CARGO_TARGET_DIR="$CACHE_DIR/target" if [ $RUST_SKIP_BUILD -ne 1 ]; then # Build our project (into CARGO_TARGET_DIR so we have caching) and copy it # back to the source tree. In theory, we could probably just copy the # binary or do something clever with `cargo install`, but we haven't # figured that out yet. # # To debug git issues: #export RUST_LOG="cargo::sources::git=debug" # To debug compiler and linking issues, add `--verbose`. echo "-----> Building application using Cargo" cd "$BUILD_DIR/$BUILD_PATH" rm -rf target/ cargo build $RUST_CARGO_BUILD_FLAGS mkdir -p target/release find "$CARGO_TARGET_DIR/release" -maxdepth 1 -type f -executable -exec cp -a -t target/release {} \; else echo "-----> Skipping Cargo build" fi # Install diesel so we can use it for migrations if [ $RUST_INSTALL_DIESEL -eq 1 ]; then echo "-----> Installing diesel" cargo install diesel_cli $DIESEL_FLAGS || echo "already installed" cp $(which diesel) target/release/ fi