Skip to content
Merged
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
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,29 @@ jobs:
"$PY" scripts/vendor_binaries.py --only gomc-rest-linux-amd64 &&
"$PY" -m pytest -v
'

# Real execution on Apple Silicon: confirms the ad-hoc-signed arm64 binary
# actually launches (Gatekeeper/signing behavior can't be judged by
# inspecting the binary offline). The Intel (amd64) binary is only verified
# offline (SHA-256 + Mach-O inspection) because GitHub's Intel macOS runners
# are not reliably schedulable here — they sat queued for 24h and were
# auto-cancelled.
test-macos:
runs-on: macos-14 # Apple Silicon
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # hatch-vcs derives the version from git tags

- uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install package and test deps
run: python -m pip install -e . pytest

- name: Vendor the macOS server binary
run: python scripts/vendor_binaries.py --only gomc-rest-darwin-arm64

- name: Run tests
run: python -m pytest -v
32 changes: 21 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
name: release

# Build one platform-specific wheel per OS (each bundling only its matching
# Build one platform-specific wheel per target (each bundling only its matching
# gomc-rest binary) plus a binary-free sdist, and publish to PyPI on a version
# tag. The sdist is the client-only fallback: on platforms without a matching
# wheel (macOS, Windows arm64, glibc < 2.34), pip builds it so connect() still
# works (launch() then raises a clear "binary not found/unsupported" error).
# tag. All wheels cross-build on a single Linux runner (a wheel just zips the
# pre-built binary). The sdist is the client-only fallback: on platforms
# without a matching wheel (Windows arm64, glibc < 2.34, macOS < 12), pip
# builds it so connect() still works (launch() then raises a clear "binary not
# found/unsupported" error).
on:
push:
tags:
Expand All @@ -14,25 +16,33 @@ on:
jobs:
build-wheels:
name: wheel (${{ matrix.plat }})
runs-on: ${{ matrix.os }}
# A wheel just zips a pre-built binary and gets its platform tag forced by
# `wheel tags`, so the build host's OS/arch is irrelevant — everything
# cross-builds on one Linux runner (same idea as upstream gomc-rest, which
# cross-compiles all platforms from ubuntu). This avoids depending on
# scarce Windows/arm/macOS runners for releases.
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
asset: gomc-rest.exe
- asset: gomc-rest.exe
plat: win_amd64
# amd64 binary is dynamically linked and needs GLIBC_2.34, so it must
# be tagged manylinux_2_34 (not 2014/glibc 2.17) or pip would install
# it on older systems where it fails with "GLIBC_2.34 not found".
- os: ubuntu-latest
asset: gomc-rest-linux-amd64
- asset: gomc-rest-linux-amd64
plat: manylinux_2_34_x86_64
# arm64 binary is statically linked (no glibc dependency), so the
# widest valid tag is fine.
- os: ubuntu-24.04-arm
asset: gomc-rest-linux-arm64
- asset: gomc-rest-linux-arm64
plat: manylinux2014_aarch64
# Both darwin binaries declare a minimum OS of macOS 12 (Monterey)
# via LC_BUILD_VERSION, so the wheel must not claim an older floor.
- asset: gomc-rest-darwin-amd64
plat: macosx_12_0_x86_64
- asset: gomc-rest-darwin-arm64
plat: macosx_12_0_arm64
steps:
- uses: actions/checkout@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion GOMC_REST_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.4.0
v1.6.0
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Both `launch()` and `connect()` hand you the same `PLCClient`, so one package
covers "bundle and run the server" and "just be a client".

`connect()` needs no bundled binary, so it works even on platforms without a
prebuilt wheel (macOS, Windows arm64, glibc < 2.34): there `pip install
prebuilt wheel (Windows arm64, glibc < 2.34, macOS < 12): there `pip install
gomc-rest` installs from the sdist, and only `launch()` is unavailable (it
raises a clear error).

Expand Down Expand Up @@ -107,7 +107,7 @@ boundary is the trust boundary here.

## Versions

This package bundles a pinned `gomc-rest` binary (currently **v1.4.0**, set in
This package bundles a pinned `gomc-rest` binary (currently **v1.6.0**, set in
`GOMC_REST_VERSION`) that must satisfy `gomc-rest-client`'s
`MINIMUM_SUPPORTED_GOMC_REST_VERSION`; `launch()` verifies this on startup. The
`gomc-rest-client` dependency is capped (`>=0.10.0,<0.11`) so a future client
Expand Down
4 changes: 2 additions & 2 deletions README_JP.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ with gomc_rest.connect("http://192.168.0.1:8080", token="...") as plc:
同じ読み書きAPIを利用できます。

`connect()` は同梱バイナリを必要としないため、対応するビルド済み `wheel` が
ない環境(macOS、Windows arm64、glibc 2.34未満など)でも利用できます。
ない環境(Windows arm64、glibc 2.34未満、macOS 12未満など)でも利用できます。
その場合、`pip install gomc-rest` は `sdist` からパッケージをインストールします。
`connect()` は利用できますが、`launch()` を実行すると、対応するバイナリが
ないことを示すエラーが発生します。
Expand Down Expand Up @@ -117,7 +117,7 @@ finally:
## バージョン

同梱するgomc-restのバージョンは `GOMC_REST_VERSION` で固定しています
(現在は **v1.4.0**)。`launch()` は起動時に、サーバーが
(現在は **v1.6.0**)。`launch()` は起動時に、サーバーが
`gomc-rest-client` の `MINIMUM_SUPPORTED_GOMC_REST_VERSION` を満たしているか
確認します。

Expand Down
28 changes: 22 additions & 6 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,26 @@ Pushing a `v*` tag runs `.github/workflows/release.yml`:

1. **Version** — derived from the tag itself by hatch-vcs
(`dynamic = ["version"]`); there is no version string to keep in sync.
2. **Build wheels** (one per platform, each bundling only its matching
server binary, downloaded and SHA-256-verified at build time):
2. **Build wheels** — all cross-build on a single `ubuntu-latest` runner
(a wheel just zips the matching binary, SHA-256-verified at build time,
then `wheel tags` forces the platform tag; the build host's OS/arch is
irrelevant, same as upstream gomc-rest cross-compiling from Linux):
- `win_amd64` — `gomc-rest.exe`
- `manylinux_2_34_x86_64` — `gomc-rest-linux-amd64` (dynamically linked,
needs glibc ≥ 2.34; hence the 2_34 tag)
- `manylinux2014_aarch64` — `gomc-rest-linux-arm64` (statically linked)
- `macosx_12_0_x86_64` — `gomc-rest-darwin-amd64` (unsigned)
- `macosx_12_0_arm64` — `gomc-rest-darwin-arm64` (ad-hoc signed)

Both darwin binaries declare a minimum OS of macOS 12 via
`LC_BUILD_VERSION`, hence the `macosx_12_0` tags. `ci.yml`'s
`test-macos` job actually launches the server on a real `macos-14`
(Apple Silicon) runner every PR — the authoritative check for
Gatekeeper/signing on arm64. The Intel binary is verified offline only
(SHA-256 + Mach-O inspection); GitHub's Intel macOS runners are not
reliably schedulable, so we don't gate on them.
3. **Build sdist** — no binary; the client-only fallback for platforms
without a wheel (macOS, Windows arm64, older glibc).
without a wheel (Windows arm64, older glibc, macOS < 12).
4. **Publish to PyPI** — trusted publishing (OIDC) via the `pypi`
environment. `skip-existing` makes re-running a tag safe.
5. **GitHub Release** — created only after PyPI publish succeeds, with
Expand Down Expand Up @@ -51,11 +63,15 @@ Only needed when changing the bundled server version:
bump the client pin in `pyproject.toml` together if needed.
2. Add `checksums/<version>.sha256` with the trusted SHA-256 of each
release asset (`gomc-rest.exe`, `gomc-rest-linux-amd64`,
`gomc-rest-linux-arm64`). These are committed so a swapped release
`gomc-rest-linux-arm64`, `gomc-rest-darwin-amd64`,
`gomc-rest-darwin-arm64`). These are committed so a swapped release
asset is detected; vendoring fails closed without them.
3. If the new binaries change their glibc requirement (check with
3. If the Linux binaries change their glibc requirement (check with
`readelf -V <binary> | grep GLIBC`), update the `plat` tags in
`release.yml` and the CI floor test image in `ci.yml`.
`release.yml` and the CI floor test image in `ci.yml`. If the darwin
binaries change their minimum OS (check with `otool -l <binary> | grep
-A3 LC_BUILD_VERSION`, or parse the load command directly), update the
`macosx_*` tags in `release.yml`.

## Local builds (testing without PyPI)

Expand Down
5 changes: 5 additions & 0 deletions checksums/v1.6.0.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
21094f62a98516f83fb1900caf84fcba3f5ba303682189f7c180d37ff3d64e30 gomc-rest.exe
314712bfddcc826fc5ff55a2087f9ae34e108adfbc88d1bbcc1d8609eb799f3d gomc-rest-linux-amd64
f9539bdf0f5952df6b33204c0a93c9513770ad2795df468872e66a80c3963129 gomc-rest-linux-arm64
16bffdfea51e89ee3c83c6ae23ad485d6225f464c31e07ae38aa7e8646c13b36 gomc-rest-darwin-amd64
649c0d889e37708b1e6c0fb4c8503a1fd0c7a82fc666e0a9b5a25f84e73f839e gomc-rest-darwin-arm64
2 changes: 2 additions & 0 deletions scripts/vendor_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"gomc-rest.exe",
"gomc-rest-linux-amd64",
"gomc-rest-linux-arm64",
"gomc-rest-darwin-amd64",
"gomc-rest-darwin-arm64",
]

_ROOT = Path(__file__).resolve().parent.parent
Expand Down
2 changes: 2 additions & 0 deletions src/gomc_rest/_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
("windows", "amd64"): "gomc-rest.exe",
("linux", "amd64"): "gomc-rest-linux-amd64",
("linux", "arm64"): "gomc-rest-linux-arm64",
("darwin", "amd64"): "gomc-rest-darwin-amd64",
("darwin", "arm64"): "gomc-rest-darwin-arm64",
}

_MACHINE_ALIASES = {
Expand Down
12 changes: 7 additions & 5 deletions src/gomc_rest/binaries/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
This directory holds the platform-specific `gomc-rest` server binaries that the
Python package auto-launches (Pattern B):

| Platform | File name |
| --------------- | ------------------------ |
| Windows (amd64) | `gomc-rest.exe` |
| Linux (amd64) | `gomc-rest-linux-amd64` |
| Linux (arm64) | `gomc-rest-linux-arm64` |
| Platform | File name |
| ---------------- | -------------------------- |
| Windows (amd64) | `gomc-rest.exe` |
| Linux (amd64) | `gomc-rest-linux-amd64` |
| Linux (arm64) | `gomc-rest-linux-arm64` |
| macOS (amd64) | `gomc-rest-darwin-amd64` |
| macOS (arm64) | `gomc-rest-darwin-arm64` |

The binaries are **not committed to git**. They are vendored in at release time
from a pinned [gomc-rest](https://github.com/Moge800/gomc-rest) version, and each
Expand Down
Loading