Last active
August 20, 2022 18:41
-
-
Save antichris/533db4a904156a21f73cfab7327503e1 to your computer and use it in GitHub Desktop.
A script to update an executable that has been installed to GOBIN with "go install"
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
#!/bin/sh -e | |
## This Source Code Form is subject to the terms of the Mozilla Public | |
## License, v. 2.0. If a copy of the MPL was not distributed with this | |
## file, You can obtain one at https://mozilla.org/MPL/2.0/. | |
self=$(basename "$0") | |
usage=$(cat) <<*** | |
Usage: $self [OPTIONS] COMMAND [VERSION] | |
Update an executable that has been installed to GOBIN with "go install". | |
The executable must have been compiled in module-aware mode. | |
-n make no changes, only display current version | |
--help display this help and exit | |
COMMAND is the file base name (without the GOBIN path) of the targetted | |
executable in the GOBIN directory, i.e. the name one would type to run | |
the command when GOBIN is in PATH. | |
Optional VERSION can be specified to install that specific version of | |
the COMMAND instead of the latest. | |
Example: | |
$self wire v0.5.0 | |
*** | |
main() { | |
noop= | |
parseOpts "$@" | |
shift $((OPTIND - 1)) | |
[ "$1" ] || die 1 'COMMAND argument required' | |
: "${GOBIN:=${GOPATH:-$HOME/go}/bin}" | |
export GOBIN="$GOBIN" | |
version=${2:-latest} | |
ex=$GOBIN/$(basename "$1") | |
[ -e "$ex" ] || die 2 '%s not found in GOBIN' "$1" | |
v=$(getVer "$ex") | |
p=$(extractPath "$v") | |
if [ ! "$noop" ]; then | |
go install "${p}@${version}" | |
m=$(extractMod "$v") | |
goV="$(extractGoVer "$ex" "$v")" | |
printCmdV was "$p" "$m" "$goV" | |
v=$(getVer "$ex") | |
p=$(extractPath "$v") | |
fi | |
m=$(extractMod "$v") | |
goV="$(extractGoVer "$ex" "$v")" | |
printCmdV now "$p" "$m" "$goV" | |
} | |
parseOpts() { ## ($@) | |
while getopts :-:n OPT "$@"; do | |
case $OPT in | |
n) noop=1 ;; | |
-) case "$OPTARG" in | |
help) die ;; | |
*) die 1 'unrecognized option: --%s' "$OPTARG" ;; | |
esac ;; | |
?) die 1 'unrecognized short option: -%s' "$OPTARG" ;; | |
esac | |
done | |
} | |
die() { ## (code [msgFormat [msgParams...]]) | |
c=${1:-0} | |
if [ "$2" ]; then | |
f=$2\\n | |
shift 2 | |
eprintf "$f" "$@" | |
fi | |
printf %s\\n "$usage" | |
exit "$c" | |
} | |
getVer() { ## (executablePath) | |
ex=$1 c="go version -m" v=$($c "$ex") | |
[ "$v" ] || exit 2 | |
if [ "${v##"$ex: go"*}" ]; then | |
eprintf 'unrecognized output from "%s"' "$c" | |
return 3 | |
fi | |
printf %s "$v" | |
} | |
extractGoVer() { ## (executablePath goVersionOutput) | |
extract 'Go compiler version' "${2#"$1"}" ': (go\S+)' '\1' | |
} | |
extractPath() { ## (goVersionOutput) | |
subExtract 'command path' "$1" path || return 4 | |
} | |
extractMod() { ## (goVersionOutput) | |
subExtract 'version info' "$1" mod '\s+(\S+)\s+.*' '@\2' || return 5 | |
} | |
printCmdV() { ## (prefix cmdPath module@version goVersion) | |
printf '%s:\t%s@%s\t%s\n' "$1" "$2" "${3#*@}" "$4" | |
} | |
subExtract() { ## (desc data prefix [patternSuffix [substitutionSuffix]]) | |
extract "$1" "$2" '[\t ]+'"$3"'\s+(\S+)'"$4" '\1'"$5" | |
} | |
extract() ( ## (desc data pattern substitution) | |
v=$(printf %s "$2" | sed -E "s/^$3$/$4/;t;d") | |
if [ ! "$v" ]; then | |
eprintf 'failed extracting %s from the "go version -m" output:\n%s\n' \ | |
"$1" "$2" | |
return 1 | |
fi | |
printf %s "$v" | |
) | |
eprintf() { ## (format [parameters...]) | |
f="$self: $1" | |
shift | |
# shellcheck disable=SC2059 | |
printf "$f" "$@" >&2 | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment