From 41dac11125bffe80c36f73211c0ea42f73edfb7a Mon Sep 17 00:00:00 2001 From: Luis Lavena Date: Sat, 27 Apr 2024 18:54:06 +0200 Subject: [PATCH] Add Crystal 1.12.1 --- .github/workflows/ci.yml | 5 + Makefile | 2 +- docker/1.12/Dockerfile | 295 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 docker/1.12/Dockerfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ba0fee..4013f2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,11 @@ jobs: fail-fast: false matrix: include: + - crystal_major_minor: '1.12' + crystal_full: '1.12.1' + target_platforms: linux/amd64,linux/arm64 + concurrency_group: compile-crystal + - crystal_major_minor: '1.11' crystal_full: '1.11.2' target_platforms: linux/amd64,linux/arm64 diff --git a/Makefile b/Makefile index 4e436c3..4b30317 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION ?= 1.11 +VERSION ?= 1.12 REGISTRY ?= ghcr.io DOCKERFILE := docker/${VERSION}/Dockerfile diff --git a/docker/1.12/Dockerfile b/docker/1.12/Dockerfile new file mode 100644 index 0000000..3badc31 --- /dev/null +++ b/docker/1.12/Dockerfile @@ -0,0 +1,295 @@ +# syntax=docker/dockerfile:1.4 + +# --- +# Stages: +# +# stage0: use build platform and existing compiler to cross-compile for target +# stage1: link cross-compiled objects into executables on the target platform +# stage2: prepare directory structure, source code and final executables +# stage3: copy over artifacts and development utilities and dependencies + +# --- +# stage0: bootstrap Crystal using Alpine's build of Crystal +FROM --platform=$BUILDPLATFORM alpine:3.19.1 AS stage0 + +# expose the target architecture to be used in cross-compilation +ARG TARGETARCH + +# install dependencies needed for cross-compilation of Crystal and Shards +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + set -eux; \ + apk add \ + crystal \ + curl \ + g++ \ + git \ + llvm17-dev \ + make \ + shards \ + yaml-dev \ + ; + +# download and compile Crystal source for target platform +RUN set -eux -o pipefail; \ + cd /tmp; \ + export \ + CRYSTAL_VERSION=1.12.1 \ + CRYSTAL_SHA256=8f464ec302696c6a60410c4234569989c10bcd5004f1563b8047c5e3e1c8ba1f \ + ; \ + { \ + curl --fail -Lo crystal.tar.gz https://github.com/crystal-lang/crystal/archive/refs/tags/${CRYSTAL_VERSION}.tar.gz; \ + echo "${CRYSTAL_SHA256} *crystal.tar.gz" | sha256sum -c - >/dev/null 2>&1; \ + tar -xf crystal.tar.gz; \ + rm crystal.tar.gz; \ + mv crystal-${CRYSTAL_VERSION} crystal; \ + }; \ + { \ + cd /tmp/crystal; \ + # prepare man page + gzip -9 man/crystal.1; \ + mkdir -p /usr/local/share/man/man1; \ + cp -f man/*.1.gz /usr/local/share/man/man1/; \ + # build Compiler for target architecture + mkdir -p .build; \ + make crystal release=1 static=1 target=$TARGETARCH-alpine-linux-musl | tail -1 | tee .build/crystal.sh; \ + rm -rf src/llvm/ext/llvm_ext.o; \ + } + +# download and compile Shards source for target platform +RUN set -eux -o pipefail; \ + cd /tmp; \ + export \ + SHARDS_VERSION=0.18.0 \ + SHARDS_SHA256=46a830afd929280735d765e59d8c27ac9ba92eddde9647ae7d3fc85addc38cc5 \ + ; \ + { \ + curl --fail -Lo shards.tar.gz https://github.com/crystal-lang/shards/archive/refs/tags/v${SHARDS_VERSION}.tar.gz; \ + echo "${SHARDS_SHA256} *shards.tar.gz" | sha256sum -c - >/dev/null 2>&1; \ + tar -xf shards.tar.gz; \ + rm shards.tar.gz; \ + mv shards-${SHARDS_VERSION} shards; \ + }; \ + { \ + cd /tmp/shards; \ + # prepare man pages + gzip -9 man/shards.1 man/shard.yml.5; \ + mkdir -p /usr/local/share/man/man1 /usr/local/share/man/man5; \ + cp -f man/*.1.gz /usr/local/share/man/man1/; \ + cp -f man/*.5.gz /usr/local/share/man/man5/; \ + # build for target platform + make bin/shards release=1 static=1 FLAGS="--cross-compile --target $TARGETARCH-alpine-linux-musl" | tail -1 | tee bin/shards.sh; \ + } + +# --- +# stage1: link compiled objects on target platform +FROM alpine:3.19.1 AS stage1 + +# install dependencies needed for linking +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + set -eux; \ + apk add \ + g++ \ + gc-dev \ + gcc \ + git \ + libevent-static \ + libxml2-static \ + llvm17-dev \ + llvm17-static \ + make \ + musl-dev \ + pcre-dev \ + pcre2-dev \ + yaml-static \ + zlib-static \ + zstd-static \ + ; + +# copy build artifacts from stage0 +COPY --from=stage0 /tmp/crystal/.build /tmp/crystal/.build +COPY --from=stage0 /tmp/crystal/Makefile /tmp/crystal/Makefile +COPY --from=stage0 /tmp/crystal/src/llvm/ext /tmp/crystal/src/llvm/ext +COPY --from=stage0 /tmp/shards/bin /tmp/shards/bin + +# link objects to final binaries +RUN set -eux; \ + # compile LLVM extension and link the compiler + { \ + cd /tmp/crystal; \ + mkdir -p spec/; \ + make llvm_ext; \ + sh -ex .build/crystal.sh; \ + # smoke test + .build/crystal --version; \ + # copy final binary + mkdir -p /tmp/usr/local/bin; \ + cp -f .build/crystal /tmp/usr/local/bin/; \ + }; \ + # compile shards + { \ + cd /tmp/shards; \ + sh -ex bin/shards.sh; \ + # smoke test + bin/shards --version; \ + # copy final binary + mkdir -p /tmp/usr/local/bin; \ + cp -f bin/shards /tmp/usr/local/bin/; \ + } + +# --- +# stage2: prepare binaries and code for final image +FROM alpine:3.19.1 AS stage2 + +# combine source code and final binaries from previous stages +COPY --from=stage0 /tmp/crystal/src /usr/local/share/crystal/src +COPY --from=stage0 /usr/local/share/man /usr/local/share/man +COPY --from=stage1 /tmp/usr/local/bin /usr/local/bin + +# --- +# stage3: final image +FROM alpine:3.19.1 AS stage3 + +# upgrade system and installed dependencies for security patches +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + set -eux; \ + apk upgrade + +# copy prepared structure from stage2 +COPY --from=stage2 /usr/local /usr/local + +# install dependencies and common packages +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + set -eux; \ + apk add \ + curl \ + gc-dev \ + gcc \ + git \ + libevent-static \ + musl-dev \ + openssl-dev \ + openssl-libs-static \ + pcre-dev \ + pcre2-dev \ + sqlite-static \ + tzdata \ + yaml-dev \ + yaml-static \ + zlib-dev \ + zlib-static \ + ; \ + # smoke tests + [ "$(command -v crystal)" = '/usr/local/bin/crystal' ]; \ + [ "$(command -v shards)" = '/usr/local/bin/shards' ]; \ + crystal --version; \ + shards --version + +# setup non-root user (fixuid) +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + --mount=type=tmpfs,target=/tmp \ + set -eux -o pipefail; \ + # create non-root user & give passwordless sudo + { \ + apk add sudo; \ + addgroup -g 1000 user; \ + adduser -u 1000 -G user -h /home/user -s /bin/sh -D user; \ + mkdir -p /etc/sudoers.d; \ + echo "user ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user; \ + # cleanup backup copies + rm /etc/group- /etc/passwd- /etc/shadow-; \ + }; \ + # Install fixuid + { \ + cd /tmp; \ + export FIXUID_VERSION=0.6.0; \ + case "$(arch)" in \ + x86_64) \ + export \ + FIXUID_ARCH=amd64 \ + FIXUID_SHA256=8c47f64ec4eec60e79871796ea4097ead919f7fcdedace766da9510b78c5fa14 \ + ; \ + ;; \ + aarch64) \ + export \ + FIXUID_ARCH=arm64 \ + FIXUID_SHA256=827e0b480c38470b5defb84343be7bb4e85b9efcbf3780ac779374e8b040a969 \ + ; \ + ;; \ + esac; \ + wget -q -O fixuid.tar.gz https://github.com/boxboat/fixuid/releases/download/v${FIXUID_VERSION}/fixuid-${FIXUID_VERSION}-linux-${FIXUID_ARCH}.tar.gz; \ + echo "${FIXUID_SHA256} *fixuid.tar.gz" | sha256sum -c - >/dev/null 2>&1; \ + tar -xf fixuid.tar.gz; \ + mv fixuid /usr/local/bin/; \ + chmod u+s /usr/local/bin/fixuid; \ + rm fixuid.tar.gz; \ + }; \ + # Generate fixuid config + mkdir -p /etc/fixuid; \ + { \ + echo "user: user"; \ + echo "group: user"; \ + } | tee /etc/fixuid/config.yml + +# Adjust ENTRYPOINT +ENTRYPOINT [ "/usr/local/bin/fixuid", "-q" ] +CMD [ "/bin/sh" ] + +# install development utilities +RUN --mount=type=cache,sharing=private,target=/var/cache/apk \ + --mount=type=tmpfs,target=/tmp \ + set -eux; \ + cd /tmp; \ + # Overmind (needs tmux) + { \ + export OVERMIND_VERSION=2.4.0; \ + case "$(arch)" in \ + x86_64) \ + export \ + OVERMIND_ARCH=amd64 \ + OVERMIND_SHA256=1f7cac289b550a71bebf4a29139e58831b39003d9831be59eed3e39a9097311c \ + ; \ + ;; \ + aarch64) \ + export \ + OVERMIND_ARCH=arm64 \ + OVERMIND_SHA256=94a3e8393bd718ae9ec1b6cc21740bffa52da20710eaf020a7aa679cdc926104 \ + ; \ + ;; \ + esac; \ + apk add \ + tmux \ + ; \ + curl --fail -Lo overmind.gz https://github.com/DarthSim/overmind/releases/download/v${OVERMIND_VERSION}/overmind-v${OVERMIND_VERSION}-linux-${OVERMIND_ARCH}.gz; \ + echo "${OVERMIND_SHA256} *overmind.gz" | sha256sum -c - >/dev/null 2>&1; \ + gunzip overmind.gz; \ + chmod +x overmind; \ + mv overmind /usr/local/bin/; \ + }; \ + # Watchexec + { \ + export WATCHEXEC_VERSION=1.25.1; \ + case "$(arch)" in \ + x86_64) \ + export \ + WATCHEXEC_ARCH=x86_64 \ + WATCHEXEC_SHA256=f120752ae92a579d40956ebf527fba8cf8a953718b669d1e446ee072cbfd0bd5 \ + ; \ + ;; \ + aarch64) \ + export \ + WATCHEXEC_ARCH=aarch64 \ + WATCHEXEC_SHA256=e235f2c326122e108dc2c491252487aa596fe4894a1194f7c6dd0b6f728738bb \ + ; \ + ;; \ + esac; \ + curl --fail -Lo watchexec.tar.xz https://github.com/watchexec/watchexec/releases/download/v${WATCHEXEC_VERSION}/watchexec-${WATCHEXEC_VERSION}-${WATCHEXEC_ARCH}-unknown-linux-musl.tar.xz; \ + echo "${WATCHEXEC_SHA256} *watchexec.tar.xz" | sha256sum -c - >/dev/null 2>&1; \ + tar -xf watchexec.tar.xz; \ + mv watchexec-${WATCHEXEC_VERSION}-${WATCHEXEC_ARCH}-unknown-linux-musl/watchexec /usr/local/bin/; \ + rm -rf watchexec.tar.xz watchexec-${WATCHEXEC_VERSION}-${WATCHEXEC_ARCH}-unknown-linux-musl; \ + }; \ + # smoke tests + [ "$(command -v overmind)" = '/usr/local/bin/overmind' ]; \ + [ "$(command -v watchexec)" = '/usr/local/bin/watchexec' ]; \ + overmind --version; \ + watchexec --version