From 2a195ae35afd54600f9cb3e26821800c6c7f9524 Mon Sep 17 00:00:00 2001 From: Jonah Kruschke Date: Mon, 3 Aug 2020 22:51:02 -0400 Subject: [PATCH] chore(installation): Refactor installation script - Run "install.sh" through `shellcheck` and implement the suggested changes, bar one regarding the use of `ls`. - Ensure the `git clone ...` operation is successful before continuing. - Add more descriptive comments. - Refactor and simplify code. --- install.sh | 253 +++++++++++++++++++++-------------------------------- 1 file changed, 101 insertions(+), 152 deletions(-) diff --git a/install.sh b/install.sh index f3b3f33d..dbab72fe 100755 --- a/install.sh +++ b/install.sh @@ -1,184 +1,133 @@ #!/usr/bin/env bash -set -euo pipefail -echo "Let's get you set up with Rustlings!" - -echo "Checking requirements..." -if [ -x "$(command -v git)" ] -then - echo "SUCCESS: Git is installed" -else - echo "ERROR: Git does not seem to be installed." - echo "Please download Git using your package manager or over https://git-scm.com/!" - exit 1 -fi - -if [ -x "$(command -v cc)" ] -then - echo "SUCCESS: cc is installed" -else - echo "ERROR: cc does not seem to be installed." - echo "Please download (g)cc using your package manager." - echo "OSX: xcode-select --install" - echo "Deb: sudo apt install gcc" - echo "Yum: sudo yum -y install gcc" - exit 1 -fi - -if [ -x "$(command -v rustup)" ] -then - echo "SUCCESS: rustup is installed" -else - echo "ERROR: rustup does not seem to be installed." - echo "Please download rustup using https://rustup.rs!" - exit 1 -fi - -if [ -x "$(command -v rustc)" ] -then - echo "SUCCESS: Rust is installed" -else - echo "ERROR: Rust does not seem to be installed." - echo "Please download Rust using rustup!" - exit 1 -fi - -if [ -x "$(command -v cargo)" ] -then - echo "SUCCESS: Cargo is installed" -else - echo "ERROR: Cargo does not seem to be installed." - echo "Please download Rust and Cargo using rustup!" - exit 1 -fi - -# Look up python installations, starting with 3 with a fallback of 2 -if [ -x "$(command -v python3)" ] -then - PY="$(command -v python3)" -elif [ -x "$(command -v python)" ] -then - PY="$(command -v python)" -elif [ -x "$(command -v python2)" ] -then - PY="$(command -v python2)" -else - echo "ERROR: No working python installation was found" - echo "Please install python and add it to the PATH variable" - exit 1 -fi - -# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0). -# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2. -function vercomp() { - if [[ $1 == $2 ]] - then - return 0 - fi - v1=( ${1//./ } ) - v2=( ${2//./ } ) - len1=${#v1[@]} - len2=${#v2[@]} - max_len=$len1 - if [[ $max_len -lt $len2 ]] - then - max_len=$len2 - fi - - #pad right in short arr - if [[ len1 -gt len2 ]]; - then - for ((i = len2; i < len1; i++)); - do - v2[$i]=0 - done - else - for ((i = len1; i < len2; i++)); - do - v1[$i]=0 - done - fi - - for i in `seq 0 $max_len` +# Compare two version strings, v1 and v2, passed as arguments (e.g 1.31 and +# 1.33.0). Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2. +compare_versions() { + [ "$1" == "$2" ] && return 0 + declare -a v1=() v2=() + mapfile -d . -t v1 < <(echo "$1") + mapfile -d . -t v2 < <(echo "$2") + declare -ir max_len=$(( ${#v1[@]} > ${#v2[@]} ? ${#v1[@]} : ${#v2[@]} )) + for i in $(seq 0 "$max_len") do - # Fill empty fields with zeros in v1 - if [ -z "${v1[$i]}" ] - then - v1[$i]=0 - fi - # And in v2 - if [ -z "${v2[$i]}" ] - then - v2[$i]=0 - fi - if [ ${v1[$i]} -gt ${v2[$i]} ] - then - return 1 - fi - if [ ${v1[$i]} -lt ${v2[$i]} ] - then - return 2 - fi + # Fill empty fields with zeros. + [ -z "${v1[$i]}" ] && v1["$i"]=0 + [ -z "${v2[$i]}" ] && v2["$i"]=0 + # Compare the fields. + [ ${v1[$i]} -gt ${v2[$i]} ] && return 1 + [ ${v1[$i]} -lt ${v2[$i]} ] && return 2 done return 0 } -RustVersion=$(rustc --version | cut -d " " -f 2) -MinRustVersion=1.56 -vercomp "$RustVersion" $MinRustVersion || ec=$? -if [ ${ec:-0} -eq 2 ] +# Return 0 if the argument represents a valid command on the machine, 1 +# otherwise. +verify_dependency() { + declare -r package="$1" + if [ -x "$(command -v "$package")" ] + then + echo "SUCCESS: \`$package\` is installed." + return 0 + else + echo "ERROR: \`$package\` does not seem to be installed." >&2 + return 1 + fi +} + +# Main logic begins here +declare Clippy Py RustVersion Version +declare -r CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin" + +echo "Let's get you set up with Rustlings!" + +# Verify that the required dependencies are installed. +echo "Checking requirements..." +for dependency in cargo cc curl git rustc +do + verify_dependency "$dependency" || exit 1 +done +# Search for a Python installation; start with 3 and fallback to 2 if required. +if [ -x "$(command -v python3)" ] then - echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion" - echo "Please update Rust with 'rustup update'" + Py="$(command -v python3)" +elif [ -x "$(command -v python)" ] +then + Py="$(command -v python)" +elif [ -x "$(command -v python2)" ] +then + Py="$(command -v python2)" +else + echo "ERROR: no working Python installation was found." >&2 + echo "Please install Python and add it to the PATH variable." >&2 + exit 1 +fi + +# Ensure the installed Rust compiler is sufficiently up-to-date. +RustVersion=$(rustc --version | cut -d " " -f 2) +compare_versions "$RustVersion" "$MinRustVersion" +if [ $? -eq 2 ] +then + echo "ERROR: Rust $RustVersion is too old; the minimum version is" \ + "$MinRustVersion." >&2 + echo "Please update Rust with \`rustup update\`." >&2 exit 1 else - echo "SUCCESS: Rust is up to date" + echo "SUCCESS: Rust is up to date." fi -Path=${1:-rustlings/} -echo "Cloning Rustlings at $Path..." -git clone -q https://github.com/rust-lang/rustlings "$Path" - -cd "$Path" - -Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | ${PY} -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);") -CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin" - -if [[ -z ${Version} ]] +# Clone the Git repository. +echo "Cloning Rustlings into '$Path'..." +if git clone -q "https://github.com/rust-lang/rustlings" "$Path" then - echo "The latest tag version could not be fetched remotely." - echo "Using the local git repository..." - Version=$(ls -tr .git/refs/tags/ | tail -1) - if [[ -z ${Version} ]] + cd "$Path" || exit 1 +else + echo "ERROR: failed to clone the Git repository into '$Path'." >&2 + exit 1 +fi + +# Determine which version of Rustlings to install from the Git repository. +Version=$( + curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest \ + | "$Py" -c \ + "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name'])" +) +if [ -z "$Version" ] +then + echo "The latest tag version could not be fetched remotely, using the" \ + "local Git repository..." + Version=$(ls -t .git/refs/tags/ | head --lines=1) + if [ -z "$Version" ] then - echo "No valid tag version found" - echo "Rustlings will be installed using the main branch" + echo "No valid tag version was found; Rustlings will be installed" \ + "from the main Git branch." Version="main" else - Version="tags/${Version}" + Version="tags/$Version" fi else - Version="tags/${Version}" + Version="tags/$Version" fi +# Install the selected version of Rustlings. echo "Checking out version $Version..." -git checkout -q ${Version} - -echo "Installing the 'rustlings' executable..." +git checkout -q "$Version" +echo "Installing the \`rustlings\` executable..." cargo install --force --path . +# Verify that the Rustlings installation was successful. if ! [ -x "$(command -v rustlings)" ] then - echo "WARNING: Please check that you have '$CargoBin' in your PATH environment variable!" + echo "WARNING: Please ensure '$CargoBin' is in your PATH environment" \ + "variable!" fi -# Checking whether Clippy is installed. -# Due to a bug in Cargo, this must be done with Rustup: https://github.com/rust-lang/rustup/issues/1514 -Clippy=$(rustup component list | grep "clippy" | grep "installed") +# Ensure Clippy is installed (due to a bug in Cargo, this must be done with +# Rustup: https://github.com/rust-lang/rustup/issues/1514). +Clippy=$(rustup component list | grep 'clippy.*(installed)') if [ -z "$Clippy" ] then - echo "Installing the 'cargo-clippy' executable..." + echo "Installing the \`cargo-clippy\` executable..." rustup component add clippy fi -echo "All done! Run 'rustlings' to get started." +echo "All done! Run \`rustlings\` to get started."