Skip to content

Instantly share code, notes, and snippets.

@comradequinn
Last active March 1, 2024 09:51
Show Gist options
  • Save comradequinn/45b9eef8bde320b6e474f65061b84f78 to your computer and use it in GitHub Desktop.
Save comradequinn/45b9eef8bde320b6e474f65061b84f78 to your computer and use it in GitHub Desktop.
Script to Switch Between Active Versions of Go
#! /bin/bash
go_dir="/usr/local/go"
version=${1}
version_dir="#unset#"
dl_url="#unset#"
gos_dir="/usr/local/gos"
tar_file=".temp-go.tar.gz"
temp_dir=".temp"
arch=linux-amd64
function fatal_error() {
printf "$(tput setaf 1)ERROR: $1$(tput sgr 0)\n"
exit 1
}
function success_msg() {
printf "$(tput setaf 2)$1$(tput setaf 7)\n\n"
}
function info_msg() {
printf "$(tput setaf 4)$1$(tput setaf 7)\n"
}
function alert_msg() {
printf "$(tput setaf 3)$1$(tput setaf 7)\n"
}
function init() {
if [ ! -d "$gos_dir" ]; then
info_msg "creating go version directory at $gos_dir"
sudo mkdir $gos_dir
if [ $? -gt 0 ]; then
fatal_error "unable to create required directory structure"
fi
fi
}
function read_required_version() {
if [ -z $version ]; then
alert_msg 'select a locally available version or specify one to download:'
local_versions=(`ls -l $gos_dir | awk 'NR > 1 { print $9 }' | sed 's/go_//g' | sed 's/_/\./g'`)
specify_opt="specify"
select version in "${local_versions[@]}" "${specify_opt}"; do
case $version in *) break;;
esac
done
if [ "$version" = "${specify_opt}" ]; then
read -p "enter version:" version
fi
if [ -z $version ]; then
fatal_error "a valid version is required"
fi
fi
version_dir="go_`echo $version | sed "s/\./_/g"`"
dl_url="https://golang.org/dl/go$version.${arch}.tar.gz"
}
function get_required_version() {
if [ ! -d "$gos_dir/$version_dir" ]; then
info_msg "version $version of go not found locally. downloading from $dl_url ..."
sudo rm -rf $tar_file $temp_dir 2> /dev/null
sudo mkdir ./$temp_dir
sudo wget -q -O $tar_file $dl_url
if [ "$?" -gt 0 ]; then
fatal_error "error downloading version $version of go from $dl_url"
fi
info_msg "download successful. extracting version $version of go to $gos_dir/$version_dir ..."
sudo tar -C $temp_dir -xzf $tar_file
sudo mv $temp_dir/go $gos_dir/$version_dir
sudo rm -rf $tar_file $temp_dir
info_msg "extraction successful"
fi
}
function activate_required_version() {
sudo rm -rf $go_dir 2> /dev/null
sudo ln -s $gos_dir/$version_dir $go_dir
}
init
read_required_version
alert_msg "activating version $version of go...."
get_required_version
info_msg "version $version of go available locally"
activate_required_version
success_msg "go version $version now active"
@comradequinn
Copy link
Author

comradequinn commented Dec 24, 2021

Summary

goto enables quick and stable switching of the currently active version of Go on a Linux or Mac system to any specified version.

It will download the specified version from the official Go site and set it is as the active version on the host system. A local cache of previously downloaded versions is maintained allowing such versions to be activated and deactivated rapidly.

Usage

The below examples assume that goto is installed as per the instructions in the next section. Where that is not the case, replace goto with the name of the local script file, typically ./goto.sh

Activate a Specific Version (non-interactive)

The exact version required can be passed as an argument to the script:

goto 1.20.2

This form is particularly useful in scripts. For example, the below shows how to run Go commands against multiple versions of Go, one of which (1.19.7) was already available in the cache and one (1.20.2) which was not initially, but then subsequently is.

The Go command in question here is simply go version, but it illustrates the point:

$ goto 1.20.2
activating version 1.20.2 of go....
version 1.20.2of go not found locally. downloading from https://golang.org/dl/go1.20.2.linux-amd64.tar.gz ...
download successful. extracting version 1.20.2 of go to /usr/local/gos/go_1_20_2 ...
extraction successful
version 1.20.2 of go available locally
go version 1.20.2 now active

$ go version 
go version go1.20.2 linux/amd64

$ goto 1.19.7
activating version 1.19.7 of go....
version 1.19.7 of go available locally
go version 1.19.7 now active

$ go version 
go version go1.19.7 linux/amd64

$ goto 1.20.2
activating version 1.20.2 of go....
version 1.20.2 of go available locally
go version 1.20.2 now active

$ go version 
go version go1.20.2 linux/amd64

Select or Specify a Version

For ease of use, a version can be selected for activation from the cache, rather than entering it manually:

$ goto

This will return a list of cached versions, or an option to specify a specific one if it transpires the required version isn't actually in the cache. Example output is shown below:

select a locally available version or specify one to download:
1) 1.16.3
2) 1.17.1
3) 1.18.1
4) 1.19.4
5) 1.20.2
6) specify
#? 

Enter the number that corresponds to the required version if it is shown or, alternatively, enter the number that corresponds to specify and then enter the desired version number manually when prompted, as shown below.

$ enter version:
1.20.2

Once the version has been entered, or specified, it will be downloaded, if required, and activated. This will be confirmed with output similar to the below

activating version 1.20.2 of go....
version 1.20.2 of go available locally
go version 1.20.2 now active

Installation

goto can be kept as an adhoc script or installed for continued use. To install. run the below in the directory that the script exists

rm -rf goto.sh 2> /dev/null; \
wget "https://gist.githubusercontent.com/comradequinn/45b9eef8bde320b6e474f65061b84f78/raw/f6ee30f669c519c7c562c199d797f23b6d7c847f/goto.sh" && \
sudo cp goto.sh /usr/local/bin/goto && \
rm -f goto.sh && \
sudo chmod +x /usr/local/bin/goto && \
echo "goto installed"

Mac users should then execute one of the below after the installation to adjust the target architecture as required:

sudo sed -i'.bak' "s/arch\=linux-amd64/arch\=darwin-arm64/g" /usr/local/bin/goto && rm -f /usr/local/bin/goto.bak 2> /dev/null # apple silicon 
sudo sed -i'.bak' "s/arch\=linux-amd64/arch\=darwin-amd64/g" /usr/local/bin/goto && rm -f /usr/local/bin/goto.bak 2> /dev/null # apple on intel 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment