diff --git a/README.md b/README.md index af9fad41..acd91b61 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Factorio [![Docker Version](https://img.shields.io/docker/v/factoriotools/factorio?sort=semver)](https://hub.docker.com/r/factoriotools/factorio/) [![Docker Pulls](https://img.shields.io/docker/pulls/factoriotools/factorio.svg?maxAge=600)](https://hub.docker.com/r/factoriotools/factorio/) [![Docker Stars](https://img.shields.io/docker/stars/factoriotools/factorio.svg?maxAge=600)](https://hub.docker.com/r/factoriotools/factorio/) > [!NOTE] -> Support for ARM is experimental. Expect crashes and lag if you try to run this on a raspberry pi. +> ARM64 images for Factorio 2.1 and newer run the native `linux-arm64` headless build. Older versions have no native build and run the x64 build under box64 emulation, which is experimental: expect crashes and lag if you try to run those on a raspberry pi. [中文](./README_zh_CN.md) diff --git a/build.py b/build.py index 0ba872a6..737fc1f9 100755 --- a/build.py +++ b/build.py @@ -59,10 +59,15 @@ def push_singlearch(tags): exit(1) -def build_and_push(sha256, version, tags, push, multiarch, dockerfile="Dockerfile", builder_suffix=""): +def build_and_push(sha256, version, tags, push, multiarch, dockerfile="Dockerfile", builder_suffix="", + sha256_arm64=None): build_dir = tempfile.mktemp() shutil.copytree("docker", build_dir) - build_args = ["-f", dockerfile, "--build-arg", f"VERSION={version}", "--build-arg", f"SHA256={sha256}", "."] + build_args = ["-f", dockerfile, "--build-arg", f"VERSION={version}", "--build-arg", f"SHA256={sha256}"] + if sha256_arm64: + # Native ARM64 archive available: the arm64 image runs it instead of the x64 build under box64 + build_args.extend(["--build-arg", f"SHA256_ARM64={sha256_arm64}"]) + build_args.append(".") for tag in tags: build_args.extend(["-t", f"factoriotools/factorio:{tag}"]) @@ -131,7 +136,8 @@ def main(): for version, buildinfo in versions_to_build: sha256 = buildinfo["sha256"] tags = buildinfo["tags"] - build_and_push(sha256, version, tags, args.push_tags, args.multiarch) + build_and_push(sha256, version, tags, args.push_tags, args.multiarch, + sha256_arm64=buildinfo.get("sha256_arm64")) # Build rootless images if build_rootless: @@ -150,7 +156,8 @@ def main(): original_tags = buildinfo["tags"] rootless_tags = generate_rootless_tags(original_tags) build_and_push(sha256, version, rootless_tags, args.push_tags, args.multiarch, - dockerfile="Dockerfile.rootless", builder_suffix="-rootless") + dockerfile="Dockerfile.rootless", builder_suffix="-rootless", + sha256_arm64=buildinfo.get("sha256_arm64")) if __name__ == '__main__': diff --git a/buildinfo.json b/buildinfo.json index 0d535042..a82a4091 100644 --- a/buildinfo.json +++ b/buildinfo.json @@ -11,6 +11,7 @@ }, "2.1.20": { "sha256": "421a483dbcf69b76d854b7fdb86a800c94da04e414c20803c9fce82fc191bbb5", + "sha256_arm64": "6543968b416129f7ce905714e649bf7ae7b63e9eb2a01de53687ce1adf58d517", "tags": [ "latest", "2", diff --git a/docker/Dockerfile b/docker/Dockerfile index d118e066..908833d4 100755 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,6 +16,8 @@ ARG GROUP=factorio ARG PUID=845 ARG PGID=845 ARG BOX64_VERSION=v0.2.4 +# sha256 of the native linux-arm64 archive (2.1+); empty means x64 build under box64 +ARG SHA256_ARM64 # optionally utilize a built-in map-gen-preset (see data/base/prototypes/map-gen-presets # if this is used, the preset will be used over any .json files supplied @@ -44,7 +46,7 @@ SHELL ["/bin/bash", "-eo", "pipefail", "-c"] RUN apt-get -q update \ && DEBIAN_FRONTEND=noninteractive apt-get -qy install ca-certificates curl jq pwgen xz-utils procps gettext-base file --no-install-recommends \ - && if [[ "$(uname -m)" == "aarch64" ]]; then \ + && if [[ "$(uname -m)" == "aarch64" && -z "${SHA256_ARM64}" ]]; then \ echo "installing ARM compatability layer" \ && DEBIAN_FRONTEND=noninteractive apt-get -qy install unzip --no-install-recommends \ && curl -LO https://github.com/ptitSeb/box64/releases/download/${BOX64_VERSION}/box64-GENERIC_ARM-RelWithDebInfo.zip \ @@ -75,14 +77,21 @@ RUN set -ox pipefail \ echo "build-arg SHA256 is required" \ && exit 1; \ fi \ - && archive="/tmp/factorio_headless_x64_$VERSION.tar.xz" \ + && if [[ "$(uname -m)" == "aarch64" && -n "${SHA256_ARM64}" ]]; then \ + platform="linux-arm64" && sha256="${SHA256_ARM64}"; \ + else \ + platform="linux64" && sha256="${SHA256}"; \ + fi \ + && archive="/tmp/factorio_headless_${platform}_$VERSION.tar.xz" \ && mkdir -p /opt /factorio \ - && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/linux64" -o "$archive" --retry $CURL_RETRIES \ - && echo "$SHA256 $archive" | sha256sum -c \ + && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/$platform" -o "$archive" --retry $CURL_RETRIES \ + && echo "$sha256 $archive" | sha256sum -c \ || (sha256sum "$archive" && file "$archive" && exit 1) \ && tar xf "$archive" --directory /opt \ && chmod ugo=rwx /opt/factorio \ && rm "$archive" \ + # the native arm64 archive ships bin/arm64; keep the bin/x64 path the scripts use + && if [[ -d /opt/factorio/bin/arm64 && ! -e /opt/factorio/bin/x64 ]]; then ln -s arm64 /opt/factorio/bin/x64; fi \ && ln -s "$SCENARIOS" /opt/factorio/scenarios \ && ln -s "$SAVES" /opt/factorio/saves \ && mkdir -p /opt/factorio/config/ \ diff --git a/docker/Dockerfile.rootless b/docker/Dockerfile.rootless index 078b89f6..a8d837d8 100644 --- a/docker/Dockerfile.rootless +++ b/docker/Dockerfile.rootless @@ -12,6 +12,8 @@ FROM debian:stable-slim LABEL maintainer="https://github.com/factoriotools/factorio-docker" ARG BOX64_VERSION=v0.2.4 +# sha256 of the native linux-arm64 archive (2.1+); empty means x64 build under box64 +ARG SHA256_ARM64 # optionally utilize a built-in map-gen-preset (see data/base/prototypes/map-gen-presets ARG PRESET @@ -33,7 +35,7 @@ SHELL ["/bin/bash", "-eo", "pipefail", "-c"] RUN apt-get -q update \ && DEBIAN_FRONTEND=noninteractive apt-get -qy install ca-certificates curl jq pwgen xz-utils procps gettext-base --no-install-recommends \ - && if [[ "$(uname -m)" == "aarch64" ]]; then \ + && if [[ "$(uname -m)" == "aarch64" && -z "${SHA256_ARM64}" ]]; then \ echo "installing ARM compatability layer" \ && DEBIAN_FRONTEND=noninteractive apt-get -qy install unzip --no-install-recommends \ && curl -LO https://github.com/ptitSeb/box64/releases/download/${BOX64_VERSION}/box64-GENERIC_ARM-RelWithDebInfo.zip \ @@ -61,14 +63,21 @@ RUN set -ox pipefail \ echo "build-arg SHA256 is required" \ && exit 1; \ fi \ - && archive="/tmp/factorio_headless_x64_$VERSION.tar.xz" \ + && if [[ "$(uname -m)" == "aarch64" && -n "${SHA256_ARM64}" ]]; then \ + platform="linux-arm64" && sha256="${SHA256_ARM64}"; \ + else \ + platform="linux64" && sha256="${SHA256}"; \ + fi \ + && archive="/tmp/factorio_headless_${platform}_$VERSION.tar.xz" \ && mkdir -p /opt /factorio \ - && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/linux64" -o "$archive" --retry $CURL_RETRIES \ - && echo "$SHA256 $archive" | sha256sum -c \ + && curl -sSL "https://www.factorio.com/get-download/$VERSION/headless/$platform" -o "$archive" --retry $CURL_RETRIES \ + && echo "$sha256 $archive" | sha256sum -c \ || (sha256sum "$archive" && file "$archive" && exit 1) \ && tar xf "$archive" --directory /opt \ && chmod ugo=rwx /opt/factorio \ && rm "$archive" \ + # the native arm64 archive ships bin/arm64; keep the bin/x64 path the scripts use + && if [[ -d /opt/factorio/bin/arm64 && ! -e /opt/factorio/bin/x64 ]]; then ln -s arm64 /opt/factorio/bin/x64; fi \ && ln -s "$SCENARIOS" /opt/factorio/scenarios \ && ln -s "$SAVES" /opt/factorio/saves \ && mkdir -p /opt/factorio/config/ diff --git a/update.sh b/update.sh index 88035ad9..2d58d24c 100755 --- a/update.sh +++ b/update.sh @@ -7,6 +7,9 @@ experimental_online_version=$(curl 'https://factorio.com/api/latest-releases' | stable_sha256=$(curl "https://factorio.com/download/sha256sums/" | grep -E "(factorio_headless_x64_|factorio-headless_linux_)${stable_online_version}.tar.xz" | awk '{print $1}') experimental_sha256=$(curl "https://factorio.com/download/sha256sums/" | grep -E "(factorio_headless_x64_|factorio-headless_linux_)${experimental_online_version}.tar.xz" | awk '{print $1}') +# Native ARM64 headless builds exist from 2.1 on; older versions have no arm64 archive and the value stays empty. +stable_sha256_arm64=$(curl "https://factorio.com/download/sha256sums/" | grep -E "factorio-headless_linux-arm64_${stable_online_version}.tar.xz" | awk '{print $1}') +experimental_sha256_arm64=$(curl "https://factorio.com/download/sha256sums/" | grep -E "factorio-headless_linux-arm64_${experimental_online_version}.tar.xz" | awk '{print $1}') stable_current_version=$(jq 'with_entries(select(.value.tags | index("stable"))) | keys | .[0]' buildinfo.json -r) latest_current_version=$(jq 'with_entries(select(.value.tags | index("latest"))) | keys | .[0]' buildinfo.json -r) @@ -68,22 +71,22 @@ echo '{}' > "$tmpfile" # Add stable version if [[ "$stable_online_version" == "$experimental_online_version" ]]; then # Stable and experimental are the same version - jq --arg stable_online_version "$stable_online_version" --arg sha256 "$stable_sha256" --arg stableOnlineVersionShort "$stableOnlineVersionShort" --arg stableOnlineVersionMajor "$stableOnlineVersionMajor" \ - '. + {($stable_online_version): {sha256: $sha256, tags: ["latest", "stable", ("stable-" + $stable_online_version), $stableOnlineVersionMajor, $stableOnlineVersionShort, $stable_online_version]}}' "$tmpfile" > buildinfo.json + jq --arg stable_online_version "$stable_online_version" --arg sha256 "$stable_sha256" --arg sha256_arm64 "$stable_sha256_arm64" --arg stableOnlineVersionShort "$stableOnlineVersionShort" --arg stableOnlineVersionMajor "$stableOnlineVersionMajor" \ + '. + {($stable_online_version): {sha256: $sha256} + (if $sha256_arm64 != "" then {sha256_arm64: $sha256_arm64} else {} end) + {tags: ["latest", "stable", ("stable-" + $stable_online_version), $stableOnlineVersionMajor, $stableOnlineVersionShort, $stable_online_version]}}' "$tmpfile" > buildinfo.json else # Different stable and experimental versions # First add stable - jq --arg stable_online_version "$stable_online_version" --arg sha256 "$stable_sha256" --arg stableOnlineVersionShort "$stableOnlineVersionShort" --arg stableOnlineVersionMajor "$stableOnlineVersionMajor" \ - '. + {($stable_online_version): {sha256: $sha256, tags: ["stable", ("stable-" + $stable_online_version), $stableOnlineVersionMajor, $stableOnlineVersionShort, $stable_online_version]}}' "$tmpfile" > buildinfo.json.tmp + jq --arg stable_online_version "$stable_online_version" --arg sha256 "$stable_sha256" --arg sha256_arm64 "$stable_sha256_arm64" --arg stableOnlineVersionShort "$stableOnlineVersionShort" --arg stableOnlineVersionMajor "$stableOnlineVersionMajor" \ + '. + {($stable_online_version): {sha256: $sha256} + (if $sha256_arm64 != "" then {sha256_arm64: $sha256_arm64} else {} end) + {tags: ["stable", ("stable-" + $stable_online_version), $stableOnlineVersionMajor, $stableOnlineVersionShort, $stable_online_version]}}' "$tmpfile" > buildinfo.json.tmp mv buildinfo.json.tmp "$tmpfile" # Then add experimental if [[ $stableOnlineVersionShort == "$experimentalOnlineVersionShort" ]]; then - jq --arg experimental_online_version "$experimental_online_version" --arg sha256 "$experimental_sha256" \ - '. + {($experimental_online_version): {sha256: $sha256, tags: ["latest", $experimental_online_version]}}' "$tmpfile" > buildinfo.json + jq --arg experimental_online_version "$experimental_online_version" --arg sha256 "$experimental_sha256" --arg sha256_arm64 "$experimental_sha256_arm64" \ + '. + {($experimental_online_version): {sha256: $sha256} + (if $sha256_arm64 != "" then {sha256_arm64: $sha256_arm64} else {} end) + {tags: ["latest", $experimental_online_version]}}' "$tmpfile" > buildinfo.json else - jq --arg experimental_online_version "$experimental_online_version" --arg sha256 "$experimental_sha256" --arg experimentalOnlineVersionShort "$experimentalOnlineVersionShort" --arg experimentalOnlineVersionMajor "$experimentalOnlineVersionMajor" \ - '. + {($experimental_online_version): {sha256: $sha256, tags: ["latest", $experimentalOnlineVersionMajor, $experimentalOnlineVersionShort, $experimental_online_version]}}' "$tmpfile" > buildinfo.json + jq --arg experimental_online_version "$experimental_online_version" --arg sha256 "$experimental_sha256" --arg sha256_arm64 "$experimental_sha256_arm64" --arg experimentalOnlineVersionShort "$experimentalOnlineVersionShort" --arg experimentalOnlineVersionMajor "$experimentalOnlineVersionMajor" \ + '. + {($experimental_online_version): {sha256: $sha256} + (if $sha256_arm64 != "" then {sha256_arm64: $sha256_arm64} else {} end) + {tags: ["latest", $experimentalOnlineVersionMajor, $experimentalOnlineVersionShort, $experimental_online_version]}}' "$tmpfile" > buildinfo.json fi fi