From 9b085657641c556de10b3c3b8850d50e3c88cdf6 Mon Sep 17 00:00:00 2001 From: Tianon Gravi Date: Tue, 9 Jan 2024 16:34:58 -0800 Subject: [PATCH] Add "tip" version This is pinned to the latest commit merged upstream before midnight (UTC) on Monday of the current week. --- Dockerfile-linux.template | 67 ++++++++++++++++- generate-stackbrew-library.sh | 2 - tip/alpine3.19/Dockerfile | 127 ++++++++++++++++++++++++++++++++ tip/alpine3.20/Dockerfile | 127 ++++++++++++++++++++++++++++++++ tip/bookworm/Dockerfile | 134 ++++++++++++++++++++++++++++++++++ tip/bullseye/Dockerfile | 134 ++++++++++++++++++++++++++++++++++ versions.json | 106 ++++++++++++++++++++++++++- versions.sh | 125 +++++++++++++++++++++++++------ 8 files changed, 794 insertions(+), 28 deletions(-) create mode 100644 tip/alpine3.19/Dockerfile create mode 100644 tip/alpine3.20/Dockerfile create mode 100644 tip/bookworm/Dockerfile create mode 100644 tip/bullseye/Dockerfile diff --git a/Dockerfile-linux.template b/Dockerfile-linux.template index 9c2fb247..324adb4d 100644 --- a/Dockerfile-linux.template +++ b/Dockerfile-linux.template @@ -13,7 +13,15 @@ FROM buildpack-deps:{{ env.variant }}-scm AS build ENV PATH /usr/local/go/bin:$PATH +{{ if env.version != "tip" then ( -}} ENV GOLANG_VERSION {{ .version }} +{{ ) else ( -}} +COPY --from=golang:{{ env.variant }} /usr/local/go /usr/local/goroot-bootstrap + +# {{ .version }}: https://github.com/golang/go/tree/{{ .commit.version }} +ARG GOLANG_COMMIT={{ .commit.version | @sh }} +ENV GOLANG_COMMIT $GOLANG_COMMIT +{{ ) end -}} {{ def os_arches: @@ -54,16 +62,23 @@ RUN set -eux; \ now="$(date '+%s')"; \ {{ if is_alpine then ( -}} apk add --no-cache --virtual .fetch-deps \ +{{ if env.version != "tip" then ( -}} ca-certificates \ gnupg \ # busybox's "tar" doesn't handle directory mtime correctly, so our SOURCE_DATE_EPOCH lookup doesn't work (the mtime of "/usr/local/go" always ends up being the extraction timestamp) tar \ +{{ ) else ( -}} + bash \ + git \ +{{ ) end -}} ; \ arch="$(apk --print-arch)"; \ {{ ) else ( -}} arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \ {{ ) end -}} +{{ if env.version != "tip" then ( -}} url=; \ +{{ ) else "" end -}} case "$arch" in \ {{ [ @@ -78,8 +93,12 @@ RUN set -eux; \ | ( -}} {{ $osArch | @sh }}) \ +{{ if env.version != "tip" then ( -}} url={{ .url | @sh }}; \ sha256={{ .sha256 | @sh }}; \ +{{ ) else ( -}} + export {{ .env | to_entries | sort_by(.key) | map(.key + "=" + (.value | @sh)) | join(" ") }}; \ +{{ ) end -}} ;; \ {{ ) @@ -88,6 +107,7 @@ RUN set -eux; \ *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ esac; \ \ +{{ if env.version != "tip" then ( -}} wget -O go.tgz.asc "$url.asc"; \ wget -O go.tgz "$url"{{ if is_alpine then "" else " --progress=dot:giga" end }}; \ echo "$sha256 *go.tgz" | sha256sum -c -; \ @@ -107,6 +127,19 @@ RUN set -eux; \ \ # save the timestamp from the tarball so we can restore it for reproducibility, if necessary (see below) SOURCE_DATE_EPOCH="$(stat -c '%Y' /usr/local/go)"; \ +{{ ) else ( -}} +# before we get too far, let's validate that our "bootstrap" Go works + export GOROOT_BOOTSTRAP=/usr/local/goroot-bootstrap; \ +# TODO figure out why QEMU's user-mode emulation with Go 1.23.0 causes "can't start telemetry child process: fork/exec /usr/local/go/bin/go: invalid argument" (it works if we run it a second time, but then later "go build" fails to fork/exec the compile process πŸ™ƒ) + "$GOROOT_BOOTSTRAP/bin/go" version; \ + \ + git init --quiet /usr/local/go; \ + git -C /usr/local/go fetch --depth 1 https://github.com/golang/go.git "$GOLANG_COMMIT:"; \ + git -C /usr/local/go checkout --quiet FETCH_HEAD; \ + \ +# save the Git timestamp so we can use it for reproducibility + SOURCE_DATE_EPOCH="$(git -C /usr/local/go log -1 --format='format:%ct' HEAD)"; \ +{{ ) end -}} export SOURCE_DATE_EPOCH; \ touchy="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ # for logging validation/edification @@ -114,7 +147,37 @@ RUN set -eux; \ # sanity check (detected value should be older than our wall clock) [ "$SOURCE_DATE_EPOCH" -lt "$now" ]; \ \ -{{ if .arches["arm32v7"].url // "" | contains("armv6") then ( -}} +{{ if env.version == "tip" then ( -}} + ( \ + export \ + GOCACHE='/tmp/gocache' \ +# set GOHOST* to make sure explicitly 32bit builds on 64bit infra work correctly + GOHOSTOS="$GOOS" \ + GOHOSTARCH="$GOARCH" \ + ; \ + \ + cd /usr/local/go/src; \ + ./make.bash; \ + \ +# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain (and ".git" that is hard to make reproducible) + rm -rf \ + /usr/local/go/.git* \ + /usr/local/go/pkg/*/cmd \ + /usr/local/go/pkg/bootstrap \ + /usr/local/go/pkg/obj \ + /usr/local/go/pkg/tool/*/api \ + /usr/local/go/pkg/tool/*/go_bootstrap \ + /usr/local/go/src/cmd/dist/dist \ + "$GOCACHE" \ + ; \ + \ +# clamp timestamps for reproducibility (allows "COPY --link" to be more clever/useful) + touch -t "$touchy" /usr/local/.go-date-stamp; \ + find /usr/local/go -depth -newer /usr/local/.go-date-stamp -exec touch -ht "$touchy" '{}' +; \ + rm /usr/local/.go-date-stamp; \ + ); \ + \ +{{ ) elif .arches["arm32v7"].url // "" | contains("armv6") then ( -}} if [ "$arch" = {{ os_arches["arm32v7"] | @sh }} ]; then \ [ -s /usr/local/go/go.env ]; \ before="$(go env GOARM)"; [ "$before" != {{ .arches["arm32v7"].env["GOARM"] | @sh }} ]; \ @@ -166,8 +229,10 @@ RUN set -eux; \ rm -rf /var/lib/apt/lists/* {{ ) end -}} +{{ if env.version != "tip" then ( -}} ENV GOLANG_VERSION {{ .version }} +{{ ) else "" end -}} # don't auto-upgrade the gotoolchain # https://github.com/docker-library/golang/issues/472 ENV GOTOOLCHAIN=local diff --git a/generate-stackbrew-library.sh b/generate-stackbrew-library.sh index b3562c81..18517e1f 100755 --- a/generate-stackbrew-library.sh +++ b/generate-stackbrew-library.sh @@ -111,8 +111,6 @@ for version; do fullVersion="$(jq -r '.[env.version].version' versions.json)" - [[ "$fullVersion" == *.*[^0-9]* ]] || fullVersion+='.0' - if [ "$version" = "$fullVersion" ]; then baseAliases=( "${versionAliases[@]}" ) else diff --git a/tip/alpine3.19/Dockerfile b/tip/alpine3.19/Dockerfile new file mode 100644 index 00000000..f909108e --- /dev/null +++ b/tip/alpine3.19/Dockerfile @@ -0,0 +1,127 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM alpine:3.19 AS build + +ENV PATH /usr/local/go/bin:$PATH + +COPY --from=golang:alpine3.19 /usr/local/go /usr/local/goroot-bootstrap + +# tip-20240810: https://github.com/golang/go/tree/d36353499f673c89a267a489beb80133a14a75f9 +ARG GOLANG_COMMIT='d36353499f673c89a267a489beb80133a14a75f9' +ENV GOLANG_COMMIT $GOLANG_COMMIT + +RUN set -eux; \ + now="$(date '+%s')"; \ + apk add --no-cache --virtual .fetch-deps \ + bash \ + git \ + ; \ + arch="$(apk --print-arch)"; \ + case "$arch" in \ + 'x86_64') \ + export GOAMD64='v1' GOARCH='amd64' GOOS='linux'; \ + ;; \ + 'armhf') \ + export GOARCH='arm' GOARM='6' GOOS='linux'; \ + ;; \ + 'armv7') \ + export GOARCH='arm' GOARM='7' GOOS='linux'; \ + ;; \ + 'aarch64') \ + export GOARCH='arm64' GOARM64='v8.0' GOOS='linux'; \ + ;; \ + 'x86') \ + export GO386='softfloat' GOARCH='386' GOOS='linux'; \ + ;; \ + 'ppc64le') \ + export GOARCH='ppc64le' GOOS='linux'; \ + ;; \ + 'riscv64') \ + export GOARCH='riscv64' GOOS='linux' GORISCV64='rva20u64'; \ + ;; \ + 's390x') \ + export GOARCH='s390x' GOOS='linux'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ + esac; \ + \ +# before we get too far, let's validate that our "bootstrap" Go works + export GOROOT_BOOTSTRAP=/usr/local/goroot-bootstrap; \ +# TODO figure out why QEMU's user-mode emulation with Go 1.23.0 causes "can't start telemetry child process: fork/exec /usr/local/go/bin/go: invalid argument" (it works if we run it a second time, but then later "go build" fails to fork/exec the compile process πŸ™ƒ) + "$GOROOT_BOOTSTRAP/bin/go" version; \ + \ + git init --quiet /usr/local/go; \ + git -C /usr/local/go fetch --depth 1 https://github.com/golang/go.git "$GOLANG_COMMIT:"; \ + git -C /usr/local/go checkout --quiet FETCH_HEAD; \ + \ +# save the Git timestamp so we can use it for reproducibility + SOURCE_DATE_EPOCH="$(git -C /usr/local/go log -1 --format='format:%ct' HEAD)"; \ + export SOURCE_DATE_EPOCH; \ + touchy="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ +# for logging validation/edification + date --date "@$SOURCE_DATE_EPOCH" --rfc-2822; \ +# sanity check (detected value should be older than our wall clock) + [ "$SOURCE_DATE_EPOCH" -lt "$now" ]; \ + \ + ( \ + export \ + GOCACHE='/tmp/gocache' \ +# set GOHOST* to make sure explicitly 32bit builds on 64bit infra work correctly + GOHOSTOS="$GOOS" \ + GOHOSTARCH="$GOARCH" \ + ; \ + \ + cd /usr/local/go/src; \ + ./make.bash; \ + \ +# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain (and ".git" that is hard to make reproducible) + rm -rf \ + /usr/local/go/.git* \ + /usr/local/go/pkg/*/cmd \ + /usr/local/go/pkg/bootstrap \ + /usr/local/go/pkg/obj \ + /usr/local/go/pkg/tool/*/api \ + /usr/local/go/pkg/tool/*/go_bootstrap \ + /usr/local/go/src/cmd/dist/dist \ + "$GOCACHE" \ + ; \ + \ +# clamp timestamps for reproducibility (allows "COPY --link" to be more clever/useful) + touch -t "$touchy" /usr/local/.go-date-stamp; \ + find /usr/local/go -depth -newer /usr/local/.go-date-stamp -exec touch -ht "$touchy" '{}' +; \ + rm /usr/local/.go-date-stamp; \ + ); \ + \ +# ideally at this point, we would just "COPY --link ... /usr/local/go/ /usr/local/go/" but BuildKit insists on creating the parent directories (perhaps related to https://github.com/opencontainers/image-spec/pull/970), and does so with unreproducible timestamps, so we instead create a whole new "directory tree" that we can "COPY --link" to accomplish what we want + mkdir /target /target/usr /target/usr/local; \ + mv -vT /usr/local/go /target/usr/local/go; \ + ln -svfT /target/usr/local/go /usr/local/go; \ + touch -t "$touchy" /target/usr/local /target/usr /target; \ + \ + apk del --no-network .fetch-deps; \ + \ +# smoke test + go version; \ +# make sure our reproducibile timestamp is probably still correct (best-effort inline reproducibility test) + epoch="$(stat -c '%Y' /target/usr/local/go)"; \ + [ "$SOURCE_DATE_EPOCH" = "$epoch" ]; \ + find /target -newer /target/usr/local/go -exec sh -c 'ls -ld "$@" && exit "$#"' -- '{}' + + +FROM alpine:3.19 + +RUN apk add --no-cache ca-certificates + +# don't auto-upgrade the gotoolchain +# https://github.com/docker-library/golang/issues/472 +ENV GOTOOLCHAIN=local + +ENV GOPATH /go +ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH +# (see notes above about "COPY --link") +COPY --from=build --link /target/ / +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH" +WORKDIR $GOPATH diff --git a/tip/alpine3.20/Dockerfile b/tip/alpine3.20/Dockerfile new file mode 100644 index 00000000..dcfa16ee --- /dev/null +++ b/tip/alpine3.20/Dockerfile @@ -0,0 +1,127 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM alpine:3.20 AS build + +ENV PATH /usr/local/go/bin:$PATH + +COPY --from=golang:alpine3.20 /usr/local/go /usr/local/goroot-bootstrap + +# tip-20240810: https://github.com/golang/go/tree/d36353499f673c89a267a489beb80133a14a75f9 +ARG GOLANG_COMMIT='d36353499f673c89a267a489beb80133a14a75f9' +ENV GOLANG_COMMIT $GOLANG_COMMIT + +RUN set -eux; \ + now="$(date '+%s')"; \ + apk add --no-cache --virtual .fetch-deps \ + bash \ + git \ + ; \ + arch="$(apk --print-arch)"; \ + case "$arch" in \ + 'x86_64') \ + export GOAMD64='v1' GOARCH='amd64' GOOS='linux'; \ + ;; \ + 'armhf') \ + export GOARCH='arm' GOARM='6' GOOS='linux'; \ + ;; \ + 'armv7') \ + export GOARCH='arm' GOARM='7' GOOS='linux'; \ + ;; \ + 'aarch64') \ + export GOARCH='arm64' GOARM64='v8.0' GOOS='linux'; \ + ;; \ + 'x86') \ + export GO386='softfloat' GOARCH='386' GOOS='linux'; \ + ;; \ + 'ppc64le') \ + export GOARCH='ppc64le' GOOS='linux'; \ + ;; \ + 'riscv64') \ + export GOARCH='riscv64' GOOS='linux' GORISCV64='rva20u64'; \ + ;; \ + 's390x') \ + export GOARCH='s390x' GOOS='linux'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ + esac; \ + \ +# before we get too far, let's validate that our "bootstrap" Go works + export GOROOT_BOOTSTRAP=/usr/local/goroot-bootstrap; \ +# TODO figure out why QEMU's user-mode emulation with Go 1.23.0 causes "can't start telemetry child process: fork/exec /usr/local/go/bin/go: invalid argument" (it works if we run it a second time, but then later "go build" fails to fork/exec the compile process πŸ™ƒ) + "$GOROOT_BOOTSTRAP/bin/go" version; \ + \ + git init --quiet /usr/local/go; \ + git -C /usr/local/go fetch --depth 1 https://github.com/golang/go.git "$GOLANG_COMMIT:"; \ + git -C /usr/local/go checkout --quiet FETCH_HEAD; \ + \ +# save the Git timestamp so we can use it for reproducibility + SOURCE_DATE_EPOCH="$(git -C /usr/local/go log -1 --format='format:%ct' HEAD)"; \ + export SOURCE_DATE_EPOCH; \ + touchy="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ +# for logging validation/edification + date --date "@$SOURCE_DATE_EPOCH" --rfc-2822; \ +# sanity check (detected value should be older than our wall clock) + [ "$SOURCE_DATE_EPOCH" -lt "$now" ]; \ + \ + ( \ + export \ + GOCACHE='/tmp/gocache' \ +# set GOHOST* to make sure explicitly 32bit builds on 64bit infra work correctly + GOHOSTOS="$GOOS" \ + GOHOSTARCH="$GOARCH" \ + ; \ + \ + cd /usr/local/go/src; \ + ./make.bash; \ + \ +# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain (and ".git" that is hard to make reproducible) + rm -rf \ + /usr/local/go/.git* \ + /usr/local/go/pkg/*/cmd \ + /usr/local/go/pkg/bootstrap \ + /usr/local/go/pkg/obj \ + /usr/local/go/pkg/tool/*/api \ + /usr/local/go/pkg/tool/*/go_bootstrap \ + /usr/local/go/src/cmd/dist/dist \ + "$GOCACHE" \ + ; \ + \ +# clamp timestamps for reproducibility (allows "COPY --link" to be more clever/useful) + touch -t "$touchy" /usr/local/.go-date-stamp; \ + find /usr/local/go -depth -newer /usr/local/.go-date-stamp -exec touch -ht "$touchy" '{}' +; \ + rm /usr/local/.go-date-stamp; \ + ); \ + \ +# ideally at this point, we would just "COPY --link ... /usr/local/go/ /usr/local/go/" but BuildKit insists on creating the parent directories (perhaps related to https://github.com/opencontainers/image-spec/pull/970), and does so with unreproducible timestamps, so we instead create a whole new "directory tree" that we can "COPY --link" to accomplish what we want + mkdir /target /target/usr /target/usr/local; \ + mv -vT /usr/local/go /target/usr/local/go; \ + ln -svfT /target/usr/local/go /usr/local/go; \ + touch -t "$touchy" /target/usr/local /target/usr /target; \ + \ + apk del --no-network .fetch-deps; \ + \ +# smoke test + go version; \ +# make sure our reproducibile timestamp is probably still correct (best-effort inline reproducibility test) + epoch="$(stat -c '%Y' /target/usr/local/go)"; \ + [ "$SOURCE_DATE_EPOCH" = "$epoch" ]; \ + find /target -newer /target/usr/local/go -exec sh -c 'ls -ld "$@" && exit "$#"' -- '{}' + + +FROM alpine:3.20 + +RUN apk add --no-cache ca-certificates + +# don't auto-upgrade the gotoolchain +# https://github.com/docker-library/golang/issues/472 +ENV GOTOOLCHAIN=local + +ENV GOPATH /go +ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH +# (see notes above about "COPY --link") +COPY --from=build --link /target/ / +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH" +WORKDIR $GOPATH diff --git a/tip/bookworm/Dockerfile b/tip/bookworm/Dockerfile new file mode 100644 index 00000000..c7e47f24 --- /dev/null +++ b/tip/bookworm/Dockerfile @@ -0,0 +1,134 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM buildpack-deps:bookworm-scm AS build + +ENV PATH /usr/local/go/bin:$PATH + +COPY --from=golang:bookworm /usr/local/go /usr/local/goroot-bootstrap + +# tip-20240810: https://github.com/golang/go/tree/d36353499f673c89a267a489beb80133a14a75f9 +ARG GOLANG_COMMIT='d36353499f673c89a267a489beb80133a14a75f9' +ENV GOLANG_COMMIT $GOLANG_COMMIT + +RUN set -eux; \ + now="$(date '+%s')"; \ + arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \ + case "$arch" in \ + 'amd64') \ + export GOAMD64='v1' GOARCH='amd64' GOOS='linux'; \ + ;; \ + 'armel') \ + export GOARCH='arm' GOARM='5' GOOS='linux'; \ + ;; \ + 'armhf') \ + export GOARCH='arm' GOARM='7' GOOS='linux'; \ + ;; \ + 'arm64') \ + export GOARCH='arm64' GOARM64='v8.0' GOOS='linux'; \ + ;; \ + 'i386') \ + export GO386='softfloat' GOARCH='386' GOOS='linux'; \ + ;; \ + 'mips64el') \ + export GOARCH='mips64le' GOOS='linux'; \ + ;; \ + 'ppc64el') \ + export GOARCH='ppc64le' GOOS='linux'; \ + ;; \ + 'riscv64') \ + export GOARCH='riscv64' GOOS='linux' GORISCV64='rva20u64'; \ + ;; \ + 's390x') \ + export GOARCH='s390x' GOOS='linux'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ + esac; \ + \ +# before we get too far, let's validate that our "bootstrap" Go works + export GOROOT_BOOTSTRAP=/usr/local/goroot-bootstrap; \ +# TODO figure out why QEMU's user-mode emulation with Go 1.23.0 causes "can't start telemetry child process: fork/exec /usr/local/go/bin/go: invalid argument" (it works if we run it a second time, but then later "go build" fails to fork/exec the compile process πŸ™ƒ) + "$GOROOT_BOOTSTRAP/bin/go" version; \ + \ + git init --quiet /usr/local/go; \ + git -C /usr/local/go fetch --depth 1 https://github.com/golang/go.git "$GOLANG_COMMIT:"; \ + git -C /usr/local/go checkout --quiet FETCH_HEAD; \ + \ +# save the Git timestamp so we can use it for reproducibility + SOURCE_DATE_EPOCH="$(git -C /usr/local/go log -1 --format='format:%ct' HEAD)"; \ + export SOURCE_DATE_EPOCH; \ + touchy="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ +# for logging validation/edification + date --date "@$SOURCE_DATE_EPOCH" --rfc-2822; \ +# sanity check (detected value should be older than our wall clock) + [ "$SOURCE_DATE_EPOCH" -lt "$now" ]; \ + \ + ( \ + export \ + GOCACHE='/tmp/gocache' \ +# set GOHOST* to make sure explicitly 32bit builds on 64bit infra work correctly + GOHOSTOS="$GOOS" \ + GOHOSTARCH="$GOARCH" \ + ; \ + \ + cd /usr/local/go/src; \ + ./make.bash; \ + \ +# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain (and ".git" that is hard to make reproducible) + rm -rf \ + /usr/local/go/.git* \ + /usr/local/go/pkg/*/cmd \ + /usr/local/go/pkg/bootstrap \ + /usr/local/go/pkg/obj \ + /usr/local/go/pkg/tool/*/api \ + /usr/local/go/pkg/tool/*/go_bootstrap \ + /usr/local/go/src/cmd/dist/dist \ + "$GOCACHE" \ + ; \ + \ +# clamp timestamps for reproducibility (allows "COPY --link" to be more clever/useful) + touch -t "$touchy" /usr/local/.go-date-stamp; \ + find /usr/local/go -depth -newer /usr/local/.go-date-stamp -exec touch -ht "$touchy" '{}' +; \ + rm /usr/local/.go-date-stamp; \ + ); \ + \ +# ideally at this point, we would just "COPY --link ... /usr/local/go/ /usr/local/go/" but BuildKit insists on creating the parent directories (perhaps related to https://github.com/opencontainers/image-spec/pull/970), and does so with unreproducible timestamps, so we instead create a whole new "directory tree" that we can "COPY --link" to accomplish what we want + mkdir /target /target/usr /target/usr/local; \ + mv -vT /usr/local/go /target/usr/local/go; \ + ln -svfT /target/usr/local/go /usr/local/go; \ + touch -t "$touchy" /target/usr/local /target/usr /target; \ + \ +# smoke test + go version; \ +# make sure our reproducibile timestamp is probably still correct (best-effort inline reproducibility test) + epoch="$(stat -c '%Y' /target/usr/local/go)"; \ + [ "$SOURCE_DATE_EPOCH" = "$epoch" ]; \ + find /target -newer /target/usr/local/go -exec sh -c 'ls -ld "$@" && exit "$#"' -- '{}' + + +FROM buildpack-deps:bookworm-scm + +# install cgo-related dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + g++ \ + gcc \ + libc6-dev \ + make \ + pkg-config \ + ; \ + rm -rf /var/lib/apt/lists/* + +# don't auto-upgrade the gotoolchain +# https://github.com/docker-library/golang/issues/472 +ENV GOTOOLCHAIN=local + +ENV GOPATH /go +ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH +# (see notes above about "COPY --link") +COPY --from=build --link /target/ / +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH" +WORKDIR $GOPATH diff --git a/tip/bullseye/Dockerfile b/tip/bullseye/Dockerfile new file mode 100644 index 00000000..36979832 --- /dev/null +++ b/tip/bullseye/Dockerfile @@ -0,0 +1,134 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + +FROM buildpack-deps:bullseye-scm AS build + +ENV PATH /usr/local/go/bin:$PATH + +COPY --from=golang:bullseye /usr/local/go /usr/local/goroot-bootstrap + +# tip-20240810: https://github.com/golang/go/tree/d36353499f673c89a267a489beb80133a14a75f9 +ARG GOLANG_COMMIT='d36353499f673c89a267a489beb80133a14a75f9' +ENV GOLANG_COMMIT $GOLANG_COMMIT + +RUN set -eux; \ + now="$(date '+%s')"; \ + arch="$(dpkg --print-architecture)"; arch="${arch##*-}"; \ + case "$arch" in \ + 'amd64') \ + export GOAMD64='v1' GOARCH='amd64' GOOS='linux'; \ + ;; \ + 'armel') \ + export GOARCH='arm' GOARM='5' GOOS='linux'; \ + ;; \ + 'armhf') \ + export GOARCH='arm' GOARM='7' GOOS='linux'; \ + ;; \ + 'arm64') \ + export GOARCH='arm64' GOARM64='v8.0' GOOS='linux'; \ + ;; \ + 'i386') \ + export GO386='softfloat' GOARCH='386' GOOS='linux'; \ + ;; \ + 'mips64el') \ + export GOARCH='mips64le' GOOS='linux'; \ + ;; \ + 'ppc64el') \ + export GOARCH='ppc64le' GOOS='linux'; \ + ;; \ + 'riscv64') \ + export GOARCH='riscv64' GOOS='linux' GORISCV64='rva20u64'; \ + ;; \ + 's390x') \ + export GOARCH='s390x' GOOS='linux'; \ + ;; \ + *) echo >&2 "error: unsupported architecture '$arch' (likely packaging update needed)"; exit 1 ;; \ + esac; \ + \ +# before we get too far, let's validate that our "bootstrap" Go works + export GOROOT_BOOTSTRAP=/usr/local/goroot-bootstrap; \ +# TODO figure out why QEMU's user-mode emulation with Go 1.23.0 causes "can't start telemetry child process: fork/exec /usr/local/go/bin/go: invalid argument" (it works if we run it a second time, but then later "go build" fails to fork/exec the compile process πŸ™ƒ) + "$GOROOT_BOOTSTRAP/bin/go" version; \ + \ + git init --quiet /usr/local/go; \ + git -C /usr/local/go fetch --depth 1 https://github.com/golang/go.git "$GOLANG_COMMIT:"; \ + git -C /usr/local/go checkout --quiet FETCH_HEAD; \ + \ +# save the Git timestamp so we can use it for reproducibility + SOURCE_DATE_EPOCH="$(git -C /usr/local/go log -1 --format='format:%ct' HEAD)"; \ + export SOURCE_DATE_EPOCH; \ + touchy="$(date -d "@$SOURCE_DATE_EPOCH" '+%Y%m%d%H%M.%S')"; \ +# for logging validation/edification + date --date "@$SOURCE_DATE_EPOCH" --rfc-2822; \ +# sanity check (detected value should be older than our wall clock) + [ "$SOURCE_DATE_EPOCH" -lt "$now" ]; \ + \ + ( \ + export \ + GOCACHE='/tmp/gocache' \ +# set GOHOST* to make sure explicitly 32bit builds on 64bit infra work correctly + GOHOSTOS="$GOOS" \ + GOHOSTARCH="$GOARCH" \ + ; \ + \ + cd /usr/local/go/src; \ + ./make.bash; \ + \ +# remove a few intermediate / bootstrapping files the official binary release tarballs do not contain (and ".git" that is hard to make reproducible) + rm -rf \ + /usr/local/go/.git* \ + /usr/local/go/pkg/*/cmd \ + /usr/local/go/pkg/bootstrap \ + /usr/local/go/pkg/obj \ + /usr/local/go/pkg/tool/*/api \ + /usr/local/go/pkg/tool/*/go_bootstrap \ + /usr/local/go/src/cmd/dist/dist \ + "$GOCACHE" \ + ; \ + \ +# clamp timestamps for reproducibility (allows "COPY --link" to be more clever/useful) + touch -t "$touchy" /usr/local/.go-date-stamp; \ + find /usr/local/go -depth -newer /usr/local/.go-date-stamp -exec touch -ht "$touchy" '{}' +; \ + rm /usr/local/.go-date-stamp; \ + ); \ + \ +# ideally at this point, we would just "COPY --link ... /usr/local/go/ /usr/local/go/" but BuildKit insists on creating the parent directories (perhaps related to https://github.com/opencontainers/image-spec/pull/970), and does so with unreproducible timestamps, so we instead create a whole new "directory tree" that we can "COPY --link" to accomplish what we want + mkdir /target /target/usr /target/usr/local; \ + mv -vT /usr/local/go /target/usr/local/go; \ + ln -svfT /target/usr/local/go /usr/local/go; \ + touch -t "$touchy" /target/usr/local /target/usr /target; \ + \ +# smoke test + go version; \ +# make sure our reproducibile timestamp is probably still correct (best-effort inline reproducibility test) + epoch="$(stat -c '%Y' /target/usr/local/go)"; \ + [ "$SOURCE_DATE_EPOCH" = "$epoch" ]; \ + find /target -newer /target/usr/local/go -exec sh -c 'ls -ld "$@" && exit "$#"' -- '{}' + + +FROM buildpack-deps:bullseye-scm + +# install cgo-related dependencies +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + g++ \ + gcc \ + libc6-dev \ + make \ + pkg-config \ + ; \ + rm -rf /var/lib/apt/lists/* + +# don't auto-upgrade the gotoolchain +# https://github.com/docker-library/golang/issues/472 +ENV GOTOOLCHAIN=local + +ENV GOPATH /go +ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH +# (see notes above about "COPY --link") +COPY --from=build --link /target/ / +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 1777 "$GOPATH" +WORKDIR $GOPATH diff --git a/versions.json b/versions.json index ce501651..baffd815 100644 --- a/versions.json +++ b/versions.json @@ -350,7 +350,7 @@ "src": { "url": "https://dl.google.com/go/go1.22.6.src.tar.gz", "sha256": "9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51", - "supported": true + "supported": false }, "windows-amd64": { "url": "https://dl.google.com/go/go1.22.6.windows-amd64.zip", @@ -762,7 +762,7 @@ "src": { "url": "https://dl.google.com/go/go1.23.0.src.tar.gz", "sha256": "42b7a8e80d805daa03022ed3fde4321d4c3bf2c990a144165d01eeecd6f699c6", - "supported": true + "supported": false }, "windows-amd64": { "url": "https://dl.google.com/go/go1.23.0.windows-amd64.zip", @@ -811,5 +811,107 @@ "windows/nanoserver-ltsc2022", "windows/nanoserver-1809" ] + }, + "tip": { + "version": "tip-20240810", + "commit": { + "version": "d36353499f673c89a267a489beb80133a14a75f9" + }, + "arches": { + "amd64": { + "env": { + "GOOS": "linux", + "GOARCH": "amd64", + "GOAMD64": "v1" + }, + "supported": true + }, + "arm32v5": { + "env": { + "GOOS": "linux", + "GOARCH": "arm", + "GOARM": "5" + }, + "supported": true + }, + "arm32v6": { + "env": { + "GOOS": "linux", + "GOARCH": "arm", + "GOARM": "6" + }, + "supported": true + }, + "arm32v7": { + "env": { + "GOOS": "linux", + "GOARCH": "arm", + "GOARM": "7" + }, + "supported": true + }, + "arm64v8": { + "env": { + "GOOS": "linux", + "GOARCH": "arm64", + "GOARM64": "v8.0" + }, + "supported": true + }, + "i386": { + "env": { + "GOOS": "linux", + "GOARCH": "386", + "GO386": "softfloat" + }, + "supported": true + }, + "mips64le": { + "env": { + "GOOS": "linux", + "GOARCH": "mips64le" + }, + "supported": true + }, + "ppc64le": { + "env": { + "GOOS": "linux", + "GOARCH": "ppc64le" + }, + "supported": true + }, + "riscv64": { + "env": { + "GOOS": "linux", + "GOARCH": "riscv64", + "GORISCV64": "rva20u64" + }, + "supported": true + }, + "s390x": { + "env": { + "GOOS": "linux", + "GOARCH": "s390x" + }, + "supported": true + }, + "src": { + "url": "https://github.com/golang/go/archive/d36353499f673c89a267a489beb80133a14a75f9.tar.gz", + "supported": false + }, + "windows-amd64": { + "env": { + "GOOS": "windows", + "GOARCH": "amd64" + }, + "supported": true + } + }, + "variants": [ + "bookworm", + "bullseye", + "alpine3.20", + "alpine3.19" + ] } } diff --git a/versions.sh b/versions.sh index e3f857e4..e1a1dd3f 100755 --- a/versions.sh +++ b/versions.sh @@ -88,29 +88,101 @@ goVersions="$( for version in "${versions[@]}"; do export version - if \ - ! goJson="$(jq <<<"$goVersions" -ce ' - [ .[] | select(.major == env.version) ] | sort_by( - .version - | split(".") - | map( - if test("^[0-9]+$") then - tonumber - else . end - ) - )[-1] - ')" \ - || ! fullVersion="$(jq <<<"$goJson" -r '.version')" \ - || [ -z "$fullVersion" ] \ - ; then - echo >&2 "warning: cannot find full version for $version" - continue - fi + case "$version" in + tip) + # clamp so we don't update too frequently (https://github.com/docker-library/golang/issues/464#issuecomment-1587758290, https://github.com/docker-library/faq#can-i-use-a-bot-to-make-my-image-update-prs) + # https://github.com/golang/go + # https://go.googlesource.com/go + snapshotDate="$(date --utc --date 'last monday 00:00:00' '+%s')" + snapshotDateStr="$(date --utc --date "@$snapshotDate" '+%Y-%m-%d @ %H:%M:%S')" + commit='HEAD' # this is also our iteration variable, so if we don't find a suitable commit each time through this loop, we'll use the last commit of the previous list to get a list of new (older) commits until we find one suitably old enough + fullVersion= + date= + while [ -z "$fullVersion" ]; do + commits="$( + # wget -qO- 'https://go.googlesource.com/go/+log/refs/heads/master?format=JSON' # the first line of this is ")]}'" for avoiding javscript injection vulnerabilities, which is annoying, and the dates are *super* cursed ("Mon Dec 04 10:00:41 2023 -0800") -- even date(1) doesn't want to parse them ("date: invalid date β€˜Mon Dec 04 10:00:41 2023 -0800’") + # ... so we use GitHub's "atom feeds" endpoint instead, which if you ask for JSON, gives back JSON πŸ˜„ + wget -qO- --header 'Accept: application/json' "https://github.com/golang/go/commits/$commit.atom" \ + | jq -r ' + .payload.commitGroups[].commits[] + | first([ .committedDate, .authoredDate ] | sort | reverse[]) as $date + | "\(.oid) \($date)" + | @sh + ' + )" + eval "commitDates=( $commits )" + if [ "${#commitDates[@]}" -eq 0 ]; then + echo >&2 "error: got no commits when listing history from $commit" + exit 1 + fi + for commitDate in "${commitDates[@]}"; do + commit="${commitDate%%[[:space:]]*}" + date="${commitDate#$commit[[:space:]]}" + [ "$commit" != "$date" ] # sanity check + date="$(date --utc --date "$date" '+%s')" + if [ "$date" -le "$snapshotDate" ]; then + fullVersion="$commit" + break 2 + fi + done + done + if [ -z "$fullVersion" ]; then + echo >&2 "error: cannot find full version for $version (maybe too many commits since $snapshotDateStr?)" + exit 1 + fi + [ "$commit" = "$fullVersion" ] + [ -n "$date" ] + fullVersion="$(date --utc --date "@$date" '+%Y%m%d')" + url="https://github.com/golang/go/archive/$commit.tar.gz" + sha256= # TODO "$(wget -qO- "$url" | sha256sum | cut -d' ' -f1)" # 😭 (this is not fast) + goJson="$( + export fullVersion commit dateStr date url sha256 + jq -nc ' + { + version: "tip-\(env.fullVersion)", + commit: { + version: env.commit, + }, + arches: { + src: { + url: env.url, + #sha256: env.sha256, + }, + }, + } + ' + )" + ;; + + *) + if \ + ! goJson="$(jq <<<"$goVersions" -ce ' + [ .[] | select(.major == env.version) ] | sort_by( + .version + | split(".") + | map( + if test("^[0-9]+$") then + tonumber + else . end + ) + )[-1] + ')" \ + || ! fullVersion="$(jq <<<"$goJson" -r '.version')" \ + || [ -z "$fullVersion" ] \ + ; then + echo >&2 "warning: cannot find full version for $version" + continue + fi + ;; + esac echo "$version: $fullVersion" - doc="$(jq <<<"$goJson" -c --argjson potentiallySupportedArches "$potentiallySupportedArches" '{ + doc="$(jq <<<"$goJson" -c --argjson potentiallySupportedArches "$potentiallySupportedArches" ' + { version: .version, + commit: .commit, + date: .date, arches: ( .arches | . += ( @@ -131,8 +203,12 @@ for version in "${versions[@]}"; do | with_entries( .key as $bashbrewArch | .value.supported = ( - # https://github.com/docker-library/golang/pull/500#issuecomment-1863578601 - as of Go 1.21+, we no longer build from source - .value.url + .key != "src" + and ( + # https://github.com/docker-library/golang/pull/500#issuecomment-1863578601 - as of Go 1.21+, we no longer build from source (except for tip builds) + .value.url + or env.version == "tip" + ) and ($potentiallySupportedArches | index($bashbrewArch)) ) | .value.env += @@ -166,7 +242,7 @@ for version in "${versions[@]}"; do "3.19", empty | "alpine" + .), - if .arches | has("windows-amd64") and .["windows-amd64"].url then + if .arches | has("windows-amd64") and .["windows-amd64"].url then # TODO consider windows + tip ( "ltsc2022", "1809", @@ -179,7 +255,10 @@ for version in "${versions[@]}"; do | "windows/nanoserver-" + .) else empty end ], - }')" + } + # if "date" or "commit" are null, exclude them + | with_entries(select(.value)) + ')" json="$(jq <<<"$json" -c --argjson doc "$doc" '.[env.version] = $doc')" done