Skip to content

Instantly share code, notes, and snippets.

@antichris
Last active August 20, 2022 18:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antichris/533db4a904156a21f73cfab7327503e1 to your computer and use it in GitHub Desktop.
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"
#!/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