#!/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= # Ignore the error from read, which may error if the mark file does not contain a line end. read -r extracted < "$mark" || true 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}" "$@"