-
Notifications
You must be signed in to change notification settings - Fork 503
Expand file tree
/
Copy pathcompile
More file actions
executable file
·365 lines (307 loc) · 11.3 KB
/
compile
File metadata and controls
executable file
·365 lines (307 loc) · 11.3 KB
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#!/bin/bash
# usage: bin/compile <build-dir> <cache-dir> <env-dir>
set -eo pipefail
[ "$BUILDPACK_XTRACE" ] && set -o xtrace
mkdir -p "$1" "$2"
build=$(cd "$1/" && pwd)
cache_root=$(cd "$2/" && pwd)
cache="${cache_root}/.heroku/go"
mkdir -p "${cache}"
env_dir="${3}"
buildpack=$(cd "$(dirname $0)/.." && pwd)
source "${buildpack}/lib/common.sh"
# Set CACHE_DIR (used by build_data)
CACHE_DIR="${cache_root}"
source "${buildpack}/lib/build_data.sh"
compile_start_time=$(build_data::current_unix_realtime)
# Initialise the build data store used to track state across builds (for cache invalidation
# and messaging when build configuration changes) and also so that `bin/report` can generate
# a build report that will be consumed by the build system for observability.
build_data::setup
snapshotBinBefore
# Clean up old cache files if migrating from old cache structure.
# We detect this legacy structure by looking for 'go-path' in the root.
if [ -d "${cache_root}/go-path" ] && [ ! -d "${cache}/go-path" ]; then
output::step "Clearing old build cache artifacts"
# Remove artifacts that were previously stored in the cache root
rm -rf "${cache_root}"/go[0-9]* \
"${cache_root}"/devel-* \
"${cache_root}/go-path" \
"${cache_root}/go-build-cache" \
"${cache_root}/glide" \
"${cache_root}/gb" \
"${cache_root}/dep" \
"${cache_root}/godep" \
"${cache_root}/govendor" \
"${cache_root}/.tq" \
"${cache_root}/.jq" \
"${cache_root}/github.com/golang-migrate" \
"${cache_root}/github.com/mattes" 2>/dev/null || true
fi
DefaultGoVersion="$(<${DataJSON} jq -r '.Go.DefaultVersion')"
handleDefaultPkgSpec() {
if [ "${pkgs}" = "default" ]; then
output::warning <<-EOF
Installing package '.' (default)
To install a different package spec add a comment in the
following form to your go.mod file:
// +heroku install ./cmd/...
EOF
pkgs="."
fi
}
# Expand a version identifier to supported versions of Go. If the version
# identifier starts with one or more digits, then "go" is prepended before
# expansion. So `1.23` => `go1.23` => `go1.23.12`, `devel` => `devel`. See
# data.json for supported expansions. All others are returned as is without go
# prepended to it.
expandVer() {
local v="${1}"
if [[ "${v}" =~ ^[[:digit:]]+ ]]; then
v="go${v}"
fi
echo $(<${DataJSON} jq -r 'if .Go.VersionExpansion."'${v}'" then .Go.VersionExpansion."'${v}'" else "'${v}'" end')
}
# Report development versions to user
# Use after expandVer
reportVer() {
local ver="${1}"
case $ver in
devel*)
output::warning <<-EOF
You are using a development build of Go.
This is provided for users requiring an unreleased Go version
but is otherwise unsupported.
Build tests are NOT RUN!!
EOF
;;
esac
}
ensureGo() {
local goVersion="${1}"
local goPath="${cache}/${goVersion}/go"
local goFile=""
local txt="Installing ${goVersion}"
if [ -d "${goPath}" ]; then
output::step "Using ${goVersion}"
else
#For a go version change, we delete everything in our namespace
output::step "New Go Version, clearing old cache"
if [ -d "${cache}/go-path" ]; then
find "${cache}/go-path" ! -perm -u=w -print0 | xargs -r -0 chmod u+w 2>&1
fi
rm -rf ${cache}/*
case "${goVersion}" in
devel*)
local bGoVersion="$(expandVer ${DefaultGoVersion})"
goFile="${bGoVersion}.linux-amd64.tar.gz"
goPath="${cache}/${bGoVersion}/go"
txt="Installing bootstrap ${bGoVersion}"
;;
go1)
goFile="go.go1.linux-amd64.tar.gz"
;;
*)
goFile="${goVersion}.linux-amd64.tar.gz"
;;
esac
output::step "${txt}"
ensureFile "${goFile}" "${goPath}" "tar -C ${goPath} --strip-components=1 -zxf"
rm -f "${goPath}/${goFile}"
case "${goVersion}" in
devel*)
pushd "${cache}" &> /dev/null
mkdir -p "${goVersion}"
pushd "${goVersion}" &> /dev/null
local sha=$(echo ${goVersion} | cut -d - -f 2) #assumes devel-<short sha> or devel-<full sha>
local url="https://github.com/golang/go/archive/$sha.tar.gz"
output::step "Downloading development Go version ${goVersion}"
${CURL} ${url} | tar zxf -
mv go-${sha}* go
output::step "Compiling development Go version ${goVersion}"
pushd go/src &> /dev/null
echo "devel +${sha} $(date "+%a %b %H:%M:%S %G %z")"> ../VERSION
GOROOT_BOOTSTRAP=$(pushd ${cache}/${bGoVersion}/go > /dev/null; pwd; popd > /dev/null) ./make.bash 2>&1
popd &> /dev/null
go/bin/go version
rm -rf "${goPath}"
popd &> /dev/null
popd &> /dev/null
goPath="${cache}/${goVersion}/go"
;;
*)
;;
esac
fi
export GOROOT="${goPath}"
PATH="${goPath}/bin:${PATH}"
# Export GOCACHE if Go >= 1.10
if go env | grep -q '^GOCACHE='; then
export GOCACHE="${cache}/go-build-cache"
fi
}
warnGoVersionOverride() {
if [ ! -z "${GOVERSION}" ]; then
output::warning <<-EOF
Using \$GOVERSION override.
\$GOVERSION = ${GOVERSION}
If this isn't what you want please run:
heroku config:unset GOVERSION -a <app>
EOF
fi
}
warnPackageSpecOverride() {
if [ ! -z "${GO_INSTALL_PACKAGE_SPEC}" ]; then
output::warning <<-EOF
Using \$GO_INSTALL_PACKAGE_SPEC override.
\$GO_INSTALL_PACKAGE_SPEC = ${GO_INSTALL_PACKAGE_SPEC}
If this isn't what you want please run:
heroku config:unset GO_INSTALL_PACKAGE_SPEC -a <app>
EOF
fi
}
installPkgs() {
output::step "Running: go install -v ${FLAGS[*]} ${pkgs}"
go install -v "${FLAGS[@]}" ${pkgs} 2>&1 | output::indent
}
loadEnvDir "${env_dir}"
setGitCredHelper "${env_dir}"
trap clearGitCredHelper INT TERM EXIT
FLAGS=(-tags heroku)
determineTool
# Track the requested version before expansion (for pinned check)
requested_go_version="${ver}"
# Expand the version and track the resolved version
ver=$(expandVer $ver)
build_data::set_string "go_version" "${ver}"
# Track whether the version was pinned (fully specified)
if [ "${requested_go_version}" = "${ver}" ]; then
build_data::set_raw "go_version_pinned" "true"
else
build_data::set_raw "go_version_pinned" "false"
fi
# If $GO_LINKER_SYMBOL and GO_LINKER_VALUE are set, tell the linker to DTRT
if [ -n "${GO_LINKER_SYMBOL}" -a -n "${GO_LINKER_VALUE}" ]; then
FLAGS+=(-ldflags "-X ${GO_LINKER_SYMBOL}=${GO_LINKER_VALUE}")
fi
if [ -e "${build}/bin" -a ! -d "${build}/bin" ]; then
output::error <<-EOF
Error: File bin exists and is not a directory.
EOF
exit 1
fi
reportVer "${ver}"
go_install_start_time=$(build_data::current_unix_realtime)
ensureGo "${ver}"
build_data::set_duration "go_install_duration" "${go_install_start_time}"
mkdir -p "${build}/bin"
export GOPATH
mainPackagesInModule() {
# For an explanation of what this is doing, see https://dave.cheney.net/2014/09/14/go-list-your-swiss-army-knife
# Stderr (module download progress) is indented and redirected back to stderr so it displays
# neatly under the current step without being captured into the command substitution's stdout.
go list -find "${FLAGS[@]}" -f '{{ if eq .Name "main" }} {{.ImportPath}} {{ end }}' ./... 2> >(output::indent >&2)
}
setupProcfile() {
if [ -f "${build}/Procfile" ]; then
return
fi
local pkgs=$(mainPackagesInModule)
if [ -z "${pkgs}" ]; then
return
fi
local pf=()
for pkg in ${pkgs}; do
local bn=$(basename ${pkg})
pf+=("${bn}: bin/${bn}")
done
if [ ${#pf} -eq 0 ]; then
return
fi
output::step "Created a Procfile with the following entries:"
if [ ${#pf[@]} -eq 1 ]; then
local line="web: bin/$(echo ${pf[0]} | cut -d / -f 2)"
echo "${line}" > ${build}/Procfile
echo "${line}" | output::indent
elif [ ${#pf[@]} -gt 1 ]; then
for pfl in "${pf[@]}"; do
echo "${pfl}" >> ${build}/Procfile
echo "${pfl}" | output::indent
done
fi
output::notice <<-EOF
If these entries look incomplete or incorrect please create a
Procfile with the required entries.
See https://devcenter.heroku.com/articles/procfile for more details about Procfiles
EOF
}
dependencies_install_start_time=$(build_data::current_unix_realtime)
cd ${build}
export GOBIN="${build}/bin"
if [ "${GO_SETUP_GOPATH_FOR_MODULE_CACHE}" = "true" ]; then
export GOPATH="${build}/.heroku/go-path"
mkdir -p $GOPATH # ensure that it's created
else
export GOPATH="${cache}/go-path"
fi
# TODO: Check the desired language version (eg `go mod edit -json | jq -r '.Go'`)
# and only do this if it's <1.14. The 1.14 release and beyond handles this automatically
# when the desired language version is 1.14+ and vendoring should be used.
# https://golang.org/doc/go1.14#vendor
if [ -d "${build}/vendor" -a -s "${build}/go.sum" ]; then
FLAGS+=(-mod=vendor)
fi
output::step "Determining packages to install"
pkgs=${GO_INSTALL_PACKAGE_SPEC:-$(awk '{ if ($1 == "//" && $2 == "+heroku" && $3 == "install" ) { print substr($0, index($0,$4)); exit }}' ${goMOD})}
if [ -z "${pkgs}" ]; then
pkgs=$(mainPackagesInModule)
if [ -z "${pkgs}" ]; then
output::warning <<-EOF
No main packages found in module ${name}
Unsure what package(s) to install, defaulting to '.'
EOF
pkgs="default"
else
output::step "Detected the following main packages to install:"
for pkg in ${pkgs}; do
echo "${pkg}" | output::indent
done
fi
fi
warnPackageSpecOverride
handleDefaultPkgSpec
unset GIT_DIR # unset git dir or it will mess with goinstall
if [[ -f bin/go-pre-compile ]]; then
output::step "Running bin/go-pre-compile hook"
chmod a+x bin/go-pre-compile
bin/go-pre-compile 2>&1 | output::indent
fi
installPkgs
if [[ -f bin/go-post-compile ]]; then
output::step "Running bin/go-post-compile hook"
chmod a+x bin/go-post-compile
bin/go-post-compile 2>&1 | output::indent
fi
build_data::set_duration "dependencies_install_duration" "${dependencies_install_start_time}"
_newOrUpdatedBinFiles=$(binDiff)
output::step "Installed the following binaries:"
for fyle in ${_newOrUpdatedBinFiles}; do
echo "${fyle}" | output::indent
done
setupProcfile
cd $build
mkdir -p $build/.profile.d
echo 'PATH=$PATH:$HOME/bin' > $build/.profile.d/go.sh
if [ "${GO_INSTALL_TOOLS_IN_IMAGE}" = "true" ]; then
output::step "Copying go tool chain to \$GOROOT=\$HOME/.heroku/go"
mkdir -p "${build}/.heroku/go"
cp -a "${GOROOT}/"* "${build}/.heroku/go"
echo 'export GOROOT=$HOME/.heroku/go' > "${build}/.profile.d/goroot.sh"
echo 'PATH=$PATH:$GOROOT/bin' >> "${build}/.profile.d/goroot.sh"
fi
t="${build}/.heroku/go"
mkdir -p "${t}"
t="${t}/.meta"
echo "TOOL=${TOOL}" > "${t}"
echo "NAME=${name}" >> "${t}"
build_data::set_duration "total_duration" "${compile_start_time}"