Skip to content

Commit 15fe7fa

Browse files
millergarymGary Millerpdubroy
authored
Dockerize (#578)
Co-authored-by: Gary Miller <gary@helixcollective.com> Co-authored-by: Patrick Dubroy <pdubroy@gmail.com>
1 parent 2fef8b5 commit 15fe7fa

13 files changed

Lines changed: 321 additions & 13 deletions

File tree

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Dockerfile
2+
**/node_modules
3+
**/node_modules/**
4+
docker-compose.yml
5+
docker-compose.dev.yml
6+
doc/**
7+
.dockerignore
8+
**/build
9+
**/dist
10+
packages/compiler/test/go/testmain
11+
12+
# committed to repo - see 'git ls-files packages/ohm-js/dist'
13+
!packages/ohm-js/dist

.github/workflows/node.js.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ jobs:
2424
with:
2525
node-version: ${{ matrix.node-version }}
2626
- uses: pnpm/action-setup@v2
27+
with:
28+
version: 10
2729
- run: pnpm install
2830
- run: pnpm ci-test

.github/workflows/publish-preview.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717
with:
1818
node-version: 22
1919
- uses: pnpm/action-setup@v2
20+
with:
21+
version: 10
2022
- run: pnpm install
2123
- run: pnpm build
2224
- run: pnpm dlx pkg-pr-new publish './packages/compiler' './packages/runtime' './packages/to-ast-compat'

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ The easiest way to get started with Ohm is to use the [interactive editor](https
3737
- For community support and discussion, join us on [Discord](https://discord.gg/KwxY5gegRQ), [GitHub Discussions](https://github.com/ohmjs/ohm/discussions), or the [ohm-discuss mailing list](https://groups.google.com/u/0/g/ohm-discuss).
3838
- For updates, follow on [Bluesky](hhttps://bsky.app/profile/ohmjs.org) or [Mastodon](https://hachyderm.io/@ohmjs).
3939

40+
### Docker
41+
42+
You can use the Ohm CLI without a local Node.js installation via the Docker image:
43+
44+
```sh
45+
docker run --rm -v $(pwd):/local ohmjs/ohm:latest compile my-grammar.ohm
46+
```
47+
48+
For full usage instructions, including how to build the image locally and set up a development container, see [doc/docker.md](doc/docker.md).
49+
4050
### Installation
4151

4252
#### On a web page

doc/docker.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Using Ohm.js with Docker
2+
3+
The `ohm:latest` image provides the Ohm compiler CLI in a self-contained environment — no local Node.js or pnpm installation required.
4+
5+
## Commands overview
6+
7+
| Command | Description |
8+
|-------------------|-------------|
9+
| `compile` | Compile an `.ohm` grammar file to a `.wasm` module |
10+
| `generateBundles` | Generate grammar bundles (currently not working) |
11+
| `shell` | Open a bash shell inside the container |
12+
| `help` | Print usage information |
13+
14+
Your current directory is mounted at `/local` inside the container, so relative paths to grammar files work as expected.
15+
16+
---
17+
18+
## 1. Running
19+
20+
Pull and run the image directly from Docker Hub:
21+
22+
```sh
23+
docker run --rm -v $(pwd):/local ohmjs/ohm:latest compile my-grammar.ohm
24+
```
25+
26+
### `compile` usage
27+
28+
```sh
29+
docker run --rm -v $(pwd):/local ohmjs/ohm:latest compile [options] <grammar-file>
30+
```
31+
32+
Options:
33+
34+
| Flag | Description |
35+
|-------------------------------|-------------|
36+
| `--debug` / `-d` | Enable debug output |
37+
| `--grammarName` / `-g <name>` | Override the grammar name |
38+
| `--output` / `-o <file>` | Write output to `<file>` instead of `<grammar-file>.wasm` |
39+
40+
**Example** — compile `arithmetic.ohm` and write the result to `arithmetic.wasm`:
41+
42+
```sh
43+
docker run --rm -v $(pwd):/local ohmjs/ohm:latest compile -o arithmetic.wasm arithmetic.ohm
44+
```
45+
46+
### Getting help
47+
48+
```sh
49+
docker run --rm ohmjs/ohm:latest help
50+
```
51+
52+
---
53+
54+
## 2. Development
55+
56+
### Minimal Docker setup for macOS
57+
58+
```sh
59+
brew install colima docker docker-compose docker-credential-helper
60+
colima start
61+
```
62+
63+
Add to `~/.docker/config.json`:
64+
65+
```json
66+
{
67+
"cliPluginsExtraDirs": [
68+
"/opt/homebrew/lib/docker/cli-plugins"
69+
]
70+
}
71+
```
72+
73+
> **Note:** If you see `docker-credential-desktop` errors, remove `"credsStore": "desktop"` from `~/.docker/config.json` — it references Docker Desktop, which isn't needed with Colima.
74+
75+
### Building the image locally
76+
77+
Clone the repository and build the production image with Docker Compose:
78+
79+
```sh
80+
git clone https://github.com/ohmjs/ohm.git
81+
cd ohm
82+
docker compose -f docker/docker-compose.yml build
83+
```
84+
85+
This builds the `ohm:latest` image using the `dist` stage of the multi-stage `Dockerfile`, which produces a slim image containing only the compiled packages and their production dependencies.
86+
87+
The `ohm:latest` image is 664 MB and is 99% space efficient (per `wagoodman/dive`).
88+
89+
### Building a development image
90+
91+
The development image uses the `build` stage of the `Dockerfile`, which includes the full source tree, all dev dependencies, and the complete build output. This is useful for iterating on the compiler or debugging build issues.
92+
93+
**Build:**
94+
95+
```sh
96+
TARGET=build docker compose -f docker/docker-compose.yml build
97+
```
98+
99+
This produces the `ohmjs/ohm:development` image.
100+
101+
**Run:**
102+
103+
```sh
104+
docker run -v $(pwd):/local -it --rm ohmjs/ohm:development shell
105+
# or
106+
docker run -v ${PWD}:/local -it --rm ohmjs/ohm:development shell
107+
```
108+
109+
The `-v $(pwd):/local` mount makes your current directory available at `/local` inside the container. The `shell` command drops you into a bash session where you can inspect the built artifacts under `/ohm/` or run CLI commands directly.
110+
111+
The `ohm-dev:latest` images is 1.62 GB and is 97% efficient with only 64 MB potentially wasted space.
112+
113+
### Publishing to Docker Hub
114+
115+
Build and push a versioned image to Docker Hub using the git tag as the version:
116+
117+
```sh
118+
# if not set default to ohmjs (ie docker hub using the ohmjs org)
119+
export DOCKER_REPO=<custom docker repo>
120+
# if not set defaults to 'development'
121+
export VERSION=$(cat packages/runtime/package.json | jq -r '.version')
122+
# or export VERSION=$(git describe --tag --dirty)
123+
124+
# # it might be necessary (particularly on osx) to create a new builder
125+
# # the default builder might not support multi-platform builds
126+
# docker buildx create --use --name ohmjs-builder
127+
# # might be needed
128+
# docker buildx inspect --bootstrap
129+
# # or if already created
130+
# docker buildx use ohmjs-builder
131+
132+
# generate a person access token at https://app.docker.com/accounts/millergarym/settings/personal-access-tokens
133+
# assuming DHPAT contains your PAT
134+
echo $DHPAT | docker login -u <personal username> --password-stdin
135+
docker buildx bake --push
136+
```
137+
138+
`git describe --tag --dirty` produces a version string based on the nearest git tag, appending commit info and a `-dirty` suffix if there are uncommitted changes.
139+
140+
The defaults in `docker-compose.yml` are `DOCKER_REPO=ohmjs` and `VERSION=development`. See [docker-compose.yml](../docker/docker-compose.yml) for details.
141+
142+
## Tips and Tricks
143+
144+
### Image size
145+
146+
To track down file which can be deleted.
147+
148+
**From inside the container**
149+
```sh
150+
apt-get update
151+
apt-get install -y ncdu
152+
ncdu /
153+
```
154+
155+
**Analysing the images**
156+
```sh
157+
alias dive="docker run -ti --rm -v /var/run/docker.sock:/var/run/docker.sock docker.io/wagoodman/dive"
158+
dive ohmjs/ohm:latest
159+
```

docker/Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM node:24 AS build
2+
3+
RUN npm install -g pnpm@latest-10
4+
5+
WORKDIR /ohm
6+
COPY package.json pnpm-lock.yaml ./
7+
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
8+
CI=true pnpm fetch
9+
10+
COPY . /ohm
11+
12+
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
13+
CI=true pnpm install --frozen-lockfile --offline && \
14+
CI=true pnpm build
15+
16+
ENTRYPOINT [ "/ohm/docker/entrypoint.sh" ]
17+
18+
CMD ["help"]
19+
20+
FROM node:24-slim AS dist
21+
22+
RUN npm install -g pnpm@latest-10
23+
24+
WORKDIR /ohm
25+
26+
COPY package.json pnpm-lock.yaml ./
27+
COPY docker/pnpm-workspace.yaml ./pnpm-workspace.yaml
28+
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
29+
CI=true pnpm fetch --prod
30+
31+
COPY --from=build /ohm/packages/ohm-js /ohm/packages/ohm-js
32+
COPY --from=build /ohm/packages/runtime /ohm/packages/runtime
33+
COPY --from=build /ohm/packages/to-ast-compat /ohm/packages/to-ast-compat
34+
COPY --from=build /ohm/packages/compiler /ohm/packages/compiler
35+
COPY --from=build /ohm/packages/semantics /ohm/packages/semantics
36+
COPY --from=build /ohm/packages/lang-python /ohm/packages/lang-python
37+
COPY --from=build /ohm/packages/cli /ohm/packages/cli
38+
39+
# Note:
40+
# The build stage fetched all dependencies, where as the dist stage only fetches production dependencies.
41+
# This means that some symlinks, copied from the build stage, will be broken in the dist stage.
42+
# Safely remove all broken symlinks.
43+
RUN find /ohm/packages -xtype l | xargs rm
44+
45+
COPY ./docker/entrypoint.sh entrypoint.sh
46+
ENTRYPOINT [ "/ohm/entrypoint.sh" ]
47+
48+
CMD ["help"]

docker/docker-compose.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: ohmjs
2+
3+
services:
4+
5+
ohm:
6+
build:
7+
context: ..
8+
dockerfile: docker/Dockerfile
9+
tags:
10+
- ${DOCKER_REPO:-ohmjs}/ohm:latest
11+
- ${DOCKER_REPO:-ohmjs}/ohm:${VERSION:-development}
12+
labels:
13+
- org.opencontainers.image.source=https://github.com/${OWNER:-ohmjs}/${REPO:-ohm}
14+
- org.opencontainers.image.licenses=MIT
15+
- org.opencontainers.image.description=Ohm tooling - A library and language for building parsers, interpreters, compilers, etc.
16+
x-bake:
17+
platforms:
18+
- linux/amd64
19+
# - linux/arm/v7
20+
- linux/arm64/v8
21+
# - linux/ppc64le
22+
# - linux/s390x
23+
target: ${TARGET:-dist}
24+
volumes:
25+
- .:/local
26+
command: ["help"]

docker/entrypoint.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
3+
function usage() {
4+
echo "Usage: docker run --rm -v \`pwd\`:/local ohm:lastest <cmd>"
5+
echo ""
6+
echo " where cmd is compile, generateBundles or shell"
7+
echo ""
8+
echo " compile usage: [(--debug|-d)] [(--grammarName|-g) <name>] [(--output|-o) <file>] <ohm-grammar-file>"
9+
echo ""
10+
echo " generateBundles - currently not working"
11+
echo ""
12+
echo " shell: drop into a bash shell in the container, useful for debug the docker build"
13+
echo ""
14+
}
15+
16+
if [ "$1" = "help" ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
17+
usage
18+
exit 0
19+
fi
20+
21+
case "$1" in
22+
compile)
23+
shift
24+
mkdir -p /local
25+
cd /local
26+
node \
27+
--disable-warning=ExperimentalWarning \
28+
/ohm/packages/compiler/dist/src/cli.js "$@"
29+
;;
30+
generateBundles)
31+
set -x
32+
shift
33+
mkdir -p /local
34+
cd /local
35+
node /ohm/packages/cli/src/cli.js generateBundles "$@"
36+
;;
37+
shell)
38+
/bin/bash
39+
;;
40+
*)
41+
echo "Unknown command: $1"
42+
usage
43+
exit 1
44+
;;
45+
esac

docker/pnpm-workspace.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
packages:
2+
- 'packages/*'
3+
linkWorkspacePackages: true
4+
# injectWorkspacePackages: true
5+
minimumReleaseAge: 1440

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"private": true,
3-
"packageManager": "pnpm@10.10.0",
43
"scripts": {
54
"api-report": "pnpm --filter ohm-js --filter @ohm-js/compiler api-report",
65
"build": "pnpm -r build",

0 commit comments

Comments
 (0)