Ian Chamberlain
1 year ago
committed by
GitHub
19 changed files with 283 additions and 143 deletions
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
name: 'Run 3DS Executable' |
||||
description: 'Run a given 3DS executable with citra and GDB' |
||||
inputs: |
||||
executable: |
||||
description: > |
||||
The 3DS executable(s) to run. Globs and space separated lists allowed. |
||||
required: true |
||||
runs: |
||||
using: docker |
||||
image: ../../../Dockerfile |
||||
args: |
||||
- ${{ inputs.executable }} |
@ -1,34 +0,0 @@
@@ -1,34 +0,0 @@
|
||||
FROM buildpack-deps:latest as builder |
||||
|
||||
ARG CITRA_CHANNEL=nightly |
||||
ARG CITRA_RELEASE=1962 |
||||
|
||||
WORKDIR /tmp |
||||
COPY ./docker/download_citra.sh /usr/local/bin/download_citra |
||||
RUN apt-get update -y && apt-get install -y jq |
||||
RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} |
||||
|
||||
FROM devkitpro/devkitarm:latest as devkitarm |
||||
|
||||
FROM ubuntu:latest |
||||
|
||||
RUN --mount=type=cache,sharing=locked,target=/var/cache/apt \ |
||||
apt-get update -y && \ |
||||
apt-get install -y \ |
||||
libswscale5 \ |
||||
libsdl2-2.0-0 \ |
||||
libavformat58 \ |
||||
libavfilter7 \ |
||||
xvfb |
||||
|
||||
COPY --from=devkitarm /opt/devkitpro /opt/devkitpro |
||||
ENV PATH=/opt/devkitpro/devkitARM/bin:${PATH} |
||||
|
||||
COPY --from=builder /tmp/citra.AppImage /usr/local/bin/citra |
||||
COPY ./docker/sdl2-config.ini /app/ |
||||
COPY ./docker/test-runner.gdb /app/ |
||||
COPY ./docker/entrypoint.sh /app/ |
||||
|
||||
WORKDIR /app |
||||
|
||||
ENTRYPOINT [ "/app/entrypoint.sh" ] |
@ -1,50 +0,0 @@
@@ -1,50 +0,0 @@
|
||||
#!/bin/bash |
||||
|
||||
# Clean up child processes on exit: https://stackoverflow.com/a/2173421/14436105 |
||||
trap "pkill -P $$" EXIT INT TERM |
||||
|
||||
mkdir -p ~/.config/citra-emu |
||||
cp /app/sdl2-config.ini ~/.config/citra-emu |
||||
# For some reason, log file is only written when this dir already exists, |
||||
# but it is only created after the first run of citra (our only run, in the container) |
||||
mkdir -p ~/.local/share/citra-emu/ |
||||
|
||||
ERRS=0 |
||||
# shellcheck disable=SC2068 |
||||
for EXE in $@; do |
||||
VIDEO_OUT="$(dirname "$EXE")/$(basename "$EXE" .elf)_capture.webm" |
||||
|
||||
# colored logs would be nice, but we can always just grab the plaintext log file |
||||
xvfb-run citra \ |
||||
--appimage-extract-and-run \ |
||||
--dump-video="$VIDEO_OUT" \ |
||||
"$EXE" \ |
||||
&>/dev/null & |
||||
PID=$! |
||||
|
||||
# Citra takes a little while to start up, so wait a little before we try to connect |
||||
sleep 3 |
||||
|
||||
arm-none-eabi-gdb --silent --batch-silent --command /app/test-runner.gdb "$EXE" |
||||
STATUS=$? |
||||
if [ $STATUS -ne 0 ]; then |
||||
echo >&2 "FAILED (exit status $STATUS): $EXE" |
||||
ERRS=$(( ERRS + 1 )) |
||||
fi |
||||
|
||||
kill -INT $PID &>/dev/null |
||||
sleep 1 |
||||
if kill -0 $PID &>/dev/null; then |
||||
kill -KILL $PID &>/dev/null |
||||
fi |
||||
|
||||
CITRA_LOG=~/.local/share/citra-emu/log/citra_log.txt |
||||
CITRA_LOG_OUT="$(dirname "$EXE")/$(basename "$EXE" .elf)_citra_log.txt" |
||||
if test -f "$CITRA_LOG"; then |
||||
cp "$CITRA_LOG" "$CITRA_LOG_OUT" |
||||
else |
||||
echo "WARNING: citra log not found" |
||||
fi |
||||
done |
||||
|
||||
exit $ERRS |
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
FROM buildpack-deps:latest as builder |
||||
|
||||
WORKDIR /tmp |
||||
COPY ./docker/download_citra.sh /usr/local/bin/download_citra |
||||
RUN apt-get update -y && apt-get install -y jq |
||||
|
||||
ARG CITRA_CHANNEL=nightly |
||||
ARG CITRA_RELEASE=1995 |
||||
RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} |
||||
|
||||
FROM devkitpro/devkitarm:latest as devkitarm |
||||
|
||||
# For some reason, citra isn't always happy when you try to run it for the first time, |
||||
# so we build a simple dummy program to force it to create its directory structure |
||||
RUN cd /opt/devkitpro/examples/3ds/graphics/printing/hello-world && \ |
||||
echo 'int main(int, char**) {}' > source/main.c && \ |
||||
make && \ |
||||
mv hello-world.3dsx /tmp/ |
||||
|
||||
FROM ubuntu:latest |
||||
|
||||
RUN --mount=type=cache,sharing=locked,target=/var/cache/apt \ |
||||
apt-get update -y && \ |
||||
apt-get install -y \ |
||||
libswscale5 \ |
||||
libsdl2-2.0-0 \ |
||||
libavformat58 \ |
||||
libavfilter7 \ |
||||
xvfb |
||||
|
||||
COPY --from=devkitarm /opt/devkitpro /opt/devkitpro |
||||
# There's no way to copy ENV values from other stages properly: |
||||
# https://github.com/moby/moby/issues/37345 |
||||
# Luckily in this case we know exactly what the values should be: |
||||
ENV DEVKITPRO=/opt/devkitpro |
||||
ENV DEVKITARM=${DEVKITPRO}/devkitARM |
||||
ENV PATH=${DEVKITARM}/bin:${PATH} |
||||
|
||||
COPY --from=builder /tmp/citra.AppImage /usr/local/bin/citra |
||||
COPY --from=devkitarm /tmp/hello-world.3dsx /tmp/ |
||||
# We run citra once before copying our config file, so it should create its |
||||
# necessary directory structure and run once with defaults |
||||
RUN xvfb-run citra --appimage-extract-and-run /tmp/hello-world.3dsx; \ |
||||
rm -f /tmp/hello-world.3dsx |
||||
# Initial run seems to miss this one directory so just make it manually |
||||
RUN mkdir -p /root/.local/share/citra-emu/log |
||||
|
||||
COPY ./docker/sdl2-config.ini /root/.config/citra-emu/ |
||||
COPY ./docker/test-runner.gdb /app/ |
||||
COPY ./docker/entrypoint.sh /app/ |
||||
|
||||
WORKDIR /app |
||||
|
||||
ENTRYPOINT [ "/app/entrypoint.sh" ] |
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
name: Cargo 3DS Test |
||||
description: > |
||||
Run `cargo 3ds test` executables using Citra. Note that to use this action, |
||||
you must mount `/var/run/docker.sock:/var/run/docker.sock` and `/tmp:/tmp` into |
||||
the container so that the runner image can be built and doctest artifacts can |
||||
be found, respectively. |
||||
|
||||
inputs: |
||||
args: |
||||
description: Extra arguments to pass to `cargo 3ds test` |
||||
required: false |
||||
default: '' |
||||
|
||||
runner-image: |
||||
description: The name of the container image to build for running tests in |
||||
required: false |
||||
default: test-runner-3ds |
||||
|
||||
working-directory: |
||||
description: Change to this directory before running tests. Defaults to $GITHUB_WORKSPACE |
||||
required: false |
||||
default: ${GITHUB_WORKSPACE} |
||||
|
||||
runs: |
||||
using: composite |
||||
steps: |
||||
- name: Set up Docker Buildx |
||||
uses: docker/setup-buildx-action@v3 |
||||
|
||||
- name: Build test-runner image |
||||
uses: docker/build-push-action@v4 |
||||
with: |
||||
context: ${{ github.action_path }} |
||||
tags: ${{ inputs.runner-image }}:latest |
||||
push: false |
||||
load: true |
||||
|
||||
- name: Ensure docker is installed in the container |
||||
shell: bash |
||||
run: apt-get update -y && apt-get install docker.io -y |
||||
|
||||
- name: Run cargo 3ds test |
||||
shell: bash |
||||
# Set a custom runner for `cargo test` commands to use. |
||||
# Use ${GITHUB_WORKSPACE} due to |
||||
# https://github.com/actions/runner/issues/2058, which also means |
||||
# we have to export this instead of using the env: key |
||||
run: | |
||||
cd ${{ inputs.working-directory }} |
||||
export CARGO_TARGET_ARMV6K_NINTENDO_3DS_RUNNER=" |
||||
docker run --rm |
||||
-v ${{ runner.temp }}:${{ runner.temp }} |
||||
-v ${{ github.workspace }}/target:/app/target |
||||
-v ${{ github.workspace }}:${GITHUB_WORKSPACE} |
||||
${{ inputs.runner-image }}:latest" |
||||
env |
||||
cargo 3ds -v test ${{ inputs.args }} |
||||
env: |
||||
# Ensure that doctests get built into a path which is mounted on the host |
||||
# as well as in this container (via the bind mount in the RUNNER command) |
||||
TMPDIR: ${{ runner.temp }} |
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
#!/bin/bash |
||||
|
||||
# Uncomment for debugging the action itself. Maybe consider a job summary or |
||||
# grouping the output, to keep this stuff visible but make it simpler to use: |
||||
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions |
||||
|
||||
# set -x |
||||
|
||||
function cleanup_jobs() { |
||||
# shellcheck disable=SC2317 # Unreachable because it's only used in trap |
||||
if [ -n "$(jobs -p)" ]; then |
||||
sleep 5 & |
||||
wait -n |
||||
# shellcheck disable=SC2046 # We want to expand jobs here and for `wait` |
||||
kill -9 $(jobs -p) |
||||
# shellcheck disable=SC2046 |
||||
wait $(jobs -p) &>/dev/null |
||||
fi |
||||
} |
||||
|
||||
trap cleanup_jobs EXIT |
||||
|
||||
EXE_ELF=$1 |
||||
EXE_3DSX="$(dirname "$EXE")/$(basename "$EXE" .elf).3dsx" |
||||
|
||||
EXE_TO_RUN="$EXE_ELF" |
||||
if [ -f "$EXE_3DSX" ]; then |
||||
echo >&2 "Found $(basename "$EXE_3DSX"), it will be run instead of $(basename "$EXE_ELF")" |
||||
EXE_TO_RUN="$EXE_3DSX" |
||||
fi |
||||
|
||||
VIDEO_OUT="$(dirname "$EXE_ELF")/$(basename "$EXE_ELF" .elf)_capture.webm" |
||||
|
||||
CITRA_LOG_DIR=~/.local/share/citra-emu/log |
||||
CITRA_OUT="$CITRA_LOG_DIR/citra_output.txt" |
||||
|
||||
xvfb-run --auto-servernum \ |
||||
citra \ |
||||
--appimage-extract-and-run \ |
||||
--dump-video="$VIDEO_OUT" \ |
||||
"$EXE_TO_RUN" \ |
||||
&>"$CITRA_OUT" & |
||||
CITRA_PID=$! |
||||
|
||||
# Citra takes a little while to start up, so wait a little before we try to connect |
||||
sleep 5 |
||||
|
||||
arm-none-eabi-gdb --silent --batch-silent --command /app/test-runner.gdb "$EXE_ELF" |
||||
STATUS=$? |
||||
|
||||
kill $CITRA_PID |
||||
cleanup_jobs |
||||
|
||||
CITRA_LOG="$CITRA_LOG_DIR/citra_log.txt" |
||||
|
||||
for f in "$CITRA_LOG" "$CITRA_OUT"; do |
||||
OUT="$(dirname "$EXE_ELF")/$(basename "$EXE_ELF" .elf)_$(basename "$f")" |
||||
if test -f "$f"; then |
||||
cp "$f" "$OUT" |
||||
if [ $STATUS -ne 0 ]; then |
||||
echo >&2 "$(basename $f) copied to $OUT" |
||||
fi |
||||
else |
||||
echo >&2 "WARNING: $(basename "$f") not found" |
||||
fi |
||||
done |
||||
|
||||
exit $STATUS |
Loading…
Reference in new issue