Dockerfile, AppImage Release

* Add a Dockerfile to this repo for self-contained easy releases.
  Run it from an x86_64 Linux host and it will produce 64-bit and
  32-bit Linux (rpm, deb, AppImage, tar.gz) and Windows releases.
* The `make appimage` command is more self-sufficient: it will
  download the appimagetool-x86_64.AppImage program for your $ARCH
  for an easy no-dependencies run after you have run `make dist`
This commit is contained in:
Noah 2022-12-07 21:34:12 -08:00
parent 56c03dda45
commit cbc8682406
5 changed files with 200 additions and 38 deletions

View File

@ -8,13 +8,33 @@
* [Windows Cross-Compile from Linux](#windows-cross-compile-from-linux)
* [Old Docs](#old-docs)
# Dockerfile
The Dockerfile in this git repo may be the quickest way to fully
release the game for as many platforms as possible. Run it from a
64-bit host Linux system and it will generate Linux and Windows
releases for 64-bit and 32-bit Intel CPUs.
It depends on your git clone of doodle to be fully initialized
(e.g., you have run the bootstrap.py script and a `make dist`
would build a release for your current system, with doodads and
runtime assets all in the right places).
Run `make docker` and the results will be in the
`artifacts/release` folder in your current working directory.
**Fedora notes (SELinux):** if you run this from a Fedora host
you will need to `sudo setenforce permissive` to allow the
Dockerfile to mount the artifacts/release folder to export its
results.
# Automated Release Scripts
For the quickest ways to fully end-to-end build Sketchy Maze for various
platforms to produce public release artifacts, see the following repos:
Other Dockerfiles and scripts used to release the game:
* [SketchyMaze/docker](https://git.kirsle.net/SketchyMaze/docker) provides a Dockerfile
that fully end-to-end releases the latest version of the game for Linux and Windows:
that fully end-to-end releases the latest version of the game for Linux and Windows. 64bit and 32bit versions that freshly clone the
game from git and output their respective CPU release artifacts:
* Windows: .zip file
* Linux: .tar.gz, .rpm, .deb
* [flatpak](https://code.sketchymaze.com/game/flatpak) is a Flatpak manifest for

118
Dockerfile Normal file
View File

@ -0,0 +1,118 @@
##
# Fully build and distribute Linux and Windows binaries for Project: Doodle.
#
# This is designed to be run from a fully initialized Doodle environment
# (you had run the bootstrap.py for your system, and the doodads and
# levelpacks are installed in the assets/ folder, and `make dist` would
# build a release quality game for your local machine).
#
# It will take your working directory (minus any platform-specific artifacts
# and git repos cloned in to your deps/ folder) and build them from a sane
# Debian base and generate full release artifacts for:
#
# - Linux (x86_64 and i686) as .rpm, .deb, .flatpak and .tar.gz
# - Windows (64-bit and 32-bit) as .zip
#
# Artifact outputs will be in the dist/mw/ folder.
##
FROM debian:latest AS build64
ENV GOPATH /go
ENV GOPROXY direct
ENV PATH /opt/go/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/go/bin
# Install all dependencies.
RUN apt update && apt -y install git zip tar libsdl2-dev libsdl2-ttf-dev \
libsdl2-mixer-dev gcc-mingw-w64-x86-64 gcc make wget \
flatpak-builder ruby-dev gcc rpm libffi-dev \
ruby-dev ruby-rubygems rpm libffi-dev rsync
RUN gem install fpm; exit 0
# Download and install modern Go.
WORKDIR /root
RUN wget https://go.dev/dl/go1.19.3.linux-amd64.tar.gz -O go.tgz && \
tar -xzf go.tgz && \
cp -r go /opt/go
# Add some cacheable directories to speed up Dockerfile trial-and-error.
ADD deps/vendor /SketchyMaze/deps/vendor
# MinGW setup for Windows executable cross-compile.
WORKDIR /SketchyMaze/deps/vendor/mingw-libs
RUN for i in *.tar.gz; do tar -xzvf $i; done
RUN cp -r SDL2-2.0.9/x86_64-w64-mingw32 /usr && \
cp -r SDL2_mixer-2.0.4/x86_64-w64-mingw32 /usr && \
cp -r SDL2_ttf-2.0.15/x86_64-w64-mingw32 /usr
RUN mkdir -p /usr/lib/golang/pkg/windows_amd64
WORKDIR /SketchyMaze
RUN mkdir -p bin && cp deps/vendor/DLL/*.dll bin/
# Add the current working directory (breaks the docker cache every time).
ADD . /SketchyMaze
# Fetch the guidebook.
# RUN sh -c '[[ ! -d ./guidebook ]] && wget -O - https://download.sketchymaze.com/guidebook.tar.gz | tar -xzvf -'
# Use go-winres on the Windows exe (embed application icons)
RUN go install github.com/tc-hib/go-winres@latest && go-winres make
# Install Go dependencies and do the thing:
# - builds the program for Linux
# - builds for Windows via MinGW
# - runs `make dist/` creating an uber build for both OS's
# - runs release.sh to carve out the Linux and Windows versions and
# zip them all up nicely.
RUN make setup && make from-docker64
# Collect the build artifacts.
RUN mkdir -p artifacts && cp -rv dist/release ./artifacts/
###
# 32-bit Dockerfile version of the above
###
FROM i386/debian:latest AS build32
ENV GOPATH /go
ENV GOPROXY direct
ENV PATH /opt/go/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/go/bin
# Dependencies, note the w64-i686 difference to the above
RUN apt update && apt -y install git zip tar libsdl2-dev libsdl2-ttf-dev \
libsdl2-mixer-dev gcc-mingw-w64-i686 gcc make wget \
flatpak-builder ruby-dev gcc rpm libffi-dev \
ruby-dev ruby-rubygems rpm libffi-dev
RUN gem install fpm; exit 0
# Download and install modern Go.
WORKDIR /root
RUN wget https://go.dev/dl/go1.19.3.linux-386.tar.gz -O go.tgz && \
tar -xzf go.tgz && \
cp -r go /opt/go
COPY --from=build64 /SketchyMaze /SketchyMaze
# MinGW setup for Windows executable cross-compile.
WORKDIR /SketchyMaze/deps/vendor/mingw-libs
RUN for i in *.tar.gz; do tar -xzvf $i; done
RUN cp -r SDL2-2.0.9/i686-w64-mingw32 /usr && \
cp -r SDL2_mixer-2.0.4/i686-w64-mingw32 /usr && \
cp -r SDL2_ttf-2.0.15/i686-w64-mingw32 /usr
RUN mkdir -p /usr/lib/golang/pkg/windows_386
WORKDIR /SketchyMaze
RUN mkdir -p bin && cp deps/vendor/DLL-32bit/*.dll bin/
# Do the thing.
RUN make setup && make from-docker32
# Collect the build artifacts.
RUN mkdir -p artifacts && cp -rv dist/release ./artifacts/
###
# Back to (64bit) base for the final CMD to copy artifacts out.
###
FROM debian:latest
COPY --from=build32 /SketchyMaze /SketchyMaze
CMD ["cp", "-r", "-v", \
"/SketchyMaze/artifacts/release/", \
"/mnt/export/"]

View File

@ -71,7 +71,7 @@ doodads:
# `make mingw` to cross-compile a Windows binary with mingw.
.PHONY: mingw
mingw: doodads
mingw:
env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \
GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \
go build $(LDFLAGS_W) -i -o bin/sketchymaze.exe cmd/doodle/main.go
@ -81,7 +81,7 @@ mingw: doodads
# `make mingw32` to cross-compile a Windows binary with mingw (32-bit).
.PHONY: mingw32
mingw32: doodads
mingw32:
env CGO_ENABLED="1" CC="/usr/bin/i686-w64-mingw32-gcc" \
GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \
go build $(LDFLAGS_W) -i -o bin/sketchymaze.exe cmd/doodle/main.go
@ -91,7 +91,7 @@ mingw32: doodads
# `make mingw-free` for Windows binary in free mode.
.PHONY: mingw-free
mingw-free: doodads
mingw-free:
env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \
GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \
go build $(LDFLAGS_W) -tags="shareware" -i -o bin/sketchymaze.exe cmd/doodle/main.go
@ -125,6 +125,17 @@ mingw-release: doodads build mingw __dist-common release
.PHONY: mingw32-release
mingw32-release: doodads build mingw32 __dist-common release32
# `make from-docker64` is an internal command run by the Dockerfile to build the
# game - assumes doodads and assets are in the right spot already.
.PHONY: from-docker64
.PHONY: from-docker32
from-docker64: build mingw __dist-common
ARCH=x86_64 make appimage
make release
from-docker32: build mingw32 __dist-common
ARCH=i686 make appimage
make release32
# `make osx` to cross-compile a Mac OS binary with osxcross.
# .PHONY: osx
# osx: doodads
@ -155,6 +166,14 @@ test:
.PHONY: dist
dist: doodads build __dist-common
# `make docker` runs the Dockerfile to do a full release for 64-bit and 32-bit Linux
# and Windows apps.
.PHONY: docker
docker:
mkdir -p docker-artifacts
podman build -t doodle_docker .
podman run --rm --mount type=bind,src=$(shell pwd)/docker-artifacts,dst=/mnt/export doodle_docker
# `make dist-free` builds and tars up a release in shareware mode.
.PHONY: dist-free
dist-free: doodads build-free __dist-common
@ -171,21 +190,6 @@ __dist-common:
cd dist && tar -czvf sketchymaze-$(VERSION).tar.gz sketchymaze-$(VERSION)
cd dist && zip -r sketchymaze-$(VERSION).zip sketchymaze-$(VERSION)
# `make docker` to run the Docker builds
.PHONY: docker docker.ubuntu docker.debian docker.fedora __docker.dist
docker.ubuntu:
mkdir -p docker/ubuntu
./docker/dist-ubuntu.sh
docker.debian:
mkdir -p docker/debian
./docker/dist-debian.sh
docker.fedora:
mkdir -p docker/fedora
./docker/dist-fedora.sh
docker: docker.ubuntu docker.debian docker.fedora
__docker.dist: dist
cp dist/*.tar.gz dist/*.zip /mnt/export/
# `make clean` cleans everything up.
.PHONY: clean
clean:

View File

@ -1,20 +1,19 @@
#!/bin/bash
# Script to build an AppImage.
#
# Dependencies:
# * appimage-builder: a Python module, so pip install -r requirements.txt
if ! command -v appimage-builder &> /dev/null;then
echo "appimage-builder not found; run pip install -r requirements.txt"
exit 1
fi
# Run it like `ARCH=x86_64 make appimage`
# It will fetch your appimagetool-x86_64.AppImage program to build the appimage.
if [[ ! -d "./dist/sketchymaze-latest" ]]; then
echo "error: run make dist before make appimage"
exit 1
fi
if [[ "$ARCH" == "" ]]; then
echo "You should set ARCH=x86_64 (or your platform for AppImage output)"
exit 1
fi
APPDIR="./dist/AppDir"
LAUNCHER="./scripts/appimage-launcher.sh"
DESKTOP="./scripts/appimage.desktop"
@ -24,6 +23,13 @@ ICON_VECTOR="./etc/icons/orange-128.svg"
APP_RUN="$APPDIR/AppRun"
DIR_ICON="$APPDIR/sketchymaze.svg"
APPIMAGETOOL="appimagetool-$ARCH.AppImage"
if [[ ! -f "./$APPIMAGETOOL" ]]; then
echo "Downloading appimagetool"
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$ARCH.AppImage"
chmod a+x $APPIMAGETOOL
fi
# Clean start
if [[ -d "$APPDIR" ]]; then
echo "Note: Removing previous $APPDIR"
@ -49,4 +55,4 @@ rsync -av "./dist/sketchymaze-latest/" "$APPDIR/"
echo "Making AppImage..."
cd $APPDIR
appimagetool $(pwd)
../../$APPIMAGETOOL $(pwd)

View File

@ -14,7 +14,7 @@ the repos easily. This script will also handle installing the SDL2 dependencies
on Fedora, Debian and macOS type systems.
"""
import sys
import argparse
import os
import os.path
import subprocess
@ -49,7 +49,7 @@ dep_arch = ["go", "sdl2", "sdl2_ttf", "sdl2_mixer"]
ROOT = pathlib.Path().absolute()
def main():
def main(fast=False):
print(
"Project: Doodle Full Installer\n\n"
"Current working directory: {root}\n\n"
@ -60,7 +60,7 @@ def main():
.format(root=ROOT)
)
input("Press Enter to begin.")
install_deps()
install_deps(fast)
clone_repos()
patch_gomod()
copy_assets()
@ -68,22 +68,25 @@ def main():
build()
def install_deps():
def install_deps(fast):
"""Install system dependencies."""
if fast:
fast = " -y"
if shell("which rpm") == 0 and shell("which dnf") == 0:
# Fedora-like.
if shell("rpm -q {}".format(' '.join(dep_fedora))) != 0:
must_shell("sudo dnf install {}".format(' '.join(dep_fedora)))
must_shell("sudo dnf install {}{}".format(' '.join(dep_fedora)), fast)
elif shell("which brew") == 0:
# MacOS, as Catalina has an apt command now??
must_shell("brew install {}".format(' '.join(dep_macos)))
must_shell("brew install {} {}".format(' '.join(dep_macos)), fast)
elif shell("which apt") == 0:
# Debian-like.
if shell("dpkg-query -l {}".format(' '.join(dep_debian))) != 0:
must_shell("sudo apt update && sudo apt install {}".format(' '.join(dep_debian)))
must_shell("sudo apt update && sudo apt install {}{}".format(' '.join(dep_debian)), fast)
elif shell("which pacman") == 0:
# Arch-like.
must_shell("sudo pacman -S {}".format(' '.join(dep_arch)))
must_shell("sudo pacman -S{} {}{}".format(fast, ' '.join(dep_arch)))
else:
print("Warning: didn't detect your package manager to install SDL2 and other dependencies")
@ -148,6 +151,17 @@ def must_shell(cmd):
if __name__ == "__main__":
parser = argparse.ArgumentParser("doodle bootstrap")
parser.add_argument("fast", "f",
action="store_true",
help="Run the script non-interactively (yes to your package manager, git clone over https)",
)
args = parser.parse_args()
if args.fast:
main(fast=args.fast)
quit()
if not input("Use ssh to git clone these repos? [yN] ").lower().startswith("y"):
keys = list(repos.keys())
for k in keys: