diff --git a/build_dist.sh b/build_dist.sh index 1fcf41aed..1ba6ad3c0 100755 --- a/build_dist.sh +++ b/build_dist.sh @@ -45,4 +45,4 @@ EOF exit 0 fi -exec go build -ldflags "-X tailscale.com/version.Long=${LONG} -X tailscale.com/version.Short=${SHORT} -X tailscale.com/version.GitCommit=${GIT_HASH}" "$@" +exec ./tool/go build -ldflags "-X tailscale.com/version.Long=${LONG} -X tailscale.com/version.Short=${SHORT} -X tailscale.com/version.GitCommit=${GIT_HASH}" "$@" diff --git a/build_docker.sh b/build_docker.sh index 8c71f584c..c2a8e7110 100755 --- a/build_docker.sh +++ b/build_docker.sh @@ -19,6 +19,9 @@ set -eu +# Use the "go" binary from the "tool" directory (which is github.com/tailscale/go) +export PATH=$PWD/tool:$PATH + eval $(./build_dist.sh shellvars) DEFAULT_TAGS="v${VERSION_SHORT},v${VERSION_MINOR}" DEFAULT_REPOS="tailscale/tailscale,ghcr.io/tailscale/tailscale" diff --git a/tool/go b/tool/go new file mode 100755 index 000000000..8f7485f92 --- /dev/null +++ b/tool/go @@ -0,0 +1,89 @@ +#!/bin/sh +# +# This script acts like the "go" command, but uses Tailscale's +# currently-desired version from https://github.com/tailscale/go, +# downloading it first if necessary. + +set -eu + +log() { + echo "$@" >&2 +} + +DEFAULT_TOOLCHAIN_DIR="${HOME}/.cache/tailscale-go" +TOOLCHAIN="${TOOLCHAIN-${DEFAULT_TOOLCHAIN_DIR}}" +TOOLCHAIN_GO="${TOOLCHAIN}/bin/go" +read -r REV < "$(dirname "$0")/../go.toolchain.rev" + +# Fast, quiet path, when Tailscale is already current. +if [ -e "${TOOLCHAIN_GO}" ]; then + short_hash=$("${TOOLCHAIN_GO}" version | sed 's/.*-ts//; s/ .*//') + case $REV in + "$short_hash"*) + unset GOROOT + exec "${TOOLCHAIN_GO}" "$@" + esac +fi + +# This works for linux and darwin, which is sufficient +# (we do not build tailscale-go for other targets). +GOOS=$(uname -s | tr A-Z a-z) +ARCH="$(uname -m)" +if [ "$ARCH" = "aarch64" ]; then + # Go uses the name "arm64". + ARCH="arm64" +elif [ "$ARCH" = "x86_64" ]; then + # Go uses the name "amd64". + ARCH="amd64" +fi + +get_cached() { + if [ ! -d "$TOOLCHAIN" ]; then + mkdir -p "$TOOLCHAIN" + fi + + archive="$TOOLCHAIN-$REV.tar.gz" + mark="$TOOLCHAIN.extracted" + extracted= + [ ! -e "$mark" ] || read -r extracted junk <$mark + + if [ "$extracted" = "$REV" ] && [ -e "${TOOLCHAIN_GO}" ]; then + # already ok + log "Go toolchain '$REV' already extracted." + return 0 + fi + + rm -f "$archive.new" "$TOOLCHAIN.extracted" + if [ ! -e "$archive" ]; then + log "Need to download go '$REV'." + if [ "$ARCH" = "amd64" ]; then + # For historic reasons, the tailscale/go amd64 release artifacts don't + # have the arch in their name. + BUILD="$GOOS" + else + BUILD="$GOOS-$ARCH" + fi + curl -f -L -o "$archive.new" "https://github.com/tailscale/go/releases/download/build-${REV}/${BUILD}.tar.gz" + rm -f "$archive" + mv "$archive.new" "$archive" + fi + + log "Extracting tailscale/go rev '$REV'" >&2 + log " into '$TOOLCHAIN'." >&2 + rm -rf "$TOOLCHAIN" + mkdir -p "$TOOLCHAIN" + (cd "$TOOLCHAIN" && tar --strip-components=1 -xf "$archive") + echo "$REV" >$mark +} + +if [ "${REV}" = "SKIP" ] || + [ "${GOOS}" != "darwin" -a "${GOOS}" != "linux" ] || + [ "${ARCH}" != "amd64" -a "${ARCH}" != "arm64" ]; then + # Use whichever go is available + exec go "$@" +else + get_cached +fi + +unset GOROOT +exec "${TOOLCHAIN_GO}" "$@" \ No newline at end of file