containers - mvx-lang/mvx GitHub Wiki

Containers

Two images ship MVX to Docker, built from docker/ in the repo:

image what it is
mvx the base system — compiler, shell, runtime, drivers, standard verbs
mvx-demo a ready-to-run account with the example programs cataloged

There was a third, mvx-lmdbd, until mvx#327 removed the daemon. A shared database is now a stock postgres image.

Build both (base first, since the demo layers on it):

docker/build.sh                       # ghcr.io/mvx-lang/mvx{,-demo}:latest
REGISTRY=you TAG=0.1 docker/build.sh  # custom namespace / tag
PUSH=1 docker/build.sh                # build, then docker push each

Each has its own Dockerfile (docker/Dockerfile.base, .demo) if you prefer to build them one at a time. The demo FROMs the base via a BASE build-arg (default mvx), so a published base can be layered on directly.

On a v* git tag, the release GitHub Actions workflow builds and pushes both images multi-arch (linux/amd64 and linux/arm64) to the GitHub Container Registry under ghcr.io/mvx-lang/, alongside the native Linux binary tarballs — see Publishing.

mvx — the base system

A multi-stage build compiles MVX against LLVM and installs it to /usr/local, then a slim runtime layer keeps the install plus a C toolchain (mvx-basic shells out to cc to link programs). mvx is on PATH, and it locates its runtime, drivers, and system account relative to itself — no environment variables.

docker run --rm -it mvx                 # MVX shell in a scratch /work account
docker run --rm mvx mvx-basic -h        # or run any tool directly
docker run --rm -v "$PWD":/src mvx \
  mvx-basic /src/prog.b -o /src/prog     # compile a program from a bind mount

It defaults to the developer privilege tier so BASIC, CATALOG, and COMPILE() work. Use it as the base for your own account images.

Compose: a shared database, local application code

docker/compose.demo.yaml wires a postgres server to two application accounts, modelling the classic MultiValue split: each app keeps its VOC and BP (source) in a local database, while the data files live on the shared server — so both apps read and write the same records.

docker compose -f docker/compose.demo.yaml up -d

Services:

  • mvxdb — a stock postgres:16-alpine; its data persists on a volume.

  • init — a one-shot that defines the connection profile, creates the shared ORDERS and CUSTOMERS files through it, seeds a few records, then exits.

  • app1, app2 — application accounts. Each creates a local VOC and BP, defines the same profile, then writes a BINDINGS record so ORDERS and CUSTOMERS resolve to the server:

    ORDERS    @shared
    CUSTOMERS @shared
    

    The address and the password are not in BINDINGS — it names only the profile, so it is committable. The profile holds the address, and the password arrives as MVXCONN_SHARED_PASSWORD from the environment rather than being written to disk.

Log on to either and the picture is the same shared data:

docker compose -f docker/compose.demo.yaml exec app1 mvx -a /acct
app1> LISTF
File                     Type
BP                       sqlite        # local to app1
VOC                      sqlite        # local to app1
ORDERS                   postgres      # shared, on mvxdb
CUSTOMERS                postgres      # shared, on mvxdb
app1> COUNT ORDERS
2 record(s) counted

A record written from app1 is visible from app2 immediately — they are the same table on the one server — while each app's cataloged verbs and source stay private to its own account. The per-file BINDINGS record is how a second account attaches to a data file the first one created.

mvx-demo — the example account

Boots straight into a /demo account with the example programs cataloged as verbs. Give it a TTY so the full-screen programs render:

docker run --rm -it ghcr.io/mvx-lang/mvx-demo   # or just `mvx-demo` if built locally
demo> SNAKE       # arrows steer; q or ESC quits
demo> FSDEMO      # the Midnight Commander-style full-screen demo

Both are ordinary cataloged BASIC — LISTF, LIST BP, or VI BP SNAKE to look under the hood.

Publishing

Releases are automated and need no external accounts or secrets. Pushing a v* tag runs the release workflow, which publishes both images multi-arch to the GitHub Container Registry under ghcr.io/mvx-lang/ — authenticating with the built-in GITHUB_TOKEN — and attaches per-architecture Linux binary tarballs to the GitHub release:

git tag v0.1.0 && git push origin v0.1.0

The packages are created private; make each public once from the org's Packages settings (or the package page → Package settings → Change visibility) so docker pull ghcr.io/mvx-lang/mvx-demo works without a login. To publish by hand instead, docker/build.sh tags images ${REGISTRY}/mvx{,-demo}:${TAG} (REGISTRY defaults to ghcr.io/mvx-lang); docker login ghcr.io, then run with PUSH=1.