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
45 changes: 45 additions & 0 deletions .github/workflows/build-musllinux-wheel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Build musllinux wheels for Alpine. Upstream only publishes manylinux (glibc).
name: Build musllinux wheel

on:
workflow_dispatch:
push:
tags:
- "v*-musl*"

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Build musllinux_1_2_x86_64 wheel
run: |
chmod +x scripts/build_musllinux_wheel.sh
OUT_DIR="${{ github.workspace }}/dist" ./scripts/build_musllinux_wheel.sh

- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: musllinux-x86_64-wheel
path: dist/*.whl
if-no-files-found: error

- name: Create GitHub Release (tag pushes)
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: dist/*.whl
generate_release_notes: true
body: |
Musllinux (Alpine/musl) wheel.

Pin with uv find-links (example):
```toml
[tool.uv]
find-links = ["https://github.com/${{ github.repository }}/releases/expanded_assets/${{ github.ref_name }}"]
```
Keep `c2pa-python==0.37.1` (or matching) on PyPI for macOS/glibc; uv selects this wheel on Alpine via the `musllinux` tag.
35 changes: 19 additions & 16 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
name: Build

# DISABLED on this fork — see MUSLLINUX.md. Restore the commented `on:` to match upstream.
on:
pull_request:
types:
- opened
- reopened
- synchronize
- labeled
push:
branches:
- main
tags:
- "*"
workflow_dispatch:
inputs:
publish:
description: 'Publish'
required: true
default: 'false'
# on:
# pull_request:
# types:
# - opened
# - reopened
# - synchronize
# - labeled
# push:
# branches:
# - main
# tags:
# - "*"
# workflow_dispatch:
# inputs:
# publish:
# description: 'Publish'
# required: true
# default: 'false'

permissions:
contents: read
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/closing_ticket.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# it will update the workflow labels appropriately.

name: Closing ticket
# DISABLED on this fork — see MUSLLINUX.md.
on:
issues:
types: [closed]
workflow_dispatch:
# on:
# issues:
# types: [closed]
jobs:
label_issues:
runs-on: ubuntu-latest
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/labeling_ticket_done.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# This ensures that when a ticket is labeled as Done in Jira, it will close the ticket on GitHub.

name: Labeling ticket "Done"
# DISABLED on this fork — see MUSLLINUX.md.
on:
issues:
types: [labeled]
workflow_dispatch:
# on:
# issues:
# types: [labeled]
jobs:
label_issues:
runs-on: ubuntu-latest
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/labeling_ticket_todo.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# This ensures that when a ticket is not labeled as Done in Jira, it will re-open the ticket on GitHub.

name: Labeling ticket "To Do"
# DISABLED on this fork — see MUSLLINUX.md.
on:
issues:
types: [labeled]
workflow_dispatch:
# on:
# issues:
# types: [labeled]
jobs:
label_issues:
runs-on: ubuntu-latest
Expand Down
15 changes: 9 additions & 6 deletions .github/workflows/memory-benchmark.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
name: Python SDK memray memory benchmark

# DISABLED on this fork — see MUSLLINUX.md. Restore the commented `on:` to match upstream.
on:
pull_request:
types:
- opened
- reopened
- synchronize
- labeled
workflow_dispatch:
# on:
# pull_request:
# types:
# - opened
# - reopened
# - synchronize
# - labeled

permissions:
contents: read
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/publish-docs.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
name: Build and publish docs

# DISABLED on this fork — see MUSLLINUX.md. Restore the commented `on:` to match upstream.
on:
release:
types: [published]

workflow_dispatch:
# on:
# release:
# types: [published]
# workflow_dispatch:

permissions:
contents: read
Expand Down
7 changes: 5 additions & 2 deletions .github/workflows/reopening_ticket.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# workflow labels in GitHub appropriately.

name: Reopening ticket
# DISABLED on this fork — see MUSLLINUX.md.
on:
issues:
types: [reopened]
workflow_dispatch:
# on:
# issues:
# types: [reopened]
jobs:
label_issues:
runs-on: ubuntu-latest
Expand Down
85 changes: 85 additions & 0 deletions MUSLLINUX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Musllinux wheels (this fork)

## Why this exists

Upstream [contentauth/c2pa-python](https://github.com/contentauth/c2pa-python) publishes **manylinux** (glibc) wheels only.

Alpine (`python:*-alpine`, **musl**) cannot load those wheels; the sdist pulls gnu natives that fail at `dlopen`; compiling Rust inside every image build is too slow.

This fork builds and publishes **musllinux** wheels so Alpine can `import c2pa` without a per-image Rust compile. The Python API is unchanged. macOS and glibc Linux keep using PyPI.

Active surface area (keep this small):

| Path | Purpose |
| --- | --- |
| `scripts/build_musllinux_wheel.sh` | Build musllinux wheel in Docker |
| `.github/workflows/build-musllinux-wheel.yml` | CI + GitHub Release on `v*-musl*` tags |
| `MUSLLINUX.md` | This file |

Upstream Adobe Actions (Build/PyPI, Pages, Jira ticket labels, memray) are **disabled** here so musl tags do not fan out into their matrix or publish to PyPI.

## How to upgrade

When Adobe ships a new `c2pa-python` / `c2pa-rs` pair:

1. **Fetch upstream** into this fork (rebase or merge `contentauth/c2pa-python` `main`).
2. **Re-apply fork bits** if the upgrade wiped them:
- `scripts/build_musllinux_wheel.sh`
- `.github/workflows/build-musllinux-wheel.yml`
- disabled triggers on unused workflows (see below)
- this `MUSLLINUX.md`
3. **Confirm pins** match the intended Adobe release:
- `pyproject.toml` → `[project].version` (e.g. `0.37.1`)
- `c2pa-native-version.txt` → `c2pa-rs` tag (e.g. `c2pa-v0.90.1`)
4. **Build & publish** a musllinux wheel:
```bash
./scripts/build_musllinux_wheel.sh
# or push a tag and let CI do it:
git tag v<version>-musl.1 # e.g. v0.37.1-musl.1
git push origin v<version>-musl.1
```
Tag shape: `v<python-package-version>-musl.<n>`
Bump `<n>` for a rebuild of the same Adobe version (link flags, script fixes).
5. **Consume** from the release (example with uv):

```toml
dependencies = [
"c2pa-python==0.37.1",
]

[tool.uv]
# Prefer releases/expanded_assets/<tag> if /releases/download/<tag>/ 404s as a directory.
find-links = [
"https://github.com/<org>/<repo>/releases/expanded_assets/v0.37.1-musl.1",
]
```

Do **not** set `c2pa-python = { url = "...musllinux....whl" }` — that forces one platform everywhere. Use find-links + wheel tags so macOS/glibc still take PyPI.

### Local build

Requires Docker (linux/amd64):

```bash
./scripts/build_musllinux_wheel.sh
OUT_DIR=/tmp/wheels ./scripts/build_musllinux_wheel.sh
```

Runtime on Alpine needs `libgcc` / `libstdc++` (apk).

### Disabled upstream Actions

These workflow files are kept for easier upstream merges, but their triggers are stubbed so they do not run on this fork:

- `build.yml` (+ callee `build-wheel.yml`) — Adobe multi-platform Build / PyPI publish
- `publish-docs.yml` — GitHub Pages
- `memory-benchmark.yml`
- `closing_ticket.yml` / `labeling_ticket_*.yml` / `reopening_ticket.yml` — Adobe Jira label sync

Only `build-musllinux-wheel.yml` should run automatically (on `v*-musl*` tags or `workflow_dispatch`).

## Current pin

- Package: `0.37.1`
- Native: `c2pa-v0.90.1`
- Release tag: `v0.37.1-musl.1`
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ To use the module in Python code, import the module like this:
import c2pa
```

**This fork:** Alpine/musl wheels are not on PyPI. See [MUSLLINUX.md](MUSLLINUX.md).

## Building from local c2pa-rs sources

### Using a virtual environment with local builds
Expand Down
64 changes: 64 additions & 0 deletions scripts/build_musllinux_wheel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env sh
# Build a musllinux_1_2_x86_64 wheel of c2pa-python for Alpine (musl).
#
# Upstream only publishes manylinux (glibc) wheels. This script clones the
# c2pa-rs tag from c2pa-native-version.txt, builds c2pa-c-ffi inside
# python:3.14-alpine, and packs a musllinux wheel into dist/.
#
# Usage (from repo root):
# ./scripts/build_musllinux_wheel.sh
# OUT_DIR=/tmp/wheels ./scripts/build_musllinux_wheel.sh
#
# Requires: docker.

set -eu

ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)"
C2PA_RS_TAG="$(tr -d '[:space:]' <"$ROOT/c2pa-native-version.txt")"
OUT_DIR="${OUT_DIR:-$ROOT/dist}"
PLATFORM_TAG="musllinux_1_2_x86_64"
# setup.py only knows gnu artifact folder names; the wheel tag is set via --plat-name.
ARTIFACT_PLATFORM="x86_64-unknown-linux-gnu"
PYTHON_IMAGE="${PYTHON_IMAGE:-python:3.14-alpine}"

echo "c2pa-rs tag: $C2PA_RS_TAG"
echo "python image: $PYTHON_IMAGE"
echo "wheel tag: $PLATFORM_TAG"

mkdir -p "$OUT_DIR"
# Clone + cargo target stay inside the container so host cleanup never hits
# root-owned files from a bind-mounted target/ directory.
docker run --rm --platform linux/amd64 \
-e C2PA_RS_TAG="$C2PA_RS_TAG" \
-e ARTIFACT_PLATFORM="$ARTIFACT_PLATFORM" \
-e PLATFORM_TAG="$PLATFORM_TAG" \
-v "$ROOT:/c2pa-python:ro" \
-v "$OUT_DIR:/out" \
-w /tmp/build \
"$PYTHON_IMAGE" \
sh -c '
set -eux
# perl: required to configure vendored openssl-src during cargo build
apk add --no-cache build-base rust cargo openssl-dev pkgconfig git perl
cp -a /c2pa-python/. /tmp/build/
rm -rf artifacts build dist src/c2pa/libs
mkdir -p "artifacts/$ARTIFACT_PLATFORM" src/c2pa/libs

git clone --depth 1 --branch "$C2PA_RS_TAG" https://github.com/contentauth/c2pa-rs.git /tmp/c2pa-rs
cd /tmp/c2pa-rs
cargo build --release -p c2pa-c-ffi --features file_io
cp target/release/libc2pa_c.so "/tmp/build/artifacts/$ARTIFACT_PLATFORM/"
cp target/release/libc2pa_c.so /tmp/build/src/c2pa/libs/
ldd target/release/libc2pa_c.so

cd /tmp/build
pip install -q -r requirements.txt -r requirements-dev.txt build wheel "setuptools>=68" toml
python setup.py bdist_wheel --plat-name "$PLATFORM_TAG"
ls -la dist/
cp dist/*.whl /out/
pip install -q dist/*.whl
python -c "import c2pa; c=c2pa.Context(); c.__enter__(); c.__exit__(None,None,None); print(\"import_ok\", c2pa.__file__)"
'

echo "Wheels written to $OUT_DIR:"
ls -la "$OUT_DIR"/*.whl