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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ jobs:
runs-on: ubuntu-latest
env:
WASM_PACK: "0.15.0"
CARGO_ABOUT: "0.9.2"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
Expand All @@ -165,6 +166,11 @@ jobs:
- run: |
curl -sSL "https://github.com/wasm-bindgen/wasm-pack/releases/download/v$WASM_PACK/wasm-pack-v$WASM_PACK-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz --strip-components=1 -C "$HOME/.cargo/bin" "wasm-pack-v$WASM_PACK-x86_64-unknown-linux-musl/wasm-pack"
# `cargo-about` writes the licence notices `pack.sh` puts in the
# package, from the same release archives `wasm-pack` comes from.
- run: |
curl -sSL "https://github.com/EmbarkStudios/cargo-about/releases/download/$CARGO_ABOUT/cargo-about-$CARGO_ABOUT-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz --strip-components=1 -C "$HOME/.cargo/bin" "cargo-about-$CARGO_ABOUT-x86_64-unknown-linux-musl/cargo-about"
# Every command below runs without the workflow's `RUSTFLAGS`: the
# variable replaces the flags of `.cargo/config.toml` instead of
# adding to them, and this target would be built without `simd128`
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
contents: write
env:
WASM_PACK: "0.15.0"
CARGO_ABOUT: "0.9.2"
PLAN: ${{ inputs.plan }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
Expand All @@ -53,6 +54,11 @@ jobs:
- run: |
curl -sSL "https://github.com/wasm-bindgen/wasm-pack/releases/download/v$WASM_PACK/wasm-pack-v$WASM_PACK-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz --strip-components=1 -C "$HOME/.cargo/bin" "wasm-pack-v$WASM_PACK-x86_64-unknown-linux-musl/wasm-pack"
# `cargo-about` writes the licence notices `pack.sh` puts in the
# package, from the same release archives `wasm-pack` comes from.
- run: |
curl -sSL "https://github.com/EmbarkStudios/cargo-about/releases/download/$CARGO_ABOUT/cargo-about-$CARGO_ABOUT-x86_64-unknown-linux-musl.tar.gz" \
| tar -xz --strip-components=1 -C "$HOME/.cargo/bin" "cargo-about-$CARGO_ABOUT-x86_64-unknown-linux-musl/cargo-about"
- run: crates/sqzer-wasm/pack.sh
# The package carries the workspace version, which dist has already
# matched against the tag for the binaries. Checked again here
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

### Bug Fixes

* **wasm:** the npm package carries `THIRD-PARTY-LICENSES.txt`, the licence notice of every crate compiled into `sqzer_bg.wasm`, generated by `cargo about` from the wasm32 dependency tree as `pack.sh` builds the package. The C library inside `libdeflate-sys` has its own MIT notice there, and `avif-parse`, under MPL-2.0, is listed with its repository. The package shipped its own two licence texts and nothing for the 170-odd crates in the module ([#54](https://github.com/sqzer-dev/sqzer/issues/54))
* **sqzer:** an explicit quality with no format, on a graphic the portable tier sends to lossless WebP, is reported as what it was: `Output::target` is `Resolved::Lossless` and `Output::lossless` is `true`, where the record said the quality asked for and `lossless: false` over the same lossless bytes. `--json`, `{quality}` in a `--template` and the npm package follow ([#56](https://github.com/sqzer-dev/sqzer/issues/56))

## 0.3.0
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cargo build --workspace # portable tier
cargo build -p sqzer-cli --features native # needs C libs on PATH / vcpkg
cargo build -p sqzer-wasm --target wasm32-unknown-unknown # proves portable builds without a libc; needs clang
(cd crates/sqzer-wasm && wasm-pack test --node) # the JavaScript API over the fixtures; needs wasm-pack, and no RUSTFLAGS set
crates/sqzer-wasm/pack.sh # the npm package as a tag publishes it, packed and run from its tarball
crates/sqzer-wasm/pack.sh # the npm package as a tag publishes it, packed and run from its tarball; needs cargo-about and jq
cargo test --workspace
cargo clippy --workspace --all-targets --all-features # pedantic is on, warnings are errors in CI
cargo fmt --all
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ cargo build -p sqzer-wasm --target wasm32-unknown-unknown

# the browser build's JavaScript API over the fixtures, in Node; needs wasm-pack
(cd crates/sqzer-wasm && wasm-pack test --node)

# the npm package as a tag publishes it, with the licence notices of every crate in
# the module; needs wasm-pack, cargo-about (`cargo install cargo-about --features cli`), jq and Node
crates/sqzer-wasm/pack.sh
```

> **Note**: The golden tests compare each encoder's SSIMULACRA2 score on the fixtures against a committed value. If a change moves a score, say why in the PR; do not just update the number.
Expand Down
116 changes: 116 additions & 0 deletions about.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# `cargo about` writes the licence notices of everything compiled into a
# build: `crates/sqzer-wasm/pack.sh` runs it over the npm package into
# `THIRD-PARTY-LICENSES.txt` with `crates/sqzer-wasm/about.hbs`. The
# accepted list is the allow-list of `deny.toml`, in the order a crate
# that offers a choice is taken: a crate that is `MIT OR Apache-2.0`
# ships its MIT notice.
accepted = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Zlib",
"MPL-2.0",
"Unicode-3.0",
"Unicode-DFS-2016",
"CC0-1.0",
]
# The package is the wasm32 build; what only a desktop target compiles
# is not in it. Build scripts and their dependencies (`cc`) do not ship,
# and neither does `sqzer-wasm` itself, `publish = false`: the package's
# own licence is next to the file. The four published workspace crates
# are left out by the template, on their repository.
targets = ["wasm32-unknown-unknown"]
ignore-build-dependencies = true
ignore-dev-dependencies = true
private = { ignore = true }
# A notice lives at the root of a crate. Scanned deeper, the tree gave a
# C fuzzing harness in `qoi` and Rust source headers in `kamadak-exif`
# as licence texts, each with a notice inside it.
max-depth = 1

# What the scan cannot read on its own, clarified per crate. Every
# checksum pins a file's text, not a crate version: a bump keeps working
# until the notice itself changes, and then `pack.sh` fails until the
# entry is checked again. `files` are read from the crate as published,
# `git` from its repository at the commit it was published from, for a
# crate that ships no notice and keeps one at the root of its repository.
# Two crates stay on the bare licence text: `simd_helpers` has no notice
# in its repository either, and `zune-inflate` names no repository.

# Vendors and compiles `libdeflate`, a C library under its own MIT
# notice, which the crate's Apache-2.0 field does not carry.
[libdeflate-sys]
clarify = { license = "Apache-2.0 AND MIT", files = [
{ path = "LICENSE", license = "Apache-2.0", checksum = "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2" },
{ path = "libdeflate/COPYING", license = "MIT", checksum = "4ad69099cb4374836fd27583d9991e2838cd86b6e4666ab26b2d32582c91e73a" },
] }

# Names its licence by file alone, `license-file = "LICENSE"`.
[quantizr]
clarify = { license = "MIT", files = [
{ path = "LICENSE", checksum = "407b2d167f73ef78da1fcbfb6c2f1051f195b1984b9bfeeac0a39b34c198a7fe" },
] }

# Notices under a name or in a form the scan does not take.
[libm]
clarify = { license = "MIT", files = [
{ path = "LICENSE.txt", checksum = "3823dda7cf046602f4b4e77ec8e227863dc4736037cc85bb33d9f19febe16bb7" },
] }
[brotli-decompressor]
clarify = { license = "BSD-3-Clause", files = [
{ path = "LICENSE", checksum = "c0c56f26d9c051cac4d200c34c84e7ae9aaa853e01a982a1df08b09931e518ae" },
] }
[exr]
clarify = { license = "BSD-3-Clause", files = [
{ path = "LICENSE.md", checksum = "97e4d3aa7a9e8ac31979c16ca8bb2b628a9cb72c3362185ad2bf4ad77f43551f" },
] }
[tsify]
clarify = { license = "MIT OR Apache-2.0", files = [
{ path = "LICENSE_MIT", license = "MIT", checksum = "23b988ff99c59aba4e37e7709d3d2102096203bb83a077cbc1aad04dd7a77244" },
{ path = "LICENSE_APACHE", license = "Apache-2.0", checksum = "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a" },
] }

# Crates published without their notice, read from the repository.
[tsify-macros]
clarify = { license = "MIT", git = [
{ path = "LICENSE_MIT", checksum = "23b988ff99c59aba4e37e7709d3d2102096203bb83a077cbc1aad04dd7a77244" },
] }
[archmage-macros]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "ea17bff5189bc1a38dcad7bd93abeb5a348da5ebeee5891a012b5db27a2a084b" },
] }
[magetypes]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "ea17bff5189bc1a38dcad7bd93abeb5a348da5ebeee5891a012b5db27a2a084b" },
] }
[enough]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "ffa509f359743823fe3cdba2c4dc8feee00be8f07ab299fbbe2b5a50d6ed1ecf" },
] }
[atomig-macro]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "6f54826bbf67526f2d41937c1904ae2de63ef5707b80c68deadbf073b5669c40" },
] }
[profiling]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "c8167fdeeed46d3f244d3f85c5bf998ce889343691c32be2c61a8bc4b5c08333" },
] }
[profiling-procmacros]
clarify = { license = "MIT", git = [
{ path = "LICENSE-MIT", checksum = "c8167fdeeed46d3f244d3f85c5bf998ce889343691c32be2c61a8bc4b5c08333" },
] }
[pulp-wasm-simd-flag]
clarify = { license = "MIT", git = [
{ path = "LICENSE", checksum = "d64f878c89bd5f1e5ada7e4aad57690b122727cf5229b7b87ea1980c188da1d9" },
] }
[alloc-stdlib]
clarify = { license = "BSD-3-Clause", git = [
{ path = "LICENSE", checksum = "c0c56f26d9c051cac4d200c34c84e7ae9aaa853e01a982a1df08b09931e518ae" },
] }
[fast-ssim2]
clarify = { license = "BSD-2-Clause", git = [
{ path = "LICENSE", checksum = "acc9e236b0011c638714a16f5634fa5bcd3be111182e237c3049db700c3521e2" },
] }
2 changes: 1 addition & 1 deletion crates/sqzer-wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,4 @@ await init({ module_or_path: await readFile(new URL(import.meta.resolve("sqzer/s

## Licence

MIT or Apache-2.0, at your option.
MIT or Apache-2.0, at your option. `THIRD-PARTY-LICENSES.txt` in the package carries the notice of every crate compiled into `sqzer_bg.wasm`, the C library inside `libdeflate-sys` included; a page that bundles the package ships it alongside, as most of those licences ask.
22 changes: 22 additions & 0 deletions crates/sqzer-wasm/about.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Third-party notices for the npm package sqzer

The package itself is MIT OR Apache-2.0, in LICENSE-MIT and LICENSE-APACHE
next to this file. sqzer_bg.wasm is compiled from the crates below, each
under the licence named, with the notice the crate ships, or the one its
repository holds where the crate ships none. A crate under MPL-2.0 has its
source at the repository given with it.

{{#each licenses}}
{{#unless (eq used_by.0.crate.repository "https://github.com/sqzer-dev/sqzer")}}
================================================================================
{{{name}}}

Used by:
{{#each used_by}}
{{{crate.name}}} {{{crate.version}}}{{#if crate.repository}} {{{crate.repository}}}{{/if}}
{{/each}}

{{{text}}}

{{/unless}}
{{/each}}
22 changes: 20 additions & 2 deletions crates/sqzer-wasm/pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# (ADR-0011 D5), and what the wasm job of `ci.yml` rehearses on every pull
# request. Leaves `pkg/sqzer-<version>.tgz`.
#
# Needs `wasm-pack`, `clang`, `jq` and Node 22.14 or later.
# Needs `wasm-pack`, `cargo-about`, `clang`, `jq` and Node 22.14 or later.
set -euo pipefail
cd "$(dirname "$0")"

Expand All @@ -19,7 +19,25 @@ env -u RUSTFLAGS wasm-pack build --release --target web --out-name sqzer
# the licence texts in the crate directory; they are at the repository
# root.
cp ../../LICENSE-MIT ../../LICENSE-APACHE pkg/
jq '.name = "sqzer" | .files += ["snippets", "LICENSE-MIT", "LICENSE-APACHE"]' \

# The notices of every crate compiled into the module, from `about.toml`
# at the repository root and `about.hbs` here. Most of their licences ask
# that the copyright notice travels with a binary; this is where it
# travels. `--fail` refuses a crate whose licence cannot be read. A stale
# clarification in `about.toml`, a crate whose licence file moved with a
# bump, is only a warning to `cargo about`, which then drops that notice
# and goes on; here a warning fails the build, so nothing is left out
# without anyone knowing.
about_log=$(cargo about generate --fail --locked --target wasm32-unknown-unknown \
-o pkg/THIRD-PARTY-LICENSES.txt about.hbs 2>&1) || { echo "$about_log" >&2; exit 1; }
if grep -q WARN <<< "$about_log"; then
echo "$about_log" >&2
echo "cargo about warned: a notice is missing, or a clarification in about.toml is stale" >&2
exit 1
fi
test -s pkg/THIRD-PARTY-LICENSES.txt

jq '.name = "sqzer" | .files += ["snippets", "LICENSE-MIT", "LICENSE-APACHE", "THIRD-PARTY-LICENSES.txt"]' \
pkg/package.json > pkg/package.json.new
mv pkg/package.json.new pkg/package.json

Expand Down
6 changes: 6 additions & 0 deletions crates/sqzer-wasm/tests/package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ assert.equal(manifest.license, "MIT OR Apache-2.0");
for (const file of ["LICENSE-MIT", "LICENSE-APACHE", "README.md", "sqzer.d.ts"]) {
await readFile(installed(file));
}
// The notices of the crates in the module, one `Used by` block per
// licence text, with the C library inside `libdeflate-sys` among them.
const notices = await readFile(installed("THIRD-PARTY-LICENSES.txt"), "utf8");
for (const needle of ["Used by:", "ravif", "mozjpeg-rs", "libdeflate-sys", "Eric Biggers", "avif-parse"]) {
assert.ok(notices.includes(needle), `THIRD-PARTY-LICENSES.txt lacks ${needle}`);
}

await init({ module_or_path: await readFile(installed("sqzer_bg.wasm")) });

Expand Down
Loading