Better way to install the static SDK in CI

Hi - i am a big fan of the static SDK - I have set up my Dockerfile for CI like this. One of the tasks for improvment is to install the static toolchain in a better way, since I currently hardcode the version and the hash. I would like to continue using swift.org's base image to save build time. Can anyone give me some pointers here?`

Thanks for the great work so far!

ARG DISTRIBUTION=debian
ARG DISTRO_VERSION=bookworm

# Set up for debian
FROM swift:bookworm AS development-debian-bookworm

ENV PATH="$PATH:/root/.nix-profile/bin:/root/.cargo/bin"
ENV CC=gcc
ENV CXX=g++
ENV OBJC=gcc
ENV OBJCXX=g++

# set up (Objective) C/++-Toolchain

RUN apt update && apt upgrade -y && apt install -y make curl gpg rpm nix cmake wget zsh zip gdb git ninja-build libncurses6 \
    build-essential gnustep-core-devel gnustep-core-doc gobjc gobjc++

# Set up Swift toolchain (some of it is already included in the base image)

RUN swift sdk install https://download.swift.org/swift-6.1-release/static-sdk/swift-6.1-RELEASE/swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum 111c6f7d280a651208b8c74c0521dd99365d785c1976a6e23162f55f65379ac6

# Set up node-js (we need a more recent version than the one included in bookworm)

RUN nix --extra-experimental-features 'nix-command flakes' profile install  \
    nixpkgs#nodejs_22

# set up rust (we need a more recent version here, too, the one in packages is too old)

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y

## FROM swift:trixie AS development-debian-trixie
## 
## ENV PATH="$PATH:/root/.nix-profile/bin:/root/.cargo/bin:/root/.local/share/swiftly/bin/"
## ENV CC=gcc
## ENV CXX=g++
## ENV OBJC=gcc
## ENV OBJCXX=g++
## 
## RUN apt update && apt upgrade -y && apt install -y make curl gpg  rpm nix cmake wget zsh zip gdb git ninja-build \
##     build-essential gnustep-core-devel gnustep-core-doc gobjc gobjc++ \
##     cargo rustc rust-src npm
## 
## # Set up Swift toolchain
## 
## RUN swift sdk install https://download.swift.org/swift-6.1-release/static-sdk/swift-6.1-RELEASE/swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum ## 111c6f7d280a651208b8c74c0521dd99365d785c1976a6e23162f55f65379ac6
## 
## RUN nix --extra-experimental-features 'nix-command flakes' profile install  \
##     nixpkgs#nodejs_22

FROM fedora:42 AS development-fedora-42

ENV PATH="$PATH:/root/.cargo/bin"
ENV CC=gcc
ENV CXX=g++
ENV OBJC=gcc
ENV OBJCXX=g++

RUN dnf update -y && dnf install -y make curl gnupg2 @development-tools rpm-build  cmake wget zsh zip gdb git ninja-build \
    gnustep-base-devel gcc-objc gcc-objc++ \
    rustup \
    npm \
    swiftlang

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y

RUN swift sdk install https://download.swift.org/swift-6.0.3-release/static-sdk/swift-6.0.3-RELEASE/swift-6.0.3-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum 111c6f7d280a651208b8c74c0521dd99365d785c1976a6e23162f55f65379ac6

FROM swift:rhel-ubi9 AS development-rhel-9

ENV PATH="$PATH:/root/.cargo/bin"
ENV CC=gcc
ENV CXX=g++
ENV OBJC=gcc
ENV OBJCXX=g++

RUN dnf update -y
RUN dnf module enable -y nodejs:22
RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm

RUN dnf install -y make gnupg2 rpm-build cmake wget zsh zip gdb git ninja-build \
    gnustep-base-devel gcc gcc-c++ gcc-objc gcc-objc++ \
    npm

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y

RUN swift sdk install https://download.swift.org/swift-6.1-release/static-sdk/swift-6.1-RELEASE/swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum 111c6f7d280a651208b8c74c0521dd99365d785c1976a6e23162f55f65379ac6

FROM swift:noble AS development-ubuntu-noble

ENV PATH="$PATH:/root/.nix-profile/bin:/root/.cargo/bin"
ENV CC=gcc
ENV CXX=g++
ENV OBJC=gcc
ENV OBJCXX=g++

# set up (Objective) C/++-Toolchain

RUN apt update && apt upgrade -y && apt install -y make curl gpg rpm nix cmake wget zsh zip gdb git ninja-build libncurses6 \
    build-essential gnustep-core-devel gnustep-core-doc gobjc gobjc++ \
    rustup \
    npm

RUN rustup default stable

# Set up Swift toolchain (some of it is already included in the base image)

RUN swift sdk install https://download.swift.org/swift-6.1-release/static-sdk/swift-6.1-RELEASE/swift-6.1-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz --checksum 111c6f7d280a651208b8c74c0521dd99365d785c1976a6e23162f55f65379ac6

FROM development-debian-bookworm AS development
# "default" environment

FROM development-${DISTRIBUTION}-${DISTRO_VERSION} AS build
ARG VARIANT=debug

WORKDIR /workspace
COPY . .
RUN make init
RUN VARIANT=${VARIANT} npx dotenvx run -- make linux-packages

FROM alpine:latest AS post-process

WORKDIR /tmp
COPY --from=build /workspace/result/*.sh .
WORKDIR /app
RUN sh /tmp/*.sh -- --skip-license --prefix .

FROM scratch AS run

WORKDIR /
COPY --from=post-process /app .
# TODO launch all binaries here
CMD [ "/bin/from-scratch" ]

I don't think you are gaining anything by having a bunch of different base images, especially with different Swift versions, so I'd cut it down to just 1 Swift image.

If rust/nodejs build steps can be separated, they should have their own builder images and then the build products should be copied over to the next step.

If you have the Swift 6.1(.0) static SDK hardcoded, you base image should also hardcode 6.1.0 (not just 6.1, this static SDK most likely won't work with 6.1.1)

If you are worried about setup time then you could have a daily/weekly/monthly automation to build and publish your base development images (with the ability to update manually in case some really important version releases that you need to use).

If you think they should provide a base image that has the static SDK preinstalled, feel free to open an issue here: GitHub · Where software is built

Would that amount to anything more than a Dockerfile based on the toolchain image with a single RUN swift sdk install directive? I'm not sure there's much value in that, given how easy it is already for an end user to create it on their own, or to add it to a Dockerfile where they're building their software. As a separate directive it would still be cached as a separate layer, so there's not much to gain from caching perspective either.

It still speeds up clean builds, so it has at least some value.

It would avoid the problem of having to update the URL and hash for the correct static SDK version when updating the base image.

It would also avoid people using base images from random 3rd parties who have it already and might or might not add some malicious code in a later update.