From 595f5a08429bed2a36a169db900cfb40a2c25b51 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 26 Apr 2025 11:50:16 +0300 Subject: [PATCH 1/3] Use Gimme to automatically install the correct Go version --- .github/workflows/coherence-matrix.yaml | 8 +- .go-version | 1 + Makefile | 33 +- go.mod | 8 + hack/gimme/LICENSE | 21 + hack/gimme/README.md | 6 + hack/gimme/gimme | 947 ++++++++++++++++++++++++ hack/golang/goinstalldir.sh | 49 ++ hack/golang/gotoolchain.sh | 23 + hack/golang/setup-go.sh | 41 + 10 files changed, 1120 insertions(+), 17 deletions(-) create mode 100644 .go-version create mode 100644 hack/gimme/LICENSE create mode 100644 hack/gimme/README.md create mode 100644 hack/gimme/gimme create mode 100644 hack/golang/goinstalldir.sh create mode 100644 hack/golang/gotoolchain.sh create mode 100644 hack/golang/setup-go.sh diff --git a/.github/workflows/coherence-matrix.yaml b/.github/workflows/coherence-matrix.yaml index 62ec8694e..df14e8c7f 100644 --- a/.github/workflows/coherence-matrix.yaml +++ b/.github/workflows/coherence-matrix.yaml @@ -171,10 +171,10 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod +# - name: Set up Go +# uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod - name: Cache Go Modules uses: actions/cache@v4 diff --git a/.go-version b/.go-version new file mode 100644 index 000000000..0b4c970ea --- /dev/null +++ b/.go-version @@ -0,0 +1 @@ +1.24.2 \ No newline at end of file diff --git a/Makefile b/Makefile index b6793dfc8..17463a74a 100644 --- a/Makefile +++ b/Makefile @@ -35,6 +35,22 @@ PROJECT_URL = https://github.com/oracle/coherence-operator KUBERNETES_DOC_VERSION=v1.32 +# ========================= Setup Go With Gimme ================================ +# go version to use for build etc. +# setup correct go version with gimme +GOTOOLCHAIN:=$(shell . hack/golang/gotoolchain.sh && echo "$${GOTOOLCHAIN}") +PATH:=$(shell . hack/golang/setup-go.sh && echo "$${PATH}") +# go1.9+ can autodetect GOROOT, but if some other tool sets it ... +GOROOT:= +# enable modules +GO111MODULE=on +# disable CGO by default for static binaries +CGO_ENABLED=0 +export PATH GOROOT GO111MODULE CGO_ENABLED GOTOOLCHAIN +# work around broken PATH export +SPACE:=$(subst ,, ) +SHELL:=env PATH=$(subst $(SPACE),\$(SPACE),$(PATH)) $(SHELL) + # ---------------------------------------------------------------------------------------------------------------------- # Operator image names # ---------------------------------------------------------------------------------------------------------------------- @@ -561,9 +577,9 @@ $(BUILD_TARGETS)/delve-image: $(BUILD_BIN)/runner-debug: $(BUILD_PROPS) $(GOS) $(BUILD_TARGETS)/generate $(BUILD_TARGETS)/manifests mkdir -p $(BUILD_BIN_AMD64) || true - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -gcflags "-N -l" -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_AMD64)/runner-debug ./runner + GOOS=linux GOARCH=amd64 GO111MODULE=on go build -gcflags "-N -l" -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_AMD64)/runner-debug ./runner mkdir -p $(BUILD_BIN_ARM64)/linux || true - CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -gcflags "-N -l" -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_ARM64)/runner-debug ./runner + GOOS=linux GOARCH=arm64 GO111MODULE=on go build -gcflags "-N -l" -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_ARM64)/runner-debug ./runner ifeq (x86_64, $(UNAME_M)) cp -f $(BUILD_BIN_AMD64)/runner-debug $(BUILD_BIN)/runner-debug else @@ -706,9 +722,9 @@ build-runner: $(BUILD_BIN)/runner ## Build the Coherence Operator runner binary $(BUILD_BIN)/runner: $(BUILD_PROPS) $(GOS) $(BUILD_TARGETS)/generate $(BUILD_TARGETS)/manifests mkdir -p $(BUILD_BIN_AMD64) || true - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -trimpath -ldflags "$(LDFLAGS)" -o $(BUILD_BIN_AMD64)/runner ./runner + GOOS=linux GOARCH=amd64 GO111MODULE=on go build -trimpath -ldflags "$(LDFLAGS)" -o $(BUILD_BIN_AMD64)/runner ./runner mkdir -p $(BUILD_BIN_ARM64)/linux || true - CGO_ENABLED=0 GOOS=linux GOARCH=arm64 GO111MODULE=on go build -trimpath -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_ARM64)/runner ./runner + GOOS=linux GOARCH=arm64 GO111MODULE=on go build -trimpath -ldflags "$(LDFLAGS)" -a -o $(BUILD_BIN_ARM64)/runner ./runner ifeq (x86_64, $(UNAME_M)) cp -f $(BUILD_BIN_AMD64)/runner $(BUILD_BIN)/runner else @@ -1242,7 +1258,6 @@ oc-login: # Executes the Go unit tests that do not require a k8s cluster # ---------------------------------------------------------------------------------------------------------------------- .PHONY: test-operator -test-operator: export CGO_ENABLED = 0 test-operator: export COHERENCE_IMAGE := $(COHERENCE_IMAGE) test-operator: export OPERATOR_IMAGE := $(OPERATOR_IMAGE) test-operator: $(BUILD_PROPS) $(BUILD_TARGETS)/manifests $(BUILD_TARGETS)/generate install-crds gotestsum ## Run the Operator unit tests @@ -1293,7 +1308,6 @@ $(TOOLS_BIN)/k8s: $(TOOLS_BIN)/setup-envtest # is pointing to. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: e2e-local-test -e2e-local-test: export CGO_ENABLED = 0 e2e-local-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) e2e-local-test: export CLUSTER_NAMESPACE := $(CLUSTER_NAMESPACE) e2e-local-test: export OPERATOR_NAMESPACE_CLIENT := $(OPERATOR_NAMESPACE_CLIENT) @@ -1345,7 +1359,6 @@ e2e-test: prepare-e2e-test ## Run the Operator end-to-end 'remote' functional te prepare-e2e-test: reset-namespace create-ssl-secrets ensure-pull-secret deploy-and-wait .PHONY: run-e2e-test -run-e2e-test: export CGO_ENABLED = 0 run-e2e-test: export TEST_SSL_SECRET := $(TEST_SSL_SECRET) run-e2e-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) run-e2e-test: export CLUSTER_NAMESPACE := $(CLUSTER_NAMESPACE) @@ -1381,7 +1394,6 @@ run-e2e-test: gotestsum ## Run the Operator 'remote' end-to-end functional test # is pointing to. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: e2e-k3d-test -e2e-k3d-test: export CGO_ENABLED = 0 e2e-k3d-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) e2e-k3d-test: export CLUSTER_NAMESPACE := $(CLUSTER_NAMESPACE) e2e-k3d-test: export OPERATOR_NAMESPACE_CLIENT := $(OPERATOR_NAMESPACE_CLIENT) @@ -1417,7 +1429,6 @@ e2e-k3d-test: reset-namespace create-ssl-secrets gotestsum undeploy install-crds # ---------------------------------------------------------------------------------------------------------------------- # Run the end-to-end Coherence client tests. # ---------------------------------------------------------------------------------------------------------------------- -e2e-client-test: export CGO_ENABLED = 0 e2e-client-test: export CLIENT_CLASSPATH := $(CURRDIR)/java/operator-test-client/target/operator-test-client-$(MVN_VERSION).jar:$(CURRDIR)/java/operator-test-client/target/lib/* e2e-client-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) e2e-client-test: export OPERATOR_NAMESPACE_CLIENT := $(OPERATOR_NAMESPACE_CLIENT) @@ -1475,7 +1486,6 @@ e2e-prometheus-test: reset-namespace install-prometheus create-ssl-secrets ensur ; exit $$rc .PHONY: run-prometheus-test -run-prometheus-test: export CGO_ENABLED = 0 run-prometheus-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) run-prometheus-test: export TEST_APPLICATION_IMAGE := $(TEST_APPLICATION_IMAGE) run-prometheus-test: export TEST_APPLICATION_IMAGE_HELIDON := $(TEST_APPLICATION_IMAGE_HELIDON) @@ -1511,7 +1521,6 @@ run-prometheus-test: gotestsum compatibility-test: undeploy build-all-images helm-chart undeploy clean-namespace reset-namespace ensure-pull-secret gotestsum just-compatibility-test ## Run the Operator backwards compatibility tests .PHONY: just-compatibility-test -just-compatibility-test: export CGO_ENABLED = 0 just-compatibility-test: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) just-compatibility-test: export CLUSTER_NAMESPACE := $(CLUSTER_NAMESPACE) just-compatibility-test: export BUILD_OUTPUT := $(BUILD_OUTPUT) @@ -1572,7 +1581,6 @@ install-certification: $(BUILD_TARGETS)/build-operator prepare-network-policies # Note that the namespace will be created if it does not exist. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: run-certification -run-certification: export CGO_ENABLED = 0 run-certification: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) run-certification: export CLUSTER_NAMESPACE := $(CLUSTER_NAMESPACE) run-certification: export BUILD_OUTPUT := $(BUILD_OUTPUT) @@ -1729,7 +1737,6 @@ install-coherence-compatibility: $(BUILD_TARGETS)/build-operator reset-namespace # Note that the namespace will be created if it does not exist. # ---------------------------------------------------------------------------------------------------------------------- .PHONY: run-coherence-compatibility -run-coherence-compatibility: export CGO_ENABLED = 0 run-coherence-compatibility: export OPERATOR_NAMESPACE := $(OPERATOR_NAMESPACE) run-coherence-compatibility: export TEST_COMPATIBILITY_IMAGE := $(TEST_COMPATIBILITY_IMAGE) run-coherence-compatibility: export IMAGE_PULL_SECRETS := $(IMAGE_PULL_SECRETS) diff --git a/go.mod b/go.mod index efb8de09b..9efcafd55 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,13 @@ module github.com/oracle/coherence-operator +// NOTE: This is the go language version, NOT the compiler version. +// +// This controls the *minimum* required go version and therefore available Go +// language features. +// +// See ./.go-version for the go compiler version used when building binaries +// +// https://go.dev/doc/modules/gomod-ref#go go 1.24.2 require ( diff --git a/hack/gimme/LICENSE b/hack/gimme/LICENSE new file mode 100644 index 000000000..aace32e57 --- /dev/null +++ b/hack/gimme/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2018 gimme contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/hack/gimme/README.md b/hack/gimme/README.md new file mode 100644 index 000000000..ae954f8b4 --- /dev/null +++ b/hack/gimme/README.md @@ -0,0 +1,6 @@ +# gimme + +This is an unmodified copy of [gimme], so we don't have to download it +from the internet. + +[gimme]: https://github.com/travis-ci/gimme \ No newline at end of file diff --git a/hack/gimme/gimme b/hack/gimme/gimme new file mode 100644 index 000000000..1b87e403e --- /dev/null +++ b/hack/gimme/gimme @@ -0,0 +1,947 @@ +#!/usr/bin/env bash +# vim:noexpandtab:ts=2:sw=2: +# +#+ Usage: $(basename $0) [flags] [go-version] [version-prefix] +#+ - +#+ Version: ${GIMME_VERSION} +#+ Copyright: ${GIMME_COPYRIGHT} +#+ License URL: ${GIMME_LICENSE_URL} +#+ - +#+ Install go! There are multiple types of installations available, with 'auto' being the default. +#+ If either 'auto' or 'binary' is specified as GIMME_TYPE, gimme will first check for an existing +#+ go installation. This behavior may be disabled by providing '-f/--force/force' as first positional +#+ argument. +#+ - +#+ Option flags: +#+ -h --help help - show this help text and exit +#+ -V --version version - show the version only and exit +#+ -f --force force - remove the existing go installation if present prior to install +#+ -l --list list - list installed go versions and exit +#+ -k --known known - list known go versions and exit +#+ --force-known-update - when used with --known, ignores the cache and updates +#+ -r --resolve resolve - resolve a version specifier to a version, show that and exit +#+ - +#+ Influential env vars: +#+ - +#+ GIMME_GO_VERSION - version to install (*REQUIRED*, may be given as first positional arg) +#+ GIMME_VERSION_PREFIX - prefix for installed versions (default '${GIMME_VERSION_PREFIX}', +#+ may be given as second positional arg) +#+ GIMME_ARCH - arch to install (default '${GIMME_ARCH}') +#+ GIMME_BINARY_OSX - darwin-specific binary suffix (default '${GIMME_BINARY_OSX}') +#+ GIMME_ENV_PREFIX - prefix for env files (default '${GIMME_ENV_PREFIX}') +#+ GIMME_GO_GIT_REMOTE - git remote for git-based install (default '${GIMME_GO_GIT_REMOTE}') +#+ GIMME_OS - os to install (default '${GIMME_OS}') +#+ GIMME_TMP - temp directory (default '${GIMME_TMP}') +#+ GIMME_TYPE - install type to perform ('auto', 'binary', 'source', or 'git') +#+ (default '${GIMME_TYPE}') +#+ GIMME_INSTALL_RACE - install race directory after compile if non-empty. +#+ If the install type is 'binary', this option is ignored. +#+ GIMME_DEBUG - enable tracing if non-empty +#+ GIMME_NO_ENV_ALIAS - disable creation of env 'alias' file when os and arch match host +#+ GIMME_SILENT_ENV - omit the 'go version' line from env file +#+ GIMME_CGO_ENABLED - enable build of cgo support +#+ GIMME_CC_FOR_TARGET - cross compiler for cgo support +#+ GIMME_DOWNLOAD_BASE - override base URL dir for download (default '${GIMME_DOWNLOAD_BASE}') +#+ GIMME_LIST_KNOWN - override base URL for known go versions (default '${GIMME_LIST_KNOWN}') +#+ GIMME_KNOWN_CACHE_MAX - seconds the cache for --known is valid for (default '${GIMME_KNOWN_CACHE_MAX}') +#+ - +# +set -e +shopt -s nullglob +shopt -s dotglob +shopt -s extglob +set -o pipefail + +[[ ${GIMME_DEBUG} ]] && set -x + +readonly GIMME_VERSION="v1.5.4" +readonly GIMME_COPYRIGHT="Copyright (c) 2015-2020 gimme contributors" +readonly GIMME_LICENSE_URL="https://raw.githubusercontent.com/travis-ci/gimme/${GIMME_VERSION}/LICENSE" +export GIMME_VERSION +export GIMME_COPYRIGHT +export GIMME_LICENSE_URL + +program_name="$(basename "$0")" +# shellcheck disable=SC1117 +warn() { printf >&2 "%s: %s\n" "${program_name}" "${*}"; } +die() { + warn "$@" + exit 1 +} + +# We don't want to go around hitting Google's servers with requests for +# files named HEAD@{date}.tar so we only try binary/source downloads if +# it looks like a plausible name to us. +# We don't need to support 0. releases of Go. +# We don't support 5 digit major-versions of Go (limit back-tracking in RE). +# We don't support very long versions +# (both to avoid annoying download server operators with attacks and +# because regexp backtracking can be pathological). +# Per _assert_version_given we do assume 2.0 not 2 +ALLOWED_UPSTREAM_VERSION_RE='^[1-9][0-9]{0,3}(\.[0-9][0-9a-zA-Z_-]{0,9})+$' +# +# The main path which allowed these to leak upstream before has been closed +# but a valid git repo tag or branch-name will still reach the point of +# being _tried_ upstream. + +# _do_curl "url" "file" +_do_curl() { + mkdir -p "$(dirname "${2}")" + + if command -v curl >/dev/null; then + curl -sSLf "${1}" -o "${2}" 2>/dev/null + return + fi + + if command -v wget >/dev/null; then + wget -q "${1}" -O "${2}" 2>/dev/null + return + fi + + if command -v fetch >/dev/null; then + fetch -q "${1}" -o "${2}" 2>/dev/null + return + fi + + echo >&2 'error: no curl, wget, or fetch found' + exit 1 +} + +# _sha256sum "file" +_sha256sum() { + if command -v sha256sum &>/dev/null; then + sha256sum "$@" + elif command -v gsha256sum &>/dev/null; then + gsha256sum "$@" + else + shasum -a 256 "$@" + fi +} + +# sort versions, handling 1.10 after 1.9, not before 1.2 +# FreeBSD sort has --version-sort, none of the others do +# Looks like --general-numeric-sort is the safest; checked macOS 10.12.6, FreeBSD 10.3, Ubuntu Trusty +if sort --version-sort /dev/null; then + _version_sort() { sort --version-sort; } +else + _version_sort() { + # If we go to four-digit minor or patch versions, then extend the padding here + # (but in such a world, perhaps --version-sort will have become standard by then?) + sed -E 's/\.([0-9](\.|$))/.00\1/g; s/\.([0-9][0-9](\.|$))/.0\1/g' | + sort --general-numeric-sort | + sed 's/\.00*/./g' + } +fi + +# _do_curls "file" "url" ["url"...] +_do_curls() { + f="${1}" + shift + if _sha256sum -c "${f}.sha256" &>/dev/null; then + return 0 + fi + for url in "${@}"; do + if _do_curl "${url}" "${f}"; then + if _do_curl "${url}.sha256" "${f}.sha256"; then + echo "$(cat "${f}.sha256") ${f}" >"${f}.sha256.tmp" + mv "${f}.sha256.tmp" "${f}.sha256" + if ! _sha256sum -c "${f}.sha256" &>/dev/null; then + warn "sha256sum failed for '${f}'" + warn 'continuing to next candidate URL' + continue + fi + fi + return + fi + done + rm -f "${f}" + return 1 +} + +# _binary "version" "file.tar.gz" "arch" +_binary() { + local version=${1} + local file=${2} + local arch=${3} + urls=( + "${GIMME_DOWNLOAD_BASE}/go${version}.${GIMME_OS}-${arch}.tar.gz" + ) + if [[ "${GIMME_OS}" == 'darwin' && "${GIMME_BINARY_OSX}" ]]; then + urls=( + "${GIMME_DOWNLOAD_BASE}/go${version}.${GIMME_OS}-${arch}-${GIMME_BINARY_OSX}.tar.gz" + "${urls[@]}" + ) + fi + if [ "${arch}" = 'arm' ]; then + # attempt "armv6l" vs just "arm" first (since that's what's officially published) + urls=( + "${GIMME_DOWNLOAD_BASE}/go${version}.${GIMME_OS}-${arch}v6l.tar.gz" # go1.6beta2 & go1.6rc1 + "${GIMME_DOWNLOAD_BASE}/go${version}.${GIMME_OS}-${arch}6.tar.gz" # go1.6beta1 + "${urls[@]}" + ) + fi + if [ "${GIMME_OS}" = 'windows' ]; then + urls=( + "${GIMME_DOWNLOAD_BASE}/go${version}.${GIMME_OS}-${arch}.zip" + ) + fi + _do_curls "${file}" "${urls[@]}" +} + +# _source "version" "file.src.tar.gz" +_source() { + urls=( + "${GIMME_DOWNLOAD_BASE}/go${1}.src.tar.gz" + "https://github.com/golang/go/archive/go${1}.tar.gz" + ) + _do_curls "${2}" "${urls[@]}" +} + +# _fetch "dir" +_fetch() { + mkdir -p "$(dirname "${1}")" + + if [[ -d "${1}/.git" ]]; then + ( + cd "${1}" + git remote set-url origin "${GIMME_GO_GIT_REMOTE}" + git fetch -q --all && git fetch -q --tags + ) + return + fi + + git clone -q "${GIMME_GO_GIT_REMOTE}" "${1}" +} + +# _checkout "version" "dir" +# NB: might emit a "renamed version" on stdout +_checkout() { + local spec="${1:?}" godir="${2:?}" + # We are called twice, once during validation that a version was given and + # later during build. We don't want to fetch twice, so we are fetching + # during the validation only, in the caller. + + if [[ "${spec}" =~ ^[0-9a-f]{6,}$ ]]; then + # We always treat this as a commit sha, whether instead of doing + # branch tests etc. It looks like a commit sha and the Go maintainers + # aren't daft enough to use pure hex for a tag or branch. + git -C "$godir" reset -q --hard "${spec}" || return 1 + return 0 + fi + + # If spec looks like HEAD^{something} or HEAD^^^ then trying + # origin/$spec would succeed but we'd write junk to the filesystem, + # propagating annoying characters out. + local retval probe_named disallow rev + + probe_named=1 + disallow='[@^~:{}]' + if [[ "${spec}" =~ $disallow ]]; then + probe_named=0 + [[ "${spec}" != "@" ]] || spec="HEAD" + fi + + try_spec() { git -C "${godir}" reset -q --hard "$@" -- 2>/dev/null; } + + retval=1 + if ((probe_named)); then + retval=0 + try_spec "origin/${spec}" || + try_spec "origin/go${spec}" || + { [[ "${spec}" == "tip" ]] && try_spec origin/master; } || + try_spec "refs/tags/${spec}" || + try_spec "refs/tags/go${spec}" || + retval=1 + fi + + if ((retval)); then + retval=0 + # We're about to reset anyway, if we succeed, so we should reset to a + # known state before parsing what might be relative specs + try_spec origin/master && + rev="$(git -C "${godir}" rev-parse --verify -q "${spec}^{object}")" && + try_spec "${rev}" && + git -C "${godir}" rev-parse --verify -q --short=12 "${rev}" || + retval=1 + # that rev-parse prints to stdout, so we can affect the version seen + fi + + unset -f try_spec + return $retval +} + +# _extract "file.tar.gz" "dir" +_extract() { + mkdir -p "${2}" + + if [[ "${1}" == *.tar.gz ]]; then + tar -xf "${1}" -C "${2}" --strip-components 1 + else + unzip -q "${1}" -d "${2}" + mv "${2}"/go/* "${2}" + rmdir "${2}"/go + fi +} + +# _setup_bootstrap +_setup_bootstrap() { + local versions=("1.18" "1.17" "1.16" "1.15" "1.14" "1.13" "1.12" "1.11" "1.10" "1.9" "1.8" "1.7" "1.6" "1.5" "1.4") + + # try existing + for v in "${versions[@]}"; do + for candidate in "${GIMME_ENV_PREFIX}/go${v}"*".env"; do + if [ -s "${candidate}" ]; then + # shellcheck source=/dev/null + GOROOT_BOOTSTRAP="$(source "${candidate}" 2>/dev/null && go env GOROOT)" + export GOROOT_BOOTSTRAP + return 0 + fi + done + done + + # try binary + for v in "${versions[@]}"; do + if [ -n "$(_try_binary "${v}" "${GIMME_HOSTARCH}")" ]; then + export GOROOT_BOOTSTRAP="${GIMME_VERSION_PREFIX}/go${v}.${GIMME_OS}.${GIMME_HOSTARCH}" + return 0 + fi + done + + echo >&2 "Unable to setup go bootstrap from existing or binary" + return 1 +} + +# _compile "dir" +_compile() { + ( + if grep -q GOROOT_BOOTSTRAP "${1}/src/make.bash" &>/dev/null; then + _setup_bootstrap || return 1 + fi + cd "${1}" + if [[ -d .git ]]; then + git clean -dfx -q + fi + cd src + export GOOS="${GIMME_OS}" GOARCH="${GIMME_ARCH}" + export CGO_ENABLED="${GIMME_CGO_ENABLED}" + export CC_FOR_TARGET="${GIMME_CC_FOR_TARGET}" + + local make_log="${1}/make.${GOOS}.${GOARCH}.log" + if [[ "${GIMME_DEBUG}" -ge "2" ]]; then + ./make.bash -v 2>&1 | tee "${make_log}" 1>&2 || return 1 + else + ./make.bash &>"${make_log}" || return 1 + fi + ) +} + +_try_install_race() { + if [[ ! "${GIMME_INSTALL_RACE}" ]]; then + return 0 + fi + "${1}/bin/go" install -race std +} + +_can_compile() { + cat >"${GIMME_TMP}/test.go" <<'EOF' +package main +import "os" +func main() { + os.Exit(0) +} +EOF + "${1}/bin/go" run "${GIMME_TMP}/test.go" +} + +# _env "dir" +_env() { + [[ -d "${1}/bin" && -x "${1}/bin/go" ]] || return 1 + + # if we try to run a Darwin binary on Linux, we need to fail so 'auto' can fallback to cross-compiling from source + # automatically + GOROOT="${1}" GOFLAGS="" "${1}/bin/go" version &>/dev/null || return 1 + + # https://twitter.com/davecheney/status/431581286918934528 + # we have to GOROOT sometimes because we use official release binaries in unofficial locations :( + # + # Issue 87 leads to: + # No, we should _always_ set GOROOT when using official release binaries, and sanest to just always set it. + # The "avoid setting it" is _only_ for people using official releases in official locations. + # Tools like `gimme` are the reason that GOROOT-in-env exists. + + echo + if [[ "$(GOROOT="${1}" "${1}/bin/go" env GOHOSTOS)" == "${GIMME_OS}" ]]; then + echo 'unset GOOS;' + else + echo 'export GOOS="'"${GIMME_OS}"'";' + fi + if [[ "$(GOROOT="${1}" "${1}/bin/go" env GOHOSTARCH)" == "${GIMME_ARCH}" ]]; then + echo 'unset GOARCH;' + else + echo 'export GOARCH="'"${GIMME_ARCH}"'";' + fi + + echo "export GOROOT='${1}';" + + # shellcheck disable=SC2016 + echo 'export PATH="'"${1}/bin"':${PATH}";' + if [[ -z "${GIMME_SILENT_ENV}" ]]; then + echo 'go version >&2;' + fi + echo +} + +# _env_alias "dir" "env-file" +_env_alias() { + if [[ "${GIMME_NO_ENV_ALIAS}" ]]; then + echo "${2}" + return + fi + + if [[ "$(GOROOT="${1}" "${1}/bin/go" env GOHOSTOS)" == "${GIMME_OS}" && "$(GOROOT="${1}" "${1}/bin/go" env GOHOSTARCH)" == "${GIMME_ARCH}" ]]; then + # GIMME_GO_VERSION might be a branch, which can contain '/' + local dest="${GIMME_ENV_PREFIX}/go${GIMME_GO_VERSION//\//__}.env" + cp "${2}" "${dest}" + ln -sf "${dest}" "${GIMME_ENV_PREFIX}/latest.env" + echo "${dest}" + else + echo "${2}" + fi +} + +_try_existing() { + case "${1}" in + binary) + local existing_ver="${GIMME_VERSION_PREFIX}/go${GIMME_GO_VERSION}.${GIMME_OS}.${GIMME_ARCH}" + local existing_env="${GIMME_ENV_PREFIX}/go${GIMME_GO_VERSION}.${GIMME_OS}.${GIMME_ARCH}.env" + ;; + source) + local existing_ver="${GIMME_VERSION_PREFIX}/go${GIMME_GO_VERSION}.src" + local existing_env="${GIMME_ENV_PREFIX}/go${GIMME_GO_VERSION}.src.env" + ;; + *) + _try_existing binary || _try_existing source + return $? + ;; + esac + + if [[ -x "${existing_ver}/bin/go" && -s "${existing_env}" ]]; then + # newer envs have existing semi-colon at end of line, because newer gimme + # puts them there; envs created before that change lack those semi-colons + # and should gain them, to make it easier for people using eval without + # double-quoting the command substition. + sed -e 's/\([^;]\)$/\1;/' <"${existing_env}" + # gimme is the corner-case where GOROOT _should_ be overriden, since if the + # ancilliary tooling's system-internal DefaultGoroot exists, and GOROOT is + # unset, then it will be used and the wrong golang will be picked up. + # Lots of old installs won't have GOROOT; munge it from $PATH + if grep -qs '^unset GOROOT' -- "${existing_env}"; then + sed -n -e 's/^export PATH="\(.*\)\/bin:.*$/export GOROOT='"'"'\1'"'"';/p' <"${existing_env}" + echo + fi + # Export the same variables whether building new or using existing + echo "export GIMME_ENV='${existing_env}';" + return + fi + + return 1 +} + +# _try_binary "version" "arch" +_try_binary() { + local version=${1} + local arch=${2} + local bin_tgz="${GIMME_TMP}/go${version}.${GIMME_OS}.${arch}.tar.gz" + local bin_dir="${GIMME_VERSION_PREFIX}/go${version}.${GIMME_OS}.${arch}" + local bin_env="${GIMME_ENV_PREFIX}/go${version}.${GIMME_OS}.${arch}.env" + + [[ "${version}" =~ ${ALLOWED_UPSTREAM_VERSION_RE} ]] || return 1 + + if [ "${GIMME_OS}" = 'windows' ]; then + bin_tgz=${bin_tgz%.tar.gz}.zip + fi + + _binary "${version}" "${bin_tgz}" "${arch}" || return 1 + _extract "${bin_tgz}" "${bin_dir}" || return 1 + _env "${bin_dir}" | tee "${bin_env}" || return 1 + echo "export GIMME_ENV=\"$(_env_alias "${bin_dir}" "${bin_env}")\"" +} + +_try_source() { + local src_tgz="${GIMME_TMP}/go${GIMME_GO_VERSION}.src.tar.gz" + local src_dir="${GIMME_VERSION_PREFIX}/go${GIMME_GO_VERSION}.src" + local src_env="${GIMME_ENV_PREFIX}/go${GIMME_GO_VERSION}.src.env" + + [[ "${GIMME_GO_VERSION}" =~ ${ALLOWED_UPSTREAM_VERSION_RE} ]] || return 1 + + _source "${GIMME_GO_VERSION}" "${src_tgz}" || return 1 + _extract "${src_tgz}" "${src_dir}" || return 1 + _compile "${src_dir}" || return 1 + _try_install_race "${src_dir}" || return 1 + _env "${src_dir}" | tee "${src_env}" || return 1 + echo "export GIMME_ENV=\"$(_env_alias "${src_dir}" "${src_env}")\"" +} + +# We do _not_ try to use any version caching with _try_existing(), but instead +# build afresh each time. We don't want to deal with someone moving the repo +# to other-version, doing an install, then resetting it back to +# last-version-we-saw and thus introducing conflicts. +# +# If you want to re-use a built-at-spec version, then avoid moving the repo +# and source the generated .env manually. +# Note that the env will just refer to the 'go' directory, so it's not safe +# to reuse anyway. +_try_git() { + local git_dir="${GIMME_VERSION_PREFIX}/go" + local git_env="${GIMME_ENV_PREFIX}/go.git.${GIMME_OS}.${GIMME_ARCH}.env" + local resolved_sha + + # Any tags should have been resolved when we asserted that we were + # given a version, so no need to handle that here. + _checkout "${GIMME_GO_VERSION}" "${git_dir}" >/dev/null || return 1 + _compile "${git_dir}" || return 1 + _try_install_race "${git_dir}" || return 1 + _env "${git_dir}" | tee "${git_env}" || return 1 + echo "export GIMME_ENV=\"$(_env_alias "${git_dir}" "${git_env}")\"" +} + +_wipe_version() { + local env_file="${GIMME_ENV_PREFIX}/go${1}.${GIMME_OS}.${GIMME_ARCH}.env" + + if [[ -s "${env_file}" ]]; then + rm -rf "$(awk -F\" '/GOROOT/ { print $2 }' "${env_file}")" + rm -f "${env_file}" + fi +} + +_list_versions() { + if [ ! -d "${GIMME_VERSION_PREFIX}" ]; then + return 0 + fi + + local current_version + current_version="$(go env GOROOT 2>/dev/null)" + current_version="${current_version##*/go}" + current_version="${current_version%%.${GIMME_OS}.*}" + + # 1.1 1.10 1.2 is bad; zsh has `setopt numeric_glob_sort` but bash + # doesn't appear to have anything like that. + for d in "${GIMME_VERSION_PREFIX}/go"*".${GIMME_OS}."*; do + local cleaned="${d##*/go}" + cleaned="${cleaned%%.${GIMME_OS}.*}" + echo "${cleaned}" + done | _version_sort | while read -r cleaned; do + echo -en "${cleaned}" + if [[ "${cleaned}" == "${current_version}" ]]; then + echo -en ' <= current' >&2 + fi + echo + done +} + +_update_remote_known_list_if_needed() { + # shellcheck disable=SC1117 + local exp="go([[:alnum:]\.]*)\.src.*" # :alnum: catches beta versions too + local list="${GIMME_VERSION_PREFIX}/known-versions.txt" + local dlfile="${GIMME_TMP}/known-dl" + + if [[ -e "${list}" ]] && + ! ((force_known_update)) && + ! _file_older_than_secs "${list}" "${GIMME_KNOWN_CACHE_MAX}"; then + echo "${list}" + return 0 + fi + + [[ -d "${GIMME_VERSION_PREFIX:?}" ]] || mkdir -p -- "${GIMME_VERSION_PREFIX}" + + _do_curl "${GIMME_LIST_KNOWN}" "${dlfile}" + + while read -r line; do + if [[ "${line}" =~ ${exp} ]]; then + echo "${BASH_REMATCH[1]}" + fi + done <"${dlfile}" | _version_sort | uniq >"${list}.new" + rm -f "${list}" &>/dev/null + mv "${list}.new" "${list}" + + rm -f "${dlfile}" + echo "${list}" + return 0 +} + +_list_known() { + local knownfile + knownfile="$(_update_remote_known_list_if_needed)" + + ( + _list_versions 2>/dev/null + cat -- "${knownfile}" + ) | grep . | _version_sort | uniq +} + +# For the "invoked on commandline" case, we want to always pass unknown +# strings through, so that we can be a uniqueness filter, but for unknown +# names we want to exit with a value other than 1, so we document that +# we'll exit 2. For use by other functions, 2 is as good as 1. +_resolve_version() { + case "${1}" in + stable) + _get_curr_stable + return 0 + ;; + oldstable) + _get_old_stable + return 0 + ;; + tip) + echo "tip" + return 0 + ;; + *.x) + true + ;; + *) + echo "${1}" + local GIMME_GO_VERSION="$1" + local ASSERT_ABORT='return' + if _assert_version_given 2>/dev/null; then + return 0 + fi + warn "version specifier '${1}' unknown" + return 2 + ;; + esac + # We have a .x suffix + local base="${1%.x}" + local ver last='' known + known="$(_update_remote_known_list_if_needed)" # will be version-sorted + if [[ ! "${base}" =~ ^[0-9.]+$ ]]; then + warn "resolve pattern '${base}.x' invalid for .x finding" + return 2 + fi + # The `.x` is optional; "1.10" matches "1.10.x" + local search="^${base//./\\.}(\\.[0-9.]+)?\$" + # avoid regexp attacks + while read -r ver; do + [[ "${ver}" =~ $search ]] || continue + last="${ver}" + done <"$known" + if [[ -n "${last}" ]]; then + echo "${last}" + return 0 + fi + echo "${1}" + warn "given '${1}' but no release for '${base}' found" + return 2 +} + +_realpath() { + # shellcheck disable=SC2005 + [ -d "$1" ] && echo "$(cd "$1" && pwd)" || echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" +} + +_get_curr_stable() { + local stable="${GIMME_VERSION_PREFIX}/stable" + + if _file_older_than_secs "${stable}" 86400; then + _update_stable "${stable}" + fi + + cat "${stable}" +} + +_get_old_stable() { + local oldstable="${GIMME_VERSION_PREFIX}/oldstable" + + if _file_older_than_secs "${oldstable}" 86400; then + _update_oldstable "${oldstable}" + fi + + cat "${oldstable}" +} + +_update_stable() { + local stable="${1}" + local url="https://golang.org/VERSION?m=text" + + _do_curl "${url}" "${stable}" + sed -i.old -e 's/^go\(.*\)/\1/' "${stable}" + rm -f "${stable}.old" +} + +_update_oldstable() { + local oldstable="${1}" + local oldstable_x + oldstable_x=$(_get_curr_stable | awk -F. '{ + $2--; + print $1 "." $2 "." "x" + }') + _resolve_version "${oldstable_x}" >"${oldstable}" +} + +_last_mod_timestamp() { + local filename="${1}" + case "${GIMME_HOSTOS}" in + darwin | *bsd) + stat -f %m "${filename}" + ;; + linux) + stat -c %Y "${filename}" + ;; + esac +} + +_file_older_than_secs() { + local file="${1}" + local age_secs="${2}" + local ts + # if the file does not exist, we return true, as the cache needs updating + ts="$(_last_mod_timestamp "${file}" 2>/dev/null)" || return 0 + ((($(date +%s) - ts) > age_secs)) +} + +_assert_version_given() { + # By the time we're called, aliases such as "stable" must have been resolved + # but we could be a reference in git. + # + # Versions can include suffices such as in "1.8beta2", so our assumption is that + # there will always be a minor present; the first public release was "1.0" so + # we assume "2.0" not "2". + + if [[ -z "${GIMME_GO_VERSION}" ]]; then + echo >&2 'error: no GIMME_GO_VERSION supplied' + echo >&2 " ex: GIMME_GO_VERSION=1.4.1 ${0} ${*}" + echo >&2 " ex: ${0} 1.4.1 ${*}" + ${ASSERT_ABORT:-exit} 1 + fi + + # Note: _resolve_version calls back to us (_assert_version_given), but + # only for cases where the version does not end with .x, so this should + # be safe. + # This should be untangled. PRs accepted, good starter project. + if [[ "${GIMME_GO_VERSION}" == *.x ]]; then + GIMME_GO_VERSION="$(_resolve_version "${GIMME_GO_VERSION}")" || ${ASSERT_ABORT:-exit} 1 + fi + + if [[ "${GIMME_GO_VERSION}" == +([[:digit:]]).+([[:digit:]])* ]]; then + return 0 + fi + + # Here we resolve symbolic references. If we don't, then we get some + # random git tag name being accepted as valid and then we try to + # curl garbage from upstream. + if [[ "${GIMME_TYPE}" == "auto" || "${GIMME_TYPE}" == "git" ]]; then + local git_dir="${GIMME_VERSION_PREFIX}/go" + local resolved_sha + _fetch "${git_dir}" + if resolved_sha="$(_checkout "${GIMME_GO_VERSION}" "${git_dir}")"; then + if [[ -n "${resolved_sha}" ]]; then + # Break our normal silence, this one really needs to be seen on stderr + # always; auditability and knowing what version of Go you got wins. + warn "resolved '${GIMME_GO_VERSION}' to '${resolved_sha}'" + GIMME_GO_VERSION="${resolved_sha}" + fi + return 0 + fi + fi + + echo >&2 'error: GIMME_GO_VERSION not recognized as valid' + echo >&2 " got: ${GIMME_GO_VERSION}" + ${ASSERT_ABORT:-exit} 1 +} + +_exclude_from_backups() { + # Please avoid anything which requires elevated privileges or is obnoxious + # enough to offend the invoker + case "${GIMME_HOSTOS}" in + darwin) + # Darwin: Time Machine is "standard", we can add others. The default + # mechanism is sticky, as an attribute on the dir, requires no + # privileges, is idempotent (and doesn't support -- to end flags). + tmutil addexclusion "$@" + ;; + esac +} + +_versint() { + IFS=" " read -r -a args <<<"${1//[^0-9]/ }" + printf '1%03d%03d%03d%03d' "${args[@]}" +} + +_to_goarch() { + case "${1}" in + aarch64) echo "arm64" ;; + *) echo "${1}" ;; + esac +} + +: "${GIMME_OS:=$(uname -s | tr '[:upper:]' '[:lower:]')}" +: "${GIMME_HOSTOS:=$(uname -s | tr '[:upper:]' '[:lower:]')}" +: "${GIMME_ARCH:=$(_to_goarch "$(uname -m)")}" +: "${GIMME_HOSTARCH:=$(_to_goarch "$(uname -m)")}" +: "${GIMME_ENV_PREFIX:=${HOME}/.gimme/envs}" +: "${GIMME_VERSION_PREFIX:=${HOME}/.gimme/versions}" +: "${GIMME_TMP:=${TMPDIR:-/tmp}/gimme}" +: "${GIMME_GO_GIT_REMOTE:=https://github.com/golang/go.git}" +: "${GIMME_TYPE:=auto}" # 'auto', 'binary', 'source', or 'git' +: "${GIMME_BINARY_OSX:=osx10.8}" +: "${GIMME_DOWNLOAD_BASE:=https://dl.google.com/go}" +: "${GIMME_LIST_KNOWN:=https://golang.org/dl}" +: "${GIMME_KNOWN_CACHE_MAX:=10800}" + +# The version prefix must be an absolute path +case "${GIMME_VERSION_PREFIX}" in +/*) true ;; +*) + echo >&2 " Fixing GIMME_VERSION_PREFIX from relative: $GIMME_VERSION_PREFIX" + GIMME_VERSION_PREFIX="$(pwd)/${GIMME_VERSION_PREFIX}" + echo >&2 " to: $GIMME_VERSION_PREFIX" + ;; +esac + +case "${GIMME_OS}" in mingw* | msys_nt*) + # Minimalist GNU for Windows + GIMME_OS='windows' + + if [ "${GIMME_ARCH}" = 'i686' ]; then + GIMME_ARCH="386" + else + GIMME_ARCH="amd64" + fi + ;; +esac + +force_install=0 +force_known_update=0 + +while [[ $# -gt 0 ]]; do + case "${1}" in + -h | --help | help | wat) + _old_ifs="$IFS" + IFS=';' + awk '/^#\+ / { + sub(/^#\+ /, "", $0) ; + sub(/-$/, "", $0) ; + print $0 + }' "$0" | while read -r line; do + eval "echo \"$line\"" + done + IFS="$_old_ifs" + exit 0 + ;; + -V | --version | version) + echo "${GIMME_VERSION}" + exit 0 + ;; + -r | --resolve | resolve) + # The normal mkdir of versions is below; we don't want to move it up + # to where we create files just if asked our version; thus + # _resolve_version has to mkdir the versions dir itself. + if [[ $# -ge 2 ]]; then + _resolve_version "${2}" + elif [[ -n "${GIMME_GO_VERSION:-}" ]]; then + _resolve_version "${GIMME_GO_VERSION}" + else + die "resolve must be given a version to resolve" + fi + exit $? + ;; + -l | --list | list) + _list_versions + exit 0 + ;; + -k | --known | known) + _list_known + exit 0 + ;; + -f | --force | force) + force_install=1 + ;; + --force-known-update | force-known-update) + force_known_update=1 + ;; + -i | install) + true # ignore a dummy argument + ;; + *) + break + ;; + esac + shift +done + +if [[ -n "${1}" ]]; then + GIMME_GO_VERSION="${1}" +fi +if [[ -n "${2}" ]]; then + GIMME_VERSION_PREFIX="${2}" +fi + +case "${GIMME_ARCH}" in +x86_64) GIMME_ARCH=amd64 ;; +x86) GIMME_ARCH=386 ;; +arm64) + if [[ "${GIMME_GO_VERSION}" != master && "$(_versint "${GIMME_GO_VERSION}")" < "$(_versint 1.5)" ]]; then + echo >&2 "error: ${GIMME_ARCH} is not supported by this go version" + echo >&2 "try go1.5 or newer" + exit 1 + fi + if [[ "${GIMME_HOSTOS}" == "linux" && "${GIMME_HOSTARCH}" != "${GIMME_ARCH}" ]]; then + : "${GIMME_CC_FOR_TARGET:="aarch64-linux-gnu-gcc"}" + fi + ;; +arm*) GIMME_ARCH=arm ;; +esac + +case "${GIMME_HOSTARCH}" in +x86_64) GIMME_HOSTARCH=amd64 ;; +x86) GIMME_HOSTARCH=386 ;; +arm64) ;; +arm*) GIMME_HOSTARCH=arm ;; +esac + +case "${GIMME_GO_VERSION}" in +stable) GIMME_GO_VERSION=$(_get_curr_stable) ;; +oldstable) GIMME_GO_VERSION=$(_get_old_stable) ;; +esac + +_assert_version_given "$@" + +((force_install)) && _wipe_version "${GIMME_GO_VERSION}" + +unset GOARCH +unset GOBIN +unset GOOS +unset GOPATH +unset GOROOT +unset CGO_ENABLED +unset CC_FOR_TARGET +# GO111MODULE breaks build of Go itself +unset GO111MODULE + +mkdir -p "${GIMME_VERSION_PREFIX}" "${GIMME_ENV_PREFIX}" +# The envs dir stays small and provides a record of what had been installed +# whereas the versions dir grows by hundreds of MB per version and is not +# intended to support local modifications (as that subverts the point of gimme) +# _and_ is a cache, so we're unilaterally declaring that the contents of +# the versions dir should be excluded from system backups. +_exclude_from_backups "${GIMME_VERSION_PREFIX}" + +GIMME_VERSION_PREFIX="$(_realpath "${GIMME_VERSION_PREFIX}")" +GIMME_ENV_PREFIX="$(_realpath "${GIMME_ENV_PREFIX}")" + +if ! case "${GIMME_TYPE}" in + binary) _try_existing binary || _try_binary "${GIMME_GO_VERSION}" "${GIMME_ARCH}" ;; + source) _try_existing source || _try_source || _try_git ;; + git) _try_git ;; + auto) _try_existing || _try_binary "${GIMME_GO_VERSION}" "${GIMME_ARCH}" || _try_source || _try_git ;; + *) + echo >&2 "I don't know how to '${GIMME_TYPE}'." + echo >&2 " Try 'auto', 'binary', 'source', or 'git'." + exit 1 + ;; + esac; then + echo >&2 "I don't have any idea what to do with '${GIMME_GO_VERSION}'." + echo >&2 " (using download type '${GIMME_TYPE}')" + exit 1 +fi \ No newline at end of file diff --git a/hack/golang/goinstalldir.sh b/hack/golang/goinstalldir.sh new file mode 100644 index 000000000..9c99dd6d1 --- /dev/null +++ b/hack/golang/goinstalldir.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# Copyright 2020 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# this utility prints out the golang install dir, even if go is not installed +# IE it prints the directory where `go install ...` would theoretically place +# binaries + +# if we have go, just ask go! +if which go >/dev/null 2>&1; then + DIR=$(go env GOBIN) + if [ -n "${DIR}" ]; then + echo "${DIR}" + exit 0 + fi + DIR=$(go env GOPATH) + if [ -n "${DIR}" ]; then + echo "${DIR}/bin" + exit 0 + fi +fi + +# mimic go behavior + +# check if GOBIN is set anyhow +if [ -n "${GOBIN}" ]; then + echo "${GOBIN}" + exit 0 +fi + +# check if GOPATH is set anyhow +if [ -n "${GOPATH}" ]; then + echo "${GOPATH}/bin" + exit 0 +fi + +# finally use default for no $GOPATH or $GOBIN +echo "${HOME}/go/bin" \ No newline at end of file diff --git a/hack/golang/gotoolchain.sh b/hack/golang/gotoolchain.sh new file mode 100644 index 000000000..581efc6ed --- /dev/null +++ b/hack/golang/gotoolchain.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Copyright 2020 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# script to set GOTOOLCHAIN as needed +# MUST BE RUN FROM THE REPO ROOT DIRECTORY + +# read go-version file unless GO_VERSION is set +GO_VERSION="${GO_VERSION:-"$(cat .go-version)"}" + +GOTOOLCHAIN="go${GO_VERSION}" +export GOTOOLCHAIN GO_VERSION \ No newline at end of file diff --git a/hack/golang/setup-go.sh b/hack/golang/setup-go.sh new file mode 100644 index 000000000..3f566f0b1 --- /dev/null +++ b/hack/golang/setup-go.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# Copyright 2020 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# script to setup go version with gimme as needed +# MUST BE RUN FROM THE REPO ROOT DIRECTORY + +# read go-version file unless GO_VERSION is set +# override GOTOOLCHAIN unless set as well +. ./hack/golang/gotoolchain.sh + +# we don't actually care where the .env files are +# however, GIMME_SILENT_ENV doesn't trigger re-generating a .env if it +# already exists and isn't "silent" (no `go version` command in it) +# so we fix that by changing where the .env is written, ensuring ours +# is generated from this repo and silent. +export GIMME_ENV_PREFIX=./bin/.gimme/ +export GIMME_SILENT_ENV=y + +# only setup go if we haven't set FORCE_HOST_GO, or `go version` doesn't match +# go version output looks like: +# go version go1.14.5 darwin/amd64 +if ! ([ -n "${FORCE_HOST_GO:-}" ] || \ + (command -v go >/dev/null && [ "$(go version | cut -d' ' -f3)" = "go${GO_VERSION}" ])); then + # eval because the output of this is shell to set PATH etc. + eval "$(hack/gimme/gimme "${GO_VERSION}")" +fi + +# force go modules +export GO111MODULE=on \ No newline at end of file From a42c0a79f3ca629e9c89cf74c3b097f75b1f20ae Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 26 Apr 2025 12:25:11 +0300 Subject: [PATCH 2/3] Use Gimme to automatically install the correct Go version --- .github/workflows/build.yaml | 5 ----- .github/workflows/compatibility-tests.yaml | 5 ----- .github/workflows/doc-check.yaml | 5 ----- .github/workflows/istio-tests.yaml | 5 ----- .github/workflows/k3d-tests.yaml | 5 ----- .github/workflows/k8s-matrix.yaml | 5 ----- .github/workflows/minikube-matrix.yaml | 5 ----- .github/workflows/prometheus-tests.yaml | 5 ----- .github/workflows/release.yml | 5 ----- .github/workflows/tanzu-tests.yaml | 5 ----- .github/workflows/trivy.yaml | 5 ----- 11 files changed, 55 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 030698269..6c7993691 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -72,11 +72,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/compatibility-tests.yaml b/.github/workflows/compatibility-tests.yaml index ab53b5186..f3e0e85b1 100644 --- a/.github/workflows/compatibility-tests.yaml +++ b/.github/workflows/compatibility-tests.yaml @@ -117,11 +117,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/doc-check.yaml b/.github/workflows/doc-check.yaml index 5ceaea536..8e7bb8ed6 100644 --- a/.github/workflows/doc-check.yaml +++ b/.github/workflows/doc-check.yaml @@ -36,11 +36,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/istio-tests.yaml b/.github/workflows/istio-tests.yaml index 599927a4a..1a05d0844 100644 --- a/.github/workflows/istio-tests.yaml +++ b/.github/workflows/istio-tests.yaml @@ -78,11 +78,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/k3d-tests.yaml b/.github/workflows/k3d-tests.yaml index c7bbe3188..1947a6f74 100644 --- a/.github/workflows/k3d-tests.yaml +++ b/.github/workflows/k3d-tests.yaml @@ -68,11 +68,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/k8s-matrix.yaml b/.github/workflows/k8s-matrix.yaml index 15d8bb15e..8ec1affe1 100644 --- a/.github/workflows/k8s-matrix.yaml +++ b/.github/workflows/k8s-matrix.yaml @@ -110,11 +110,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/minikube-matrix.yaml b/.github/workflows/minikube-matrix.yaml index bb860c5e2..11e04cc73 100644 --- a/.github/workflows/minikube-matrix.yaml +++ b/.github/workflows/minikube-matrix.yaml @@ -87,11 +87,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/prometheus-tests.yaml b/.github/workflows/prometheus-tests.yaml index 7e2950f83..64cb792e5 100644 --- a/.github/workflows/prometheus-tests.yaml +++ b/.github/workflows/prometheus-tests.yaml @@ -68,11 +68,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 435d79f3b..5a785668f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,11 +31,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/tanzu-tests.yaml b/.github/workflows/tanzu-tests.yaml index 523966e3f..8eabd809e 100644 --- a/.github/workflows/tanzu-tests.yaml +++ b/.github/workflows/tanzu-tests.yaml @@ -72,11 +72,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml index ee6ea95a2..9e9a7aa92 100644 --- a/.github/workflows/trivy.yaml +++ b/.github/workflows/trivy.yaml @@ -36,11 +36,6 @@ jobs: website: oracle.com release: 21 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - name: Cache Go Modules uses: actions/cache@v4 with: From 8a170c60cc7e89f86012397b271877077a153657 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Sat, 26 Apr 2025 13:35:27 +0300 Subject: [PATCH 3/3] Fix copyright exclusions --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 17463a74a..0f4bfafac 100644 --- a/Makefile +++ b/Makefile @@ -902,6 +902,7 @@ copyright: ## Check copyright headers -X .factories \ -X hack/codestyle/copyright.txt \ -X hack/codestyle/intellij-codestyle.xml \ + -X hack/gimme/ \ -X hack/install-cohctl.sh \ -X hack/istio- \ -X hack/sdk/ \