-
Notifications
You must be signed in to change notification settings - Fork 251
/
Copy pathgoenv-install
executable file
·276 lines (242 loc) · 7.32 KB
/
goenv-install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/usr/bin/env bash
#
# Summary: Install a Go version using go-build
#
# Usage: goenv install [-f] [-kvpq] <version>|latest|unstable
# goenv install [-f] [-kvpq] <definition-file>
# goenv install -l|--list
# goenv install --version
#
# -l/--list List all available versions
# -f/--force Install even if the version appears to be installed already
# -s/--skip-existing Skip if the version appears to be installed already
#
# go-build options:
#
# -k/--keep Keep source tree in $GOENV_BUILD_ROOT after installation
# (defaults to $GOENV_ROOT/sources)
# -p/--patch Apply a patch from stdin before building
# -v/--verbose Verbose mode: print compilation status to stdout
# -q/--quiet Disable Progress Bar
# --version Show version of go-build
# -g/--debug Build a debug version
#
# For detailed information on installing Go versions with
# go-build, including a list of environment variables for adjusting
# compilation, see: https://github.com/go-nv/goenv#readme
#
set -e
[ -n "$GOENV_DEBUG" ] && set -x
# Add `share/go-build/` directory from each goenv plugin to the list of
# paths where build definitions are looked up.
shopt -s nullglob
for plugin_path in "$GOENV_ROOT"/plugins/*/share/go-build; do
GO_BUILD_DEFINITIONS="${GO_BUILD_DEFINITIONS}:${plugin_path}"
done
export GO_BUILD_DEFINITIONS
shopt -u nullglob
# Provide goenv completions
if [ "$1" = "--complete" ]; then
echo --list
echo --force
echo --skip-existing
echo --keep
echo --patch
echo --verbose
echo --version
echo --debug
echo --quiet
exec go-build --definitions
fi
# Load shared library functions
eval "$(go-build --lib)"
usage() {
goenv-help install 2>/dev/null
[ -z "$1" ] || exit "$1"
}
definitions() {
local query="$1"
go-build --definitions | $(type -p ggrep grep | head -1) -F "$query" || true
}
latest_version() {
definitions | grep -oE "^$1\\.([0-9]+)?$" | tail -1
}
latest_includes_unstable_version() {
definitions | grep -ioE "^$1\\.?([0-9]+|beta[0-9]+|rc[0-9]+)?$" | tail -1
}
indent() {
sed 's/^/ /'
}
unset FORCE
unset SKIP_EXISTING
unset KEEP
unset VERBOSE
unset HAS_PATCH
unset DEBUG
parse_options "$@"
for option in "${OPTIONS[@]}"; do
case "$option" in
"h" | "help")
usage 0
;;
"l" | "list")
echo "Available versions:"
definitions | indent
exit
;;
"f" | "force")
FORCE=true
;;
"s" | "skip-existing")
SKIP_EXISTING=true
;;
"k" | "keep")
[ -n "${GOENV_BUILD_ROOT}" ] || GOENV_BUILD_ROOT="${GOENV_ROOT}/sources"
;;
"v" | "verbose")
VERBOSE="-v"
;;
"p" | "patch")
HAS_PATCH="-p"
;;
"q" | "quiet")
QUIET="-q"
;;
"g" | "debug")
DEBUG="-g"
;;
"version")
exec go-build --version
;;
*)
usage 1 >&2
;;
esac
done
[ "${#ARGUMENTS[@]}" -le 1 ] || usage 1 >&2
unset VERSION_NAME
# The first argument contains the definition to install. If the
# argument is missing, try to install whatever local app-specific
# version is specified by goenv. Show usage instructions if a local
# version is not specified.
DEFINITION="${ARGUMENTS[0]}"
# If latest is supplied, install the latest available (stable) version
if [[ ${DEFINITION} == "latest" ]]; then
LATEST=$(latest_version "[0-9]\\.[0-9]+")
echo "Installing latest version ${LATEST}..."
DEFINITION=$LATEST
# If unstable is supplied, install the latest available (including beta/rc) version
elif [[ ${DEFINITION} == "unstable" ]]; then
LATEST_UNSTABLE=$(latest_includes_unstable_version "[0-9]\\.[0-9]+")
echo "Installing latest (including unstable) version ${LATEST_UNSTABLE}..."
DEFINITION=$LATEST_UNSTABLE
fi
[ -n "$DEFINITION" ] || DEFINITION="$(goenv-local 2>/dev/null || true)"
[ -n "$DEFINITION" ] || usage 1 >&2
# The latest patch version will be located, e.g if 1.11 is supplied they'll be changed to `1.11.x`.
# NOTE: Try to capture semantic versions such as `1.11` which don't have a patch version and install latest patch.
if grep -q -E "^[0-9]+\.[0-9]+(\s*)$" <<<${DEFINITION}; then
REGEX=$(echo $DEFINITION | sed s/\\./\\\\./)
LATEST_PATCH=$(latest_version $REGEX)
echo "Using latest patch version $LATEST_PATCH"
DEFINITION=$LATEST_PATCH
fi
# Define `before_install` and `after_install` functions that allow
# plugin hooks to register a string of code for execution before or
# after the installation process.
declare -a before_hooks after_hooks
before_install() {
local hook="$1"
before_hooks["${#before_hooks[@]}"]="$hook"
}
after_install() {
local hook="$1"
after_hooks["${#after_hooks[@]}"]="$hook"
}
OLDIFS="$IFS"
IFS=$'\n' scripts=($(goenv-hooks install))
IFS="$OLDIFS"
for script in "${scripts[@]}"; do
source "$script"
done
# Set VERSION_NAME from $DEFINITION, if it is not already set. Then
# compute the installation prefix.
[ -n "$VERSION_NAME" ] || VERSION_NAME="${DEFINITION##*/}"
[ -n "$DEBUG" ] && VERSION_NAME="${VERSION_NAME}-debug"
PREFIX="${GOENV_ROOT}/versions/${VERSION_NAME}"
[ -d "${PREFIX}" ] && PREFIX_EXISTS=1
# If the installation prefix exists, prompt for confirmation unless
# the --force option was specified.
if [ -d "${PREFIX}/bin" ]; then
if [ -z "$FORCE" ] && [ -z "$SKIP_EXISTING" ]; then
echo "goenv: $PREFIX already exists" >&2
read -p "continue with installation? (y/N) "
case "$REPLY" in
y* | Y*) ;;
*) exit 1 ;;
esac
elif [ -n "$SKIP_EXISTING" ]; then
# Since we know the go version is already installed, and are opting to
# not force installation of existing versions, we just `exit 0` here to
# leave things happy
exit 0
fi
fi
# If GOENV_BUILD_ROOT is set, always pass keep options to go-build.
if [ -n "${GOENV_BUILD_ROOT}" ]; then
export GO_BUILD_BUILD_PATH="${GOENV_BUILD_ROOT}/${VERSION_NAME}"
KEEP="-k"
fi
# Set GO_BUILD_CACHE_PATH to $GOENV_ROOT/cache, if the directory
# exists and the variable is not already set.
if [ -z "${GO_BUILD_CACHE_PATH}" ] && [ -d "${GOENV_ROOT}/cache" ]; then
export GO_BUILD_CACHE_PATH="${GOENV_ROOT}/cache"
fi
# Execute `before_install` hooks.
for hook in "${before_hooks[@]}"; do
eval "$hook"
done
# Plan cleanup on unsuccessful installation.
cleanup() {
[ -z "${PREFIX_EXISTS}" ] && rm -rf "$PREFIX"
}
trap cleanup SIGINT
# Invoke `go-build` and record the exit status in $STATUS.
STATUS=0
go-build $KEEP $VERBOSE $HAS_PATCH $QUIET $DEBUG "$DEFINITION" "$PREFIX" || STATUS="$?"
# Display a more helpful message if the definition wasn't found.
if [ "$STATUS" == "2" ]; then
{
candidates="$(definitions "$DEFINITION")"
here="$(dirname "${0%/*}")/../.."
if [ -n "$candidates" ]; then
echo
echo "The following versions contain '$DEFINITION' in the name:"
echo "$candidates" | indent
fi
echo
echo "See all available versions with 'goenv install --list'."
echo
echo -n "If the version you need is missing, try upgrading goenv"
if [ "$here" != "${here#$(brew --prefix 2>/dev/null)}" ]; then
printf ":\n\n"
echo " brew update && brew upgrade goenv"
elif [ -d "${here}/.git" ]; then
printf ":\n\n"
echo " cd ${here} && git pull && cd -"
else
printf ".\n"
fi
} >&2
fi
# Execute `after_install` hooks.
for hook in "${after_hooks[@]}"; do
eval "$hook"
done
# Run `goenv-rehash` after a successful installation.
if [ "$STATUS" == "0" ]; then
goenv-rehash
else
cleanup
fi
exit "$STATUS"