kohakuclip 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kohakuclip-1.0.0/.github/workflows/auto-patch-release.yml +79 -0
- kohakuclip-1.0.0/.github/workflows/ci.yml +124 -0
- kohakuclip-1.0.0/.github/workflows/nightly.yml +96 -0
- kohakuclip-1.0.0/.github/workflows/release.yml +214 -0
- kohakuclip-1.0.0/.gitignore +251 -0
- kohakuclip-1.0.0/Cargo.lock +846 -0
- kohakuclip-1.0.0/Cargo.toml +39 -0
- kohakuclip-1.0.0/Change.md +34 -0
- kohakuclip-1.0.0/LICENSE +201 -0
- kohakuclip-1.0.0/PKG-INFO +253 -0
- kohakuclip-1.0.0/README.md +229 -0
- kohakuclip-1.0.0/benchmarks/bench.py +141 -0
- kohakuclip-1.0.0/benchmarks/gpu_check.py +163 -0
- kohakuclip-1.0.0/benchmarks/leak_check.py +99 -0
- kohakuclip-1.0.0/benchmarks/loader_bench.py +76 -0
- kohakuclip-1.0.0/examples/lightning_module.py +72 -0
- kohakuclip-1.0.0/examples/torch_loop.py +96 -0
- kohakuclip-1.0.0/pyproject.toml +46 -0
- kohakuclip-1.0.0/rustfmt.toml +3 -0
- kohakuclip-1.0.0/scripts/ci/release_notes.py +63 -0
- kohakuclip-1.0.0/scripts/ci/version.py +99 -0
- kohakuclip-1.0.0/scripts/ci/wheel_smoke.py +40 -0
- kohakuclip-1.0.0/src/kclip_rs/decode/decoder.rs +73 -0
- kohakuclip-1.0.0/src/kclip_rs/decode/emit.rs +101 -0
- kohakuclip-1.0.0/src/kclip_rs/decode/mod.rs +148 -0
- kohakuclip-1.0.0/src/kclip_rs/decode/profile.rs +37 -0
- kohakuclip-1.0.0/src/kclip_rs/image/color.rs +79 -0
- kohakuclip-1.0.0/src/kclip_rs/image/mod.rs +51 -0
- kohakuclip-1.0.0/src/kclip_rs/image/resize.rs +233 -0
- kohakuclip-1.0.0/src/kclip_rs/image/simd.rs +284 -0
- kohakuclip-1.0.0/src/kclip_rs/lib.rs +17 -0
- kohakuclip-1.0.0/src/kclip_rs/mp4/config.rs +59 -0
- kohakuclip-1.0.0/src/kclip_rs/mp4/faststart.rs +72 -0
- kohakuclip-1.0.0/src/kclip_rs/mp4/mod.rs +70 -0
- kohakuclip-1.0.0/src/kclip_rs/mp4/moov.rs +193 -0
- kohakuclip-1.0.0/src/kclip_rs/python/mod.rs +14 -0
- kohakuclip-1.0.0/src/kclip_rs/python/reader.rs +458 -0
- kohakuclip-1.0.0/src/kclip_rs/python/writer.rs +59 -0
- kohakuclip-1.0.0/src/kclip_rs/read/mod.rs +5 -0
- kohakuclip-1.0.0/src/kclip_rs/read/plan.rs +198 -0
- kohakuclip-1.0.0/src/kclip_rs/read/pool.rs +91 -0
- kohakuclip-1.0.0/src/kclip_rs/read/sample.rs +31 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/folder.rs +33 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/index.rs +173 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/mod.rs +96 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/shard.rs +147 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/tar.rs +59 -0
- kohakuclip-1.0.0/src/kclip_rs/storage/zip.rs +230 -0
- kohakuclip-1.0.0/src/kclip_rs/write/av1.rs +294 -0
- kohakuclip-1.0.0/src/kclip_rs/write/encode.rs +264 -0
- kohakuclip-1.0.0/src/kclip_rs/write/memio.rs +70 -0
- kohakuclip-1.0.0/src/kclip_rs/write/mod.rs +89 -0
- kohakuclip-1.0.0/src/kclip_rs/write/pack.rs +70 -0
- kohakuclip-1.0.0/src/kohakuclip/__init__.py +20 -0
- kohakuclip-1.0.0/src/kohakuclip/_core.pyi +82 -0
- kohakuclip-1.0.0/src/kohakuclip/gpu.py +152 -0
- kohakuclip-1.0.0/src/kohakuclip/py.typed +0 -0
- kohakuclip-1.0.0/src/kohakuclip/sampling.py +19 -0
- kohakuclip-1.0.0/src/kohakuclip/torch.py +266 -0
- kohakuclip-1.0.0/src/kohakuclip/writer.py +313 -0
- kohakuclip-1.0.0/tests/__init__.py +0 -0
- kohakuclip-1.0.0/tests/test_reader.py +297 -0
- kohakuclip-1.0.0/tests/test_torch.py +101 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Auto Patch Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# 05:00 UTC weekly, Monday
|
|
6
|
+
- cron: "0 5 * * 1"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
dry_run:
|
|
10
|
+
description: "Evaluate and report, do not tag"
|
|
11
|
+
required: false
|
|
12
|
+
default: true
|
|
13
|
+
type: boolean
|
|
14
|
+
min_commits:
|
|
15
|
+
description: "Commits on main since the last tag before a patch is cut"
|
|
16
|
+
required: false
|
|
17
|
+
default: "3"
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: write
|
|
21
|
+
actions: write
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
patch:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
with:
|
|
29
|
+
ref: main
|
|
30
|
+
fetch-depth: 0
|
|
31
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
- uses: actions/setup-python@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.13"
|
|
35
|
+
|
|
36
|
+
- name: Decide whether a patch is due
|
|
37
|
+
id: decide
|
|
38
|
+
shell: bash
|
|
39
|
+
run: |
|
|
40
|
+
current=$(python scripts/ci/version.py read)
|
|
41
|
+
last=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || echo "")
|
|
42
|
+
span=${last:+${last}..HEAD}
|
|
43
|
+
count=$(git rev-list --count --no-merges ${span:-HEAD})
|
|
44
|
+
min="${{ inputs.min_commits || 3 }}"
|
|
45
|
+
echo "current=${current} last=${last:-none} commits=${count} min=${min}"
|
|
46
|
+
if [ "${count}" -ge "${min}" ] && [ "v${current}" = "${last:-}" ]; then
|
|
47
|
+
echo "release=true" >> "$GITHUB_OUTPUT"
|
|
48
|
+
else
|
|
49
|
+
# Either nothing has landed, or pyproject is already ahead of the
|
|
50
|
+
# last tag — which means a human is mid-release; stay out of it.
|
|
51
|
+
echo "release=false" >> "$GITHUB_OUTPUT"
|
|
52
|
+
fi
|
|
53
|
+
echo "next=$(python scripts/ci/version.py bump patch)" >> "$GITHUB_OUTPUT"
|
|
54
|
+
|
|
55
|
+
- name: Report only
|
|
56
|
+
if: steps.decide.outputs.release != 'true' || inputs.dry_run
|
|
57
|
+
run: |
|
|
58
|
+
echo "release=${{ steps.decide.outputs.release }}"
|
|
59
|
+
echo "would cut ${{ steps.decide.outputs.next }}"
|
|
60
|
+
|
|
61
|
+
- name: Stamp, tag and push
|
|
62
|
+
if: steps.decide.outputs.release == 'true' && !inputs.dry_run
|
|
63
|
+
shell: bash
|
|
64
|
+
run: |
|
|
65
|
+
next="${{ steps.decide.outputs.next }}"
|
|
66
|
+
python scripts/ci/version.py write "${next}"
|
|
67
|
+
git config user.name "github-actions[bot]"
|
|
68
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
69
|
+
git commit -am "bump to version ${next}"
|
|
70
|
+
git tag "v${next}"
|
|
71
|
+
git push origin main --follow-tags
|
|
72
|
+
|
|
73
|
+
# The tag push above cannot start another workflow (GITHUB_TOKEN pushes
|
|
74
|
+
# do not trigger `on: push`), so Release is dispatched explicitly.
|
|
75
|
+
- name: Dispatch the release workflow
|
|
76
|
+
if: steps.decide.outputs.release == 'true' && !inputs.dry_run
|
|
77
|
+
env:
|
|
78
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
79
|
+
run: gh workflow run release.yml -f ref="v${{ steps.decide.outputs.next }}"
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
# Formatting and the breakage-only ruff set (pyproject pins which rules block); rustfmt.
|
|
15
|
+
lint:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
- run: pip install black ruff
|
|
23
|
+
- run: black --check src/ tests/ benchmarks/ examples/ scripts/
|
|
24
|
+
- run: ruff check src/ tests/ benchmarks/ examples/ scripts/
|
|
25
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
26
|
+
with:
|
|
27
|
+
components: rustfmt
|
|
28
|
+
- run: cargo fmt --check
|
|
29
|
+
|
|
30
|
+
# Builds against conda-forge's FFmpeg (the GPL build: the tests encode H.264 with x264 too),
|
|
31
|
+
# then clippy, the Rust unit tests and the end-to-end suite on CPU torch.
|
|
32
|
+
test:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
strategy:
|
|
35
|
+
fail-fast: false
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.13", "3.14"]
|
|
38
|
+
defaults:
|
|
39
|
+
run:
|
|
40
|
+
shell: bash -el {0}
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
- uses: mamba-org/setup-micromamba@v2
|
|
44
|
+
with:
|
|
45
|
+
environment-name: kohakuclip
|
|
46
|
+
create-args: >-
|
|
47
|
+
python=${{ matrix.python-version }}
|
|
48
|
+
ffmpeg=8.1.*=gpl*
|
|
49
|
+
libclang=18
|
|
50
|
+
clang=18
|
|
51
|
+
cache-environment: true
|
|
52
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
53
|
+
with:
|
|
54
|
+
components: clippy
|
|
55
|
+
- name: Build environment
|
|
56
|
+
run: |
|
|
57
|
+
{
|
|
58
|
+
echo "FFMPEG_INCLUDE_DIR=$CONDA_PREFIX/include"
|
|
59
|
+
echo "FFMPEG_LIBS_DIR=$CONDA_PREFIX/lib"
|
|
60
|
+
echo "FFMPEG_LINK_MODE=dynamic"
|
|
61
|
+
echo "LIBCLANG_PATH=$CONDA_PREFIX/lib"
|
|
62
|
+
echo "BINDGEN_EXTRA_CLANG_ARGS=-I$CONDA_PREFIX/lib/clang/18/include -I/usr/include/x86_64-linux-gnu -I/usr/include"
|
|
63
|
+
echo "RUSTFLAGS=-C link-arg=-Wl,-rpath,$CONDA_PREFIX/lib"
|
|
64
|
+
} >> "$GITHUB_ENV"
|
|
65
|
+
- run: cargo clippy --release --all-targets -- -D warnings
|
|
66
|
+
- run: cargo test --release --lib
|
|
67
|
+
- name: Install
|
|
68
|
+
run: |
|
|
69
|
+
pip install maturin
|
|
70
|
+
pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
71
|
+
pip install av numpy pytest
|
|
72
|
+
maturin develop --release
|
|
73
|
+
- run: pytest tests -v --tb=short
|
|
74
|
+
|
|
75
|
+
# The release build, end to end: a manylinux_2_35 wheel with FFmpeg bundled, installed
|
|
76
|
+
# into a clean venv with no FFmpeg around, then used to encode, pack and read a shard.
|
|
77
|
+
package-check:
|
|
78
|
+
runs-on: ubuntu-22.04
|
|
79
|
+
steps:
|
|
80
|
+
- uses: actions/checkout@v4
|
|
81
|
+
- uses: actions/setup-python@v5
|
|
82
|
+
with:
|
|
83
|
+
python-version: "3.13"
|
|
84
|
+
- uses: mamba-org/setup-micromamba@v2
|
|
85
|
+
with:
|
|
86
|
+
environment-name: ffmpeg
|
|
87
|
+
# the same packages as the test job's environment (whose bindings build), with the
|
|
88
|
+
# LGPL FFmpeg
|
|
89
|
+
create-args: >-
|
|
90
|
+
python=3.13
|
|
91
|
+
ffmpeg=8.1.*=lgpl*
|
|
92
|
+
libclang=18
|
|
93
|
+
clang=18
|
|
94
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
95
|
+
# Steps after this one run outside the activated environment: CLANG_PATH keeps the
|
|
96
|
+
# bindings on the environment's clang (the runner's own clang has other headers).
|
|
97
|
+
- name: Build environment (the LGPL FFmpeg, clang 18 for the bindings)
|
|
98
|
+
shell: bash -el {0}
|
|
99
|
+
run: |
|
|
100
|
+
{
|
|
101
|
+
echo "FFMPEG_INCLUDE_DIR=$CONDA_PREFIX/include"
|
|
102
|
+
echo "FFMPEG_LIBS_DIR=$CONDA_PREFIX/lib"
|
|
103
|
+
echo "FFMPEG_LINK_MODE=dynamic"
|
|
104
|
+
echo "LIBCLANG_PATH=$CONDA_PREFIX/lib"
|
|
105
|
+
echo "CLANG_PATH=$CONDA_PREFIX/bin/clang"
|
|
106
|
+
echo "BINDGEN_EXTRA_CLANG_ARGS=-I$CONDA_PREFIX/lib/clang/18/include -I/usr/include/x86_64-linux-gnu -I/usr/include"
|
|
107
|
+
echo "RUSTFLAGS=-Ctarget-cpu=x86-64-v3 -Clink-arg=-Wl,--as-needed -Clink-arg=-Wl,-rpath,$CONDA_PREFIX/lib"
|
|
108
|
+
} >> "$GITHUB_ENV"
|
|
109
|
+
# conda-forge's FFmpeg dependencies (ICU, shaderc) need GLIBCXX 3.4.30: the wheels are
|
|
110
|
+
# manylinux_2_35 (glibc 2.35, e.g. Ubuntu 22.04+), built on this Ubuntu 22.04 runner
|
|
111
|
+
# and repaired by maturin, which bundles FFmpeg and its libraries into the wheel
|
|
112
|
+
# (found through the extension's rpath; LD_LIBRARY_PATH would hand the env's
|
|
113
|
+
# libpython to every Python on the runner).
|
|
114
|
+
- name: Build wheels
|
|
115
|
+
run: |
|
|
116
|
+
pip install "maturin[patchelf]"
|
|
117
|
+
maturin build --release --strip \
|
|
118
|
+
--compatibility manylinux_2_35 -i python3.13 -o dist
|
|
119
|
+
- name: Install the wheel into a clean venv
|
|
120
|
+
run: |
|
|
121
|
+
python -m venv .venv-wheel
|
|
122
|
+
. .venv-wheel/bin/activate
|
|
123
|
+
pip install dist/*.whl
|
|
124
|
+
python scripts/ci/wheel_smoke.py
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Nightly
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# 03:00 UTC, once a day. This is the only automatic trigger: nothing about
|
|
6
|
+
# a nightly is per-push, so a commit landing at noon waits for tomorrow.
|
|
7
|
+
- cron: "0 3 * * *"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
force:
|
|
11
|
+
description: "Build even when the gate says there is nothing new"
|
|
12
|
+
required: false
|
|
13
|
+
default: false
|
|
14
|
+
type: boolean
|
|
15
|
+
|
|
16
|
+
# Serialised, and never cancelled: a second run has to see the tags the first
|
|
17
|
+
# one pushed, or both would decide the same commit is unbuilt.
|
|
18
|
+
concurrency:
|
|
19
|
+
group: nightly
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
actions: write
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
# Decides only. Release is the sole workflow that builds or uploads, so PyPI
|
|
28
|
+
# needs exactly one trusted publisher.
|
|
29
|
+
dispatch:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
with:
|
|
34
|
+
ref: main
|
|
35
|
+
fetch-depth: 0
|
|
36
|
+
# Release cuts its tag through `gh release create`, so the tags are
|
|
37
|
+
# the record of what has been published and the gate below reads
|
|
38
|
+
# them; a shallow clone without them would rebuild every night.
|
|
39
|
+
fetch-tags: true
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: "3.13"
|
|
43
|
+
|
|
44
|
+
- name: Decide whether a nightly is due
|
|
45
|
+
id: gate
|
|
46
|
+
shell: bash
|
|
47
|
+
run: |
|
|
48
|
+
head=$(git rev-parse HEAD)
|
|
49
|
+
today=$(date -u +%Y%m%d)
|
|
50
|
+
|
|
51
|
+
# Every release, stable or nightly, leaves a v* tag on the commit it
|
|
52
|
+
# was cut from. A tag already sitting on HEAD means main has not
|
|
53
|
+
# moved since the last one, and a rebuild would only differ by its
|
|
54
|
+
# timestamp — a duplicate under a new PyPI filename.
|
|
55
|
+
published=$(git tag --points-at HEAD --list 'v*' | head -n1)
|
|
56
|
+
|
|
57
|
+
# Second belt: the nightly version carries the UTC date it was cut
|
|
58
|
+
# on, so an extra dispatch or a re-run cannot cut a second nightly
|
|
59
|
+
# for the same day even if main did move.
|
|
60
|
+
already_today=$(git tag --list "v*.dev${today}*" | head -n1)
|
|
61
|
+
|
|
62
|
+
if [ "${{ inputs.force }}" = "true" ]; then
|
|
63
|
+
reason="forced"
|
|
64
|
+
build=true
|
|
65
|
+
elif [ -n "${published}" ]; then
|
|
66
|
+
reason="${head} is already released as ${published}"
|
|
67
|
+
build=false
|
|
68
|
+
elif [ -n "${already_today}" ]; then
|
|
69
|
+
reason="${already_today} was already cut today"
|
|
70
|
+
build=false
|
|
71
|
+
else
|
|
72
|
+
reason="main is at ${head}, unreleased"
|
|
73
|
+
build=true
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "build=${build}" >> "$GITHUB_OUTPUT"
|
|
77
|
+
echo "${reason}" | tee -a "$GITHUB_STEP_SUMMARY"
|
|
78
|
+
|
|
79
|
+
# Computed after the gate so the stamp names the moment of the build.
|
|
80
|
+
- name: Compute the nightly version
|
|
81
|
+
id: compute
|
|
82
|
+
if: steps.gate.outputs.build == 'true'
|
|
83
|
+
shell: bash
|
|
84
|
+
run: |
|
|
85
|
+
version=$(python scripts/ci/version.py nightly)
|
|
86
|
+
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
87
|
+
echo "nightly ${version}" | tee -a "$GITHUB_STEP_SUMMARY"
|
|
88
|
+
|
|
89
|
+
- name: Dispatch the release workflow
|
|
90
|
+
if: steps.gate.outputs.build == 'true'
|
|
91
|
+
env:
|
|
92
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
93
|
+
run: |
|
|
94
|
+
gh workflow run release.yml \
|
|
95
|
+
-f ref=main \
|
|
96
|
+
-f version="${{ steps.compute.outputs.version }}"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Cutting a release in the GitHub UI, or pushing the tag, both publish.
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
push:
|
|
8
|
+
tags: ["v*"]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
ref:
|
|
12
|
+
description: "Tag, branch or sha to release"
|
|
13
|
+
required: false
|
|
14
|
+
default: ""
|
|
15
|
+
version:
|
|
16
|
+
description: "Stamp this version before building (nightlies pass X.Y.Z.devN)"
|
|
17
|
+
required: false
|
|
18
|
+
default: ""
|
|
19
|
+
|
|
20
|
+
permissions:
|
|
21
|
+
contents: write
|
|
22
|
+
id-token: write
|
|
23
|
+
|
|
24
|
+
# The only workflow that builds or uploads, so PyPI needs one trusted publisher:
|
|
25
|
+
# this file (release.yml), environment `pypi`.
|
|
26
|
+
jobs:
|
|
27
|
+
version:
|
|
28
|
+
name: Resolve version
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
outputs:
|
|
31
|
+
version: ${{ steps.version.outputs.version }}
|
|
32
|
+
prerelease: ${{ steps.version.outputs.prerelease }}
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
with:
|
|
36
|
+
ref: ${{ inputs.ref || github.ref }}
|
|
37
|
+
- uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.13"
|
|
40
|
+
- id: version
|
|
41
|
+
shell: bash
|
|
42
|
+
run: |
|
|
43
|
+
if [ -n "${{ inputs.version }}" ]; then
|
|
44
|
+
python scripts/ci/version.py write "${{ inputs.version }}"
|
|
45
|
+
fi
|
|
46
|
+
version=$(python scripts/ci/version.py read)
|
|
47
|
+
case "${version}" in
|
|
48
|
+
*dev*|*a*|*b*|*rc*) pre=true ;;
|
|
49
|
+
*) pre=false ;;
|
|
50
|
+
esac
|
|
51
|
+
{
|
|
52
|
+
echo "version=${version}"
|
|
53
|
+
echo "prerelease=${pre}"
|
|
54
|
+
} >> "$GITHUB_OUTPUT"
|
|
55
|
+
echo "releasing ${version} (prerelease=${pre})"
|
|
56
|
+
|
|
57
|
+
# A tag that disagrees with pyproject is a mis-cut release: stop before anything is
|
|
58
|
+
# uploaded, since a PyPI filename cannot be reused.
|
|
59
|
+
- name: Tag must match pyproject
|
|
60
|
+
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'release'
|
|
61
|
+
shell: bash
|
|
62
|
+
run: |
|
|
63
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
64
|
+
test "${tag}" = "${{ steps.version.outputs.version }}" \
|
|
65
|
+
|| { echo "tag ${tag} != pyproject ${{ steps.version.outputs.version }}"; exit 1; }
|
|
66
|
+
|
|
67
|
+
# manylinux wheels with an LGPL FFmpeg (libdav1d, SVT-AV1, aom, openh264) bundled by
|
|
68
|
+
# auditwheel: `pip install kohakuclip` needs nothing else. Source builds against your own
|
|
69
|
+
# FFmpeg go through the sdist (see README, Build).
|
|
70
|
+
# manylinux_2_35 wheels with an LGPL FFmpeg (libdav1d, SVT-AV1, aom, openh264) bundled:
|
|
71
|
+
# `pip install kohakuclip` needs nothing else. Source builds against your own FFmpeg go
|
|
72
|
+
# through the sdist (see README, Install and build).
|
|
73
|
+
wheels:
|
|
74
|
+
name: Wheels
|
|
75
|
+
needs: [version]
|
|
76
|
+
runs-on: ubuntu-22.04
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/checkout@v4
|
|
79
|
+
with:
|
|
80
|
+
ref: ${{ inputs.ref || github.ref }}
|
|
81
|
+
- uses: actions/setup-python@v5
|
|
82
|
+
with:
|
|
83
|
+
python-version: |
|
|
84
|
+
3.14
|
|
85
|
+
3.13
|
|
86
|
+
- name: Stamp the version
|
|
87
|
+
if: inputs.version != ''
|
|
88
|
+
run: python scripts/ci/version.py write "${{ inputs.version }}"
|
|
89
|
+
- uses: mamba-org/setup-micromamba@v2
|
|
90
|
+
with:
|
|
91
|
+
environment-name: ffmpeg
|
|
92
|
+
# the same packages as the test job's environment (whose bindings build), with the
|
|
93
|
+
# LGPL FFmpeg
|
|
94
|
+
create-args: >-
|
|
95
|
+
python=3.13
|
|
96
|
+
ffmpeg=8.1.*=lgpl*
|
|
97
|
+
libclang=18
|
|
98
|
+
clang=18
|
|
99
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
100
|
+
# Steps after this one run outside the activated environment: CLANG_PATH keeps the
|
|
101
|
+
# bindings on the environment's clang (the runner's own clang has other headers).
|
|
102
|
+
- name: Build environment (the LGPL FFmpeg, clang 18 for the bindings)
|
|
103
|
+
shell: bash -el {0}
|
|
104
|
+
run: |
|
|
105
|
+
{
|
|
106
|
+
echo "FFMPEG_INCLUDE_DIR=$CONDA_PREFIX/include"
|
|
107
|
+
echo "FFMPEG_LIBS_DIR=$CONDA_PREFIX/lib"
|
|
108
|
+
echo "FFMPEG_LINK_MODE=dynamic"
|
|
109
|
+
echo "LIBCLANG_PATH=$CONDA_PREFIX/lib"
|
|
110
|
+
echo "CLANG_PATH=$CONDA_PREFIX/bin/clang"
|
|
111
|
+
echo "BINDGEN_EXTRA_CLANG_ARGS=-I$CONDA_PREFIX/lib/clang/18/include -I/usr/include/x86_64-linux-gnu -I/usr/include"
|
|
112
|
+
echo "RUSTFLAGS=-Ctarget-cpu=x86-64-v3 -Clink-arg=-Wl,--as-needed -Clink-arg=-Wl,-rpath,$CONDA_PREFIX/lib"
|
|
113
|
+
} >> "$GITHUB_ENV"
|
|
114
|
+
# conda-forge's FFmpeg dependencies (ICU, shaderc) need GLIBCXX 3.4.30: the wheels are
|
|
115
|
+
# manylinux_2_35 (glibc 2.35, e.g. Ubuntu 22.04+), built on this Ubuntu 22.04 runner
|
|
116
|
+
# and repaired by maturin, which bundles FFmpeg and its libraries into the wheel
|
|
117
|
+
# (found through the extension's rpath; LD_LIBRARY_PATH would hand the env's
|
|
118
|
+
# libpython to every Python on the runner).
|
|
119
|
+
- name: Build wheels
|
|
120
|
+
run: |
|
|
121
|
+
pip install "maturin[patchelf]"
|
|
122
|
+
maturin build --release --strip \
|
|
123
|
+
--compatibility manylinux_2_35 -i python3.13 -i python3.14 -o dist
|
|
124
|
+
- name: Smoke test the wheel in a clean venv
|
|
125
|
+
run: |
|
|
126
|
+
python3.13 -m venv .venv-wheel
|
|
127
|
+
. .venv-wheel/bin/activate
|
|
128
|
+
pip install dist/*cp313*.whl
|
|
129
|
+
python scripts/ci/wheel_smoke.py
|
|
130
|
+
- uses: actions/upload-artifact@v4
|
|
131
|
+
with:
|
|
132
|
+
name: wheels
|
|
133
|
+
path: dist/*.whl
|
|
134
|
+
if-no-files-found: error
|
|
135
|
+
retention-days: 7
|
|
136
|
+
|
|
137
|
+
sdist:
|
|
138
|
+
name: Source distribution
|
|
139
|
+
needs: [version]
|
|
140
|
+
runs-on: ubuntu-latest
|
|
141
|
+
steps:
|
|
142
|
+
- uses: actions/checkout@v4
|
|
143
|
+
with:
|
|
144
|
+
ref: ${{ inputs.ref || github.ref }}
|
|
145
|
+
- uses: actions/setup-python@v5
|
|
146
|
+
with:
|
|
147
|
+
python-version: "3.13"
|
|
148
|
+
- name: Stamp the version
|
|
149
|
+
if: inputs.version != ''
|
|
150
|
+
run: python scripts/ci/version.py write "${{ inputs.version }}"
|
|
151
|
+
- uses: PyO3/maturin-action@v1
|
|
152
|
+
with:
|
|
153
|
+
command: sdist
|
|
154
|
+
args: -o dist
|
|
155
|
+
- run: pip install twine && twine check dist/*
|
|
156
|
+
- uses: actions/upload-artifact@v4
|
|
157
|
+
with:
|
|
158
|
+
name: sdist
|
|
159
|
+
path: dist/*.tar.gz
|
|
160
|
+
if-no-files-found: error
|
|
161
|
+
retention-days: 7
|
|
162
|
+
|
|
163
|
+
publish-pypi:
|
|
164
|
+
name: Publish distributions to PyPI
|
|
165
|
+
needs: [wheels, sdist]
|
|
166
|
+
runs-on: ubuntu-latest
|
|
167
|
+
environment:
|
|
168
|
+
name: pypi
|
|
169
|
+
url: https://pypi.org/p/kohakuclip
|
|
170
|
+
permissions:
|
|
171
|
+
id-token: write
|
|
172
|
+
steps:
|
|
173
|
+
- uses: actions/download-artifact@v4
|
|
174
|
+
with:
|
|
175
|
+
path: dist/
|
|
176
|
+
merge-multiple: true
|
|
177
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
178
|
+
|
|
179
|
+
publish-github:
|
|
180
|
+
name: Publish the GitHub release
|
|
181
|
+
needs: [version, publish-pypi]
|
|
182
|
+
runs-on: ubuntu-latest
|
|
183
|
+
steps:
|
|
184
|
+
- uses: actions/checkout@v4
|
|
185
|
+
with:
|
|
186
|
+
ref: ${{ inputs.ref || github.ref }}
|
|
187
|
+
fetch-depth: 0
|
|
188
|
+
- uses: actions/setup-python@v5
|
|
189
|
+
with:
|
|
190
|
+
python-version: "3.13"
|
|
191
|
+
- uses: actions/download-artifact@v4
|
|
192
|
+
with:
|
|
193
|
+
path: dist/
|
|
194
|
+
merge-multiple: true
|
|
195
|
+
- name: Create or update the release
|
|
196
|
+
env:
|
|
197
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
198
|
+
shell: bash
|
|
199
|
+
run: |
|
|
200
|
+
version="${{ needs.version.outputs.version }}"
|
|
201
|
+
tag="v${version}"
|
|
202
|
+
flag=""
|
|
203
|
+
if [ "${{ needs.version.outputs.prerelease }}" = "true" ]; then
|
|
204
|
+
flag="--prerelease"
|
|
205
|
+
fi
|
|
206
|
+
notes=$(python scripts/ci/release_notes.py --version "${version}")
|
|
207
|
+
if ! gh release view "${tag}" >/dev/null 2>&1; then
|
|
208
|
+
gh release create "${tag}" --title "KohakuClip ${version}" \
|
|
209
|
+
--notes "${notes}" ${flag} --target "$(git rev-parse HEAD)"
|
|
210
|
+
else
|
|
211
|
+
gh release edit "${tag}" --title "KohakuClip ${version}" \
|
|
212
|
+
--notes "${notes}" ${flag}
|
|
213
|
+
fi
|
|
214
|
+
for f in dist/*; do gh release upload "${tag}" "$f" --clobber; done
|