Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: Release

# Push a `vX.Y.Z` tag to cut a release: every supported target is built, the
# archives are attached to a GitHub release, and the Homebrew tap is updated.
# A tag carrying a suffix (`v0.3.0-rc1`) publishes as a prerelease and leaves
# the tap alone — use one to prove the matrix before the real tag.
on:
push:
tags: ["v*"]

permissions:
contents: write

jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# macOS builds run natively per arch. scripts/macho-align.sh (the
# ld64 repack of libtile57.a) invokes `ld -r` and libtool without
# -arch, so it can only repack for the host.
- { target: aarch64-macos, os: macos-latest }
- { target: x86_64-macos, os: macos-15-intel }
# -gnu, not -musl: build.zig retargets the CLI to static musl on a
# glibc host anyway, so these carry a portable `tile57` AND a
# libtile57.a that a glibc C host can link.
- { target: x86_64-linux-gnu, os: ubuntu-latest, deb: amd64 }
- { target: aarch64-linux-gnu, os: ubuntu-latest, deb: arm64 }
- { target: x86_64-windows-gnu, os: ubuntu-latest }
- { target: aarch64-windows-gnu, os: ubuntu-latest }
steps:
- uses: actions/checkout@v7
with:
submodules: recursive

- name: Install Zig
uses: mlugg/setup-zig@v2
with:
version: 0.16.0

# The version is written in three places and the tag is a fourth. A
# mismatch ships a binary whose `tile57 version` contradicts its download.
- name: Check the tag against the version in the source
run: |
v="${GITHUB_REF_NAME#v}"; v="${v%%-*}"
grep -q "\.version = \"$v\"" build.zig.zon
grep -q "pub const version = \"$v\"" src/tile57.zig
grep -q "pub const VERSION = \"tile57 $v\"" tools/common.zig

- name: Build
run: zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseFast

- name: Package
run: scripts/package-release.sh "${GITHUB_REF_NAME#v}" "${{ matrix.target }}" "${{ matrix.deb }}"

- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.target }}
path: dist/*

release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true

- name: Checksums
run: cd dist && shasum -a 256 tile57* > SHA256SUMS

- name: Publish
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
gh release create "$GITHUB_REF_NAME" --generate-notes --verify-tag \
${{ contains(github.ref_name, '-') && '--prerelease' || '' }} \
dist/*

homebrew:
needs: release
if: ${{ !contains(github.ref_name, '-') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true

# A token with write access to the tap repo. Without it the release still
# stands; only the tap goes stale.
- name: Update the Homebrew tap
env:
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -z "$TAP_TOKEN" ]; then
echo "::warning::HOMEBREW_TAP_TOKEN is not set — skipping the tap update"
exit 0
fi
v="${GITHUB_REF_NAME#v}"
git clone --depth 1 \
"https://x-access-token:$TAP_TOKEN@github.com/beetlebugorg/homebrew-tap" tap
mkdir -p tap/Formula
scripts/brew-formula.sh "$v" dist > tap/Formula/tile57.rb
cd tap
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/tile57.rb
git diff --cached --quiet || git commit -m "tile57 $v"
git push
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ cache.sqlite
/.zig-cache/
/zig-out/

# Release archives staged by scripts/package-release.sh
/dist/

# Editor / OS
*.swp
.DS_Store
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ diagrams it carries.
## Start here

```sh
git submodule update --init --recursive # the vendored S-101 catalogue
zig build # writes zig-out/bin/tile57
brew install beetlebugorg/tap/tile57 # or grab a binary from Releases

tile57 bake ENC_ROOT -o out/ # every chart -> its own archive
tile57 png ENC_ROOT --view -76.48,38.974,15 --size 1600x1200 -o chart.png
Expand All @@ -75,8 +74,14 @@ tile57 bake harbour.KAP -o out/ # an RNC sheet -> the same archive
tile57 png ENC_ROOT --over-image --view -76.48,38.974,15 -o over.png
```

The first command bakes a catalogue. The second draws a chart straight to a PNG.
The last one removes the chart's solid areas, so you can draw it over a photo.
`bake` turns a catalogue into per-chart archives. `png` draws a chart straight to
an image. `--over-image` removes the chart's solid areas, so you can draw it over
a photo.

Binaries for macOS, Linux and Windows are attached to every
[release](https://github.com/beetlebugorg/tile57/releases), alongside a `.deb`
and the static library. To build it yourself you need Zig 0.16 and the
submodules — see [Installation](docs/docs/installation.md).

## What you can get

Expand Down
26 changes: 26 additions & 0 deletions docs/docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,32 @@ Direct pull requests are welcome. Please:
[Installation](./installation.md)).
- Expect review for correctness and safety, the same as AI-assisted changes.

## Cutting a release

The version lives in three files and has to agree with the tag — the release
build checks all three and stops if they diverge:

- `build.zig.zon` — `.version`
- `src/tile57.zig` — `pub const version`
- `tools/common.zig` — `pub const VERSION`

Bump them, commit, then tag and push:

```sh
git tag v0.4.0 && git push origin v0.4.0
```

`.github/workflows/release.yml` builds macOS, Linux and Windows on x86-64 and
arm64, attaches the archives, the `.deb`s and `SHA256SUMS` to a GitHub release,
and updates the Homebrew tap. A tag with a suffix — `v0.4.0-rc1` — publishes as
a prerelease and leaves the tap alone; use one to exercise the matrix before the
real tag. `scripts/package-release.sh <version> <target>` produces the same
archive locally after a `zig build`.

The tap lives in [beetlebugorg/homebrew-tap](https://github.com/beetlebugorg/homebrew-tap)
and its formula is generated, not hand-edited; the release workflow needs a
`HOMEBREW_TAP_TOKEN` secret with write access to it.

## The process

1. **Open** an issue or a requirement/prototype.
Expand Down
99 changes: 65 additions & 34 deletions docs/docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,94 @@ sidebar_position: 2

# Installation

tile57 builds from source with **Zig 0.16** — no CMake, no system libraries
beyond Zig itself. There are no pre-built binaries.
Every [release](https://github.com/beetlebugorg/tile57/releases) ships pre-built
binaries for macOS, Linux and Windows on x86-64 and arm64. Each archive carries
the `tile57` CLI, the static library `libtile57.a`, and the C header
`include/tile57.h`. The IHO S-101 Portrayal Catalogue is embedded in both, so
nothing else has to be on disk at run time.

## 1. Clone + fetch the submodules
## Homebrew (macOS and Linux)

```sh
git clone https://github.com/beetlebugorg/tile57.git
cd tile57
git submodule update --init --recursive
brew install beetlebugorg/tap/tile57
```

The vendored **IHO S-101 Portrayal Catalogue** comes in as a submodule (under
`vendor/`). It is a **build-time** dependency: `zig build` embeds the
catalogue (the Lua portrayal rules plus the symbols, line styles, area fills and
colour profile) directly into the binary via `@embedFile`, so the resulting
`tile57` needs no on-disk catalogue at runtime. Lua 5.4 is vendored under
`vendor/lua` and compiled in, so no system Lua is needed either.
## Debian and Ubuntu

```sh
curl -LO https://github.com/beetlebugorg/tile57/releases/latest/download/tile57_0.3.0_amd64.deb
sudo apt install ./tile57_0.3.0_amd64.deb
```

## 2. Zig 0.16.0 (required)
`arm64` is published alongside `amd64`. There is no apt repository — the `.deb`
is a release asset, so upgrades mean downloading the next one.

The engine, the `tile57` CLI, and the static library all need **Zig 0.16.0**.
Install it from [ziglang.org/download](https://ziglang.org/download/) (pin
0.16.0) and put it on your `PATH`.
## Direct download

## 3. Build + test
Pick the archive for your platform from the
[latest release](https://github.com/beetlebugorg/tile57/releases/latest) —
`tile57-<version>-<arch>-<os>.tar.gz`, or `.zip` for Windows — and put `bin/tile57`
on your `PATH`:

```sh
zig build # builds zig-out/bin/tile57 + libtile57.a
zig build test # runs the test suite
tar xzf tile57-0.3.0-aarch64-macos.tar.gz
sudo install -m755 tile57-0.3.0-aarch64-macos/bin/tile57 /usr/local/bin/
tile57 version
```

`zig build` produces:
Every release includes a `SHA256SUMS` file. Verify before installing:

```sh
curl -LO https://github.com/beetlebugorg/tile57/releases/latest/download/SHA256SUMS
shasum -a 256 -c SHA256SUMS --ignore-missing
```

macOS binaries are not notarized. Gatekeeper quarantines a downloaded archive, so
clear it once — `xattr -d com.apple.quarantine ./tile57` — or install through
Homebrew, which does it for you.

## Build from source

Building needs **Zig 0.16.0** and nothing else — no CMake, no system libraries.
Install Zig from [ziglang.org/download](https://ziglang.org/download/) (pin
0.16.0) and put it on your `PATH`.

```sh
git clone https://github.com/beetlebugorg/tile57.git
cd tile57
git submodule update --init --recursive # the vendored S-101 catalogue
zig build # builds zig-out/bin/tile57 + libtile57.a
zig build test # runs the test suite
```

| Target | What it is |
|--------|-----------|
| `tile57` (`zig-out/bin/tile57`) | the offline CLI: bake charts/ENC_ROOTs to PMTiles or a chart bundle, and emit portrayal assets. |
| `libtile57.a` | the static library behind the [C ABI](./c-api.md) (`include/tile57.h`). |

The engine is also a Zig package named `tile57` (v0.3.0); a Zig consumer
depends on it and uses `@import("tile57")` — see the [Zig API](./zig-api.md).
The **IHO S-101 Portrayal Catalogue** comes in as a git submodule under `vendor/`.
It is a *build-time* dependency: `zig build` embeds the catalogue — the Lua
portrayal rules plus the symbols, line styles, area fills and colour profile —
directly into the binary via `@embedFile`. Lua 5.4 is vendored under `vendor/lua`
and compiled in, so no system Lua is needed either.

## As a Zig package

The engine is a Zig package named `tile57` (v0.3.0). Fetch it by tag:

:::note Consume it as a path dependency (for now)
Depend on a local clone via a `.path` dependency in your `build.zig.zon`,
with the clone's submodules initialised:
```sh
zig fetch --save "https://github.com/beetlebugorg/tile57/archive/refs/tags/v0.3.0.tar.gz"
```

```zig
.dependencies = .{
.tile57 = .{ .path = "../tile57" },
},
const tile57 = b.dependency("tile57", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("tile57", tile57.module("tile57"));
```

**Known issue:** fetching by URL/hash (`zig fetch --save <url>`) does not work
yet — `build.zig.zon`'s `.paths` currently ships only `build.zig`,
`build.zig.zon`, and `src/`, so a fetched package is missing `vendor/` (the
embedded catalogue + Lua), `include/`, `tools/`, and the LICENSE, and cannot
build. Until that's fixed, use a path dependency.
:::
A fetched package carries its own copy of the portrayal catalogue (Zig's fetcher
does not follow git submodules, so the catalogue arrives as a lazy package
dependency instead) — no submodule init needed. See the
[Zig API](./zig-api.md) for what the module exposes.

## Runtime knob

Expand Down
7 changes: 3 additions & 4 deletions docs/docs/zig-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ source charts bake once to per-chart archives, and every output is produced
from baked archives. These pages are grouped the same way as the [C API](./c-api.md).

:::note
Add it as a **path dependency** on a local clone (submodules initialised) —
`zig fetch` by URL/hash is currently broken because the package's declared
`.paths` omit `vendor/` and `include/`. See
[Installation](./installation.md).
`zig fetch --save "https://github.com/beetlebugorg/tile57/archive/refs/tags/v0.3.0.tar.gz"`
adds it. A fetched package carries the S-101 catalogue as a lazy dependency, so
there are no submodules to initialise. See [Installation](./installation.md).
:::

## Sections
Expand Down
61 changes: 61 additions & 0 deletions scripts/brew-formula.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# Print the Homebrew formula for a released version, reading each archive's
# sha256 out of <dist-dir> (the tarballs that release.yml just published).
# The tap job pipes this into Formula/tile57.rb.
#
# Usage: brew-formula.sh <version> <dist-dir>
set -euo pipefail

version="$1"
dist="$2"
base="https://github.com/beetlebugorg/tile57/releases/download/v$version"

sha() { shasum -a 256 "$dist/tile57-$version-$1.tar.gz" | cut -d' ' -f1; }

# Resolved before the heredoc: a command substitution that fails inside one is
# not caught by `set -e`, and a missing archive would emit an empty sha256.
mac_arm="$(sha aarch64-macos)"
mac_intel="$(sha x86_64-macos)"
linux_arm="$(sha aarch64-linux-gnu)"
linux_intel="$(sha x86_64-linux-gnu)"

cat <<EOF
class Tile57 < Formula
desc "Nautical chart engine: IHO S-101 and S-57 charts to tiles, PNG, and PDF"
homepage "https://github.com/beetlebugorg/tile57"
version "$version"
license "MIT"

on_macos do
on_arm do
url "$base/tile57-$version-aarch64-macos.tar.gz"
sha256 "$mac_arm"
end
on_intel do
url "$base/tile57-$version-x86_64-macos.tar.gz"
sha256 "$mac_intel"
end
end

on_linux do
on_arm do
url "$base/tile57-$version-aarch64-linux-gnu.tar.gz"
sha256 "$linux_arm"
end
on_intel do
url "$base/tile57-$version-x86_64-linux-gnu.tar.gz"
sha256 "$linux_intel"
end
end

def install
bin.install "bin/tile57"
lib.install "lib/libtile57.a"
include.install "include/tile57.h"
end

test do
assert_match version.to_s, shell_output("#{bin}/tile57 version 2>&1")
end
end
EOF
Loading