diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..477752a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.dockerignore +.git +.github +.gitignore +Makefile +README.md +bump-info.json +coco-dev +docker-compose.build.yml +package.json +tests diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 17c5b5e..04b7089 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -1,17 +1,26 @@ name: Build Docker Image on: - pull_request: push: branches: - '**' - '!main' workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: contents: write jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: make lint + create_tag: runs-on: ubuntu-latest outputs: @@ -37,27 +46,42 @@ jobs: - ubuntu-24.04-arm steps: + - uses: actions/checkout@v4 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push image + - name: Build and load image env: RELEASE_TAG: ${{ needs.create_tag.outputs.release_tag }} uses: docker/build-push-action@v6 with: - push: ${{ startsWith(github.ref, 'refs/tags') }} + load: true tags: jamieleecho/coco-dev:${{ env.RELEASE_TAG }}-${{ matrix.os }} - cache-from: type=gha - cache-to: type=gha,mode=max + cache-from: type=gha,scope=${{ matrix.os }} + cache-to: type=gha,mode=max,scope=${{ matrix.os }} + + - name: Smoke test + env: + RELEASE_TAG: ${{ needs.create_tag.outputs.release_tag }} + run: make test TAG=jamieleecho/coco-dev:${{ env.RELEASE_TAG }}-${{ matrix.os }} - - uses: actions/checkout@v3 + - name: Image size + env: + RELEASE_TAG: ${{ needs.create_tag.outputs.release_tag }} + run: make size TAG=jamieleecho/coco-dev:${{ env.RELEASE_TAG }}-${{ matrix.os }} + + - name: Push image if: startsWith(github.ref, 'refs/tags') + env: + RELEASE_TAG: ${{ needs.create_tag.outputs.release_tag }} + run: docker push jamieleecho/coco-dev:${{ env.RELEASE_TAG }}-${{ matrix.os }} - name: Update repo description uses: peter-evans/dockerhub-description@v3 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6ba4b02 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +.DEFAULT_GOAL := help +.PHONY: help build test shell lint size push clean + +IMAGE := jamieleecho/coco-dev +VERSION := $(shell sed -nE 's/.*"version" *: *"([^"]+)".*/\1/p' package.json) +TAG ?= $(IMAGE):$(VERSION) +SHELLCHECK_IMAGE := koalaman/shellcheck-alpine:stable + +help: + @echo "coco-dev Makefile targets:" + @echo "" + @echo " make build Build the docker image and tag as $(TAG)" + @echo " make test Run smoke tests inside the built image" + @echo " make shell Drop into a one-off bash shell in the image" + @echo " make lint Run shellcheck on the shell scripts" + @echo " make size Print the size of the built image" + @echo " make push Push the image to Docker Hub" + @echo " make clean Remove the local image" + @echo " make help Show this help (default)" + @echo "" + @echo "Override the tag with TAG=... (e.g. make test TAG=jamieleecho/coco-dev:0.79)" + +build: + docker compose -f docker-compose.build.yml build + +test: + docker run --rm -v "$(CURDIR)/tests:/sources:ro" $(TAG) bash -euc '\ + echo "[1/4] java_grinder -> .bin"; \ + work=$$(mktemp -d); cp /sources/java_grinder/* $$work/; cd $$work; \ + javac Hello.java; \ + java_grinder Hello.class Hello.asm trs80_coco; \ + naken_asm -l -type bin -o Hello.bin Hello.asm; \ + test -s Hello.bin; \ + echo "[2/4] basto6809todsk -> .DSK"; \ + work=$$(mktemp -d); cp /sources/basto6809/* $$work/; cd $$work; \ + basto6809todsk HELLO.BAS; \ + test -s HELLO.DSK; \ + echo "[3/4] mcbasic -> .c10"; \ + work=$$(mktemp -d); cp /sources/mcbasic/* $$work/; cd $$work; \ + mcbasic MC10HELLO.BAS; \ + test -s MC10HELLO.c10; \ + echo "[4/4] cmoc --os9 -> OS-9 module"; \ + work=$$(mktemp -d); cp /sources/cmoc-os9/* $$work/; cd $$work; \ + cmoc --os9 hello.c; \ + test -s hello; \ + echo "All smoke tests passed."' + +shell: + docker run --rm -it $(TAG) bash + +lint: + docker run --rm -v "$(CURDIR):/work" -w /work $(SHELLCHECK_IMAGE) \ + shellcheck coco-dev utils/basto6809todsk + +size: + @bytes=$$(docker image inspect --format='{{.Size}}' $(TAG)); \ + awk -v b=$$bytes 'BEGIN { printf "%s: %.2f MB\n", "$(TAG)", b/1024/1024 }' + +push: + docker push $(TAG) + +clean: + -docker rmi $(TAG) diff --git a/README.md b/README.md index 215e5d8..6cf92d6 100644 --- a/README.md +++ b/README.md @@ -75,5 +75,9 @@ your project folder and open the folder in VS Code. See the [documentation](http # Start the Docker application if it is not already running git clone https://github.com/jamieleecho/coco-dev.git cd coco-dev -./build +make build ``` + +Run `make help` to see the available targets. After building, `make test` +runs a quick smoke test that exercises CMOC, BasTo6809, mcbasic, and Java +Grinder against the built image. diff --git a/build b/build deleted file mode 100755 index a393b73..0000000 --- a/build +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -# Build and tag are now handled in a single step -docker compose -f docker-compose.build.yml build diff --git a/coco-dev b/coco-dev index 37c55d2..3fd74fe 100755 --- a/coco-dev +++ b/coco-dev @@ -1,8 +1,8 @@ #!/usr/bin/env bash -if [[ $* = *[!\ ]* ]]; then - params=( "$*" ) +if [[ $# -gt 0 ]]; then + params=( "$@" ) else params=( bash ) fi @@ -12,11 +12,11 @@ COCO_DEV_IMAGE=jamieleecho/coco-dev:0.79 case "$(uname -s)" in Darwin) - docker run -it --rm -w "$(pwd | sed -e s#^/[Uu][Ss][Ee][Rr][Ss]#/home#)" -v "$HOME"/..:/home -e HOME=/home/"$USER" ${COCO_DEV_IMAGE} ${params[@]} + docker run -it --rm -w "$(pwd | sed -e s#^/[Uu][Ss][Ee][Rr][Ss]#/home#)" -v "$HOME"/..:/home -e HOME=/home/"$USER" "${COCO_DEV_IMAGE}" "${params[@]}" ;; Linux) - docker run -u "$(id -u):$(id -g)" -it --rm -w "$(pwd)" -v /etc/passwd:/etc/passwd -v "$HOME"/..:/home -e HOME=/home/"$USER" ${COCO_DEV_IMAGE} ${params[@]} + docker run -u "$(id -u):$(id -g)" -it --rm -w "$(pwd)" -v /etc/passwd:/etc/passwd -v "$HOME"/..:/home -e HOME=/home/"$USER" "${COCO_DEV_IMAGE}" "${params[@]}" ;; CYGWIN*|MINGW32*|MSYS*) @@ -27,7 +27,6 @@ case "$(uname -s)" in # See correspondence table at the bottom of this answer *) - echo 'Unknown OS not supported' + echo 'Unknown OS not supported' ;; esac - diff --git a/tests/basto6809/HELLO.BAS b/tests/basto6809/HELLO.BAS new file mode 100644 index 0000000..8a4715c --- /dev/null +++ b/tests/basto6809/HELLO.BAS @@ -0,0 +1,2 @@ +10 PRINT "HELLO COCO" +20 END diff --git a/tests/cmoc-os9/hello.c b/tests/cmoc-os9/hello.c new file mode 100644 index 0000000..e380a7b --- /dev/null +++ b/tests/cmoc-os9/hello.c @@ -0,0 +1,7 @@ +#include + +int main(void) +{ + printf("Hello from OS-9\n"); + return 0; +} diff --git a/tests/java_grinder/Hello.java b/tests/java_grinder/Hello.java new file mode 100644 index 0000000..7c108a6 --- /dev/null +++ b/tests/java_grinder/Hello.java @@ -0,0 +1,8 @@ +import net.mikekohn.java_grinder.TRS80Coco; + +public class Hello { + public static void main(String[] args) { + TRS80Coco.setText(1024, 0x48); + TRS80Coco.setText(1025, 0x49); + } +} diff --git a/tests/mcbasic/MC10HELLO.BAS b/tests/mcbasic/MC10HELLO.BAS new file mode 100644 index 0000000..9880304 --- /dev/null +++ b/tests/mcbasic/MC10HELLO.BAS @@ -0,0 +1,2 @@ +10 PRINT "HELLO MC-10" +20 END diff --git a/utils/basto6809todsk b/utils/basto6809todsk index 148f98d..83c4cca 100755 --- a/utils/basto6809todsk +++ b/utils/basto6809todsk @@ -1,27 +1,28 @@ -#!/bin/env bash +#!/usr/bin/env bash +set -eu if [[ $# -ne 1 ]] ; then - echo $0 PROG.BAS - echo Compiles PROG.BAS into a binary located on PROG.DSK + echo "$0 PROG.BAS" + echo "Compiles PROG.BAS into a binary located on PROG.DSK" exit 0 fi BAS_FILE="$1" -BAS_FILE0=$(basename ${BAS_FILE}) +BAS_FILE0=$(basename "${BAS_FILE}") ASM_FILE="${BAS_FILE0%.BAS}.asm" BIN_FILE="${BAS_FILE0%.BAS}.BIN" DSK_FILE="${BAS_FILE0%.BAS}.DSK" -CURRENT_DIR="`pwd`" +CURRENT_DIR="$(pwd)" # Create a working folder tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t 'tmpdir') -echo Copying compiler and source file to ${tmpdir} -cp -R /usr/local/share/basto6809/* ${tmpdir} -cp $1 ${tmpdir} -cd ${tmpdir} +echo "Copying compiler and source file to ${tmpdir}" +cp -R /usr/local/share/basto6809/* "${tmpdir}" +cp "$1" "${tmpdir}" +cd "${tmpdir}" # Do real work -echo Compiling ${BAS_FILE} and creating ${ASM_FILE}, ${BIN_FILE} and ${DSK_FILE} +echo "Compiling ${BAS_FILE} and creating ${ASM_FILE}, ${BIN_FILE} and ${DSK_FILE}" ./BasTo6809 "${BAS_FILE0}" lwasm -o "${BIN_FILE}" "$ASM_FILE" decb dskini "${DSK_FILE}"