I’m not a fan of rustup and I’ve been always using the installation scripts in official packages.

However, things have become troublesome since I started cross-compilation. Rust have provided their pre-compiled standard libraries in Rust Archives which saved me plenty of time. However each time a new version is released, I have to manually download and install a number of packages and I went through a lot of pain.

So finally I decided to write an updating script for Rust. It is capable of handling rustc, libraries as well as the source code (by detecting environment variable). I deem that it could work on most Linux distros. You will need aria2c as the downloader and of course you can change it easily.

#!/bin/bash
HOST="x86_64-unknown-linux-gnu"
VERSION=$1

# check rustc
RUSTC=$(type -p rustc)
if [[ $? -ne 0 ]]; then
    echo "ERROR: rustc not found"
    exit 1
fi
RUSTLIB=$(dirname $(dirname $(type -p rustc)))"/lib/rustlib"

# check temp directory
TMP="/tmp/rustc"
mkdir -p $TMP
if [[ $? -ne 0 ]]; then
    echo "ERROR: Cannot create temp directory: $TMP"
    exit 1
fi

# check aria2c
type -p aria2c > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
    echo "ERROR: aria2c not found, please install it first"
    exit 1
fi

# default stable
if [[ -z $VERSION ]]; then
    echo "WARN : Version not specified, falling back to stable"
    VERSION="stable"
fi

if [[ $VERSION == "stable" ]]; then
    VERSION=$(curl https://static.rust-lang.org/dist/channel-rust-$VERSION 2>/dev/null | head -n 1 | sed -r "s/^rust-([0-9\.]+).*/\1/")
fi

printf "INFO : Installing Rust v%b, continue? [y/n] " "$VERSION"
read PROMPT
if [[ $PROMPT != "y" && $PROMPT != "Y" ]]; then
    exit 0
fi

sha256_file()
{
    echo $(sha256sum "$1" 2>/dev/null | sed -r "s/^([a-z0-9]+).*/\1/")
}

rust_download()
{
    local ARIA2C="aria2c -d $TMP -q "
    local FILE=$1
    local BASE="https://static.rust-lang.org/dist/"

    local DEST="$TMP/$FILE"
    local SHA=$(curl "$BASE""$FILE".sha256 2>/dev/null | sed -r "s/^([a-z0-9]+).*/\1/")

    if [[ -s $DEST && $(sha256_file $DEST) == "$SHA" ]]; then
        echo "INFO : $FILE already existed"
    else
        if [[ -e $DEST ]]; then
            rm $DEST
        fi
        $ARIA2C "$BASE""$FILE"
        local SHA_GOT=$(sha256_file $DEST)
        if [[ "$SHA_GOT" != "$SHA" ]]; then
            printf "ERROR: SHA256 mismatch: %b\n\tExpected: %b\n\tGot     : %b\n" "$DEST" "$SHA" "$SHA_GOT"
            return 1
        fi
    fi

    echo "INFO : Extracting $FILE"
    tar -xf "$DEST" -C "$TMP"
}

# check installed standard libraries
echo "INFO : Searching for installed Rust libraries in $RUSTLIB"
LIBLIST=$(ls $RUSTLIB | grep manifest-rust-std | sed -r "s/^manifest-rust-std-(.*)/\1/" | grep -v "$HOST")
if [[ -z $LIBLIST ]]; then
    echo "INFO : No libraries were found"
else
    for i in ${LIBLIST[@]}; do
        printf "\t%b\n" "${i}"
    done
fi

# check installed source files
if [[ -n "$RUST_SRC_PATH" ]]; then
    RUSTSRC=$(dirname $(dirname $RUST_SRC_PATH))
    echo "INFO : Source code found, installing to $RUSTSRC"
fi

# start downloading
set -e
echo "INFO : Downloading rustc"
FILE="rust-""$VERSION""-""$HOST"".tar.gz"
rust_download $FILE

if [[ -n "$RUST_SRC_PATH" ]]; then
    echo "INFO : Downloading source"
    FILE="rustc-""$VERSION""-src.tar.gz"
    rust_download $FILE
fi

if [[ -n $LIBLIST ]]; then
    echo "INFO : Downloading libraries"
    for i in ${LIBLIST[@]}; do
        echo "INFO : Downloading library for target: ${i}"
        FILE="rust-std-""$VERSION""-""${i}"".tar.gz"
        rust_download $FILE
    done
fi

# start installation
echo "WARN : Please input password if prompted"
# install rustc
echo "INFO : Installing rustc"
sudo "$TMP/rust-""$VERSION""-""$HOST""/install.sh"
# install source files
if [[ -n "$RUST_SRC_PATH" ]]; then
    echo "INFO : Copying source"
    NEWSRC="$RUSTSRC""/rustc-""$VERSION"
    cp "$TMP/rustc-""$VERSION" "$NEWSRC" -rf
    echo "INFO : The new soruce path is $NEWSRC/src"
fi
# install standard libraries
if [[ -n $LIBLIST ]]; then
    for i in ${LIBLIST[@]}; do
        echo "INFO : Installing library for target: ${i}"
        sudo "$TMP/rust-std-""$VERSION""-${i}/install.sh"
    done
fi

# finished
echo "INFO : ALL DONE!"
if [[ -n "$RUST_SRC_PATH" ]]; then
    echo "INFO : Don't forget to change RUST_SRC_PATH to $NEWSRC/src"
fi