Last active
January 21, 2024 02:58
-
-
Save ianfoo/32f78b615d35bf581d4709f514409554 to your computer and use it in GitHub Desktop.
Install/switch version of Go on a Linux host
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env bash | |
# | |
# This script downloads and installs Go from http://go.dev. If no version is | |
# provided, it will install the latest released version as shown by | |
# https://go.dev/VERSION. If there is already a Go installed, the script will | |
# replace that installation with the new one (though it will not delete the old | |
# installation). If a directory exists in BASE_DIR indicating that the | |
# requested version is already present, the download will be skipped. | |
# | |
# Requirements: curl, GNU stow | |
# | |
# Assumptions | |
# =========== | |
# Go is (or will be) installed in a protected directory that requires sudo to | |
# write. Specifically, /usr/local. The actual directory can be changed easily, | |
# by changing the variable, but the sudo'd commands are interspersed. It would | |
# be possible to conditionally execute the commands with sudo by determining | |
# whether the current user had write privileges in BASE_DIR, but that's beyond | |
# the scope of this little script. | |
# | |
# CHANGELOG | |
# ========= | |
# 20-Jan-2024 | |
# * Update latest_released_go_version to restrict output to one line, | |
# since this page now includes a second line with the time of the | |
# release. | |
set -eEuo pipefail | |
PREFIX="/usr/local" | |
BASE_DIR="$PREFIX/go" | |
WORK_DIR="" | |
FILE_SUFFIX="linux-amd64.tar.gz" | |
latest_released_go_version () { | |
echo "$(curl -sL 'https://go.dev/VERSION?m=text')" | head -n 1 | |
} | |
go_version_from_filename () { | |
echo $1 | sed -E "s|${WORK_DIR}/(.+)\.${FILE_SUFFIX}|\1|" | |
} | |
download_latest_go_distribution () { | |
local latest_go_version=$1 | |
local download_filename="${latest_go_version}.${FILE_SUFFIX}" | |
local download_url="https://go.dev/dl/${download_filename}" | |
curl -LsO --output-dir "$WORK_DIR" "$download_url" | |
echo "$WORK_DIR/$download_filename" | |
} | |
unpack_and_move_distribution () { | |
local distribution_file=$1 | |
local downloaded_version=$(go_version_from_filename "$distribution_file") | |
local installed_directory="${BASE_DIR}/${downloaded_version}" | |
# Unpack the archive in WORK_DIR, next to the archive file. | |
tar xzf "$distribution_file" -C "$WORK_DIR" | |
# Untarring produces a "go" directory, so we need to account for that | |
# when relocating the unpacked Go distribution. | |
sudo mv "$WORK_DIR/go" "$installed_directory" | |
} | |
get_currently_installed_go_version () { | |
local go_executable="$PREFIX/bin/go" | |
if [[ -f $go_executable ]]; then | |
stat -c%N $go_executable | awk -F '->' '{ print $2 }' | awk -F/ '{ print $3 }' | |
fi | |
} | |
remove_current_go_installation () { | |
local current_version="$1" | |
if [[ -z $current_version ]]; then | |
return 1 | |
fi | |
cd "$BASE_DIR" | |
if [[ ! -d "$current_version" ]]; then | |
echo >&2 "No Go installation found at $BASE_DIR/$current_version: skipping stow deletion" | |
return 1 | |
fi | |
sudo stow -D "$current_version" | |
} | |
install_new_go_version () { | |
local new_version=$1 | |
cd "$BASE_DIR" | |
if [[ ! -d "$new_version" ]]; then | |
echo >&2 "error: expected new go version unpacked at $BASE_DIR/$new_version" | |
return 1 | |
fi | |
sudo stow "$new_version" | |
} | |
cleanup () { | |
if [[ -d "$WORK_DIR" ]]; then | |
rm -rf "$WORK_DIR" | |
fi | |
} | |
main () { | |
sudo mkdir -p "$BASE_DIR" | |
trap cleanup EXIT | |
local requested_version=$1 | |
if [[ -z $requested_version ]]; then | |
# User has not requested a particular version, so get the latest. | |
requested_version="$(latest_released_go_version)" | |
echo "Latest version is $requested_version" | |
elif [[ ! $requested_version =~ "^go" ]]; then | |
# Ensure version is in "goN.NN" format. | |
requested_version="go${requested_version}" | |
fi | |
local current_version="$(get_currently_installed_go_version)" | |
if [[ $requested_version == $current_version ]]; then | |
echo >&2 "Version $requested_version is already the currently installed version" | |
return 1 | |
fi | |
if [[ ! -d "$BASE_DIR/$requested_version" ]]; then | |
WORK_DIR="$(mktemp --tmpdir -d golang-get.XXXX)" | |
echo "Downloading $requested_version to $WORK_DIR" | |
local downloaded_file="$(download_latest_go_distribution $requested_version)" | |
unpack_and_move_distribution "$downloaded_file" | |
fi | |
remove_current_go_installation "$current_version" && echo "Deactivated $current_version" | |
install_new_go_version "$requested_version" && echo "Installed $requested_version" | |
} | |
main "${1:-}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment