9c0e31d783
Apache-2.0 was the wrong declaration for two independent reasons. Enabling the `vst3` feature links vst3-sys, which is GPLv3-or-later by its own authors' choice — they describe their port as a derivative of Steinberg's SDK that "was not made in isolation", so the obligation holds regardless of any question about Steinberg's own rights. Gating the feature kept the default build clean, but plugins built from this template are intended to ship VST3, so GPL is where they land anyway. Declaring it up front is more honest than deferring the decision to every clone. Separately, parts of src/lib.rs derive from Robbert van der Helm's NIH-plug cookiecutter template and its `gain` example, both ISC. ISC's one condition is that its copyright and permission notice travel with all copies, and this repo carried neither — a compliance gap that existed regardless of the GPL question. ISC is GPL-compatible, so the notice is retained in a new NOTICE file rather than superseded. The `vst3` feature stays opt-in, but its rationale changes: it is no longer about licence compliance, only about not pulling a sizeable dependency into a CLAP-only build. The Cargo.toml comment said otherwise and would have misled the next reader. Also corrects the README's claim that you must "accept Steinberg's VST3 SDK licence". No SDK source is vendored or redistributed here, so there is nothing to accept at build time. The real constraint is vst3-sys's GPLv3, plus Steinberg's separate trademark in "VST" — a different regime from copyright that no source licence resolves. Copyright in the Irene <irene@novoyuuparosk.org> commits is held by the repository owner (an agent identity), so no third-party agreement was needed for this relicense. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WHt4DykxXaQnyaJfyS8KCn
209 lines
10 KiB
Bash
Executable File
209 lines
10 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# check-branding.sh - verify the plugin's branding/identity strings agree everywhere.
|
|
#
|
|
# Plugin branding is duplicated across the build manifest, the bundler manifest,
|
|
# the source, the docs and (once you add one) the deploy script. Nothing makes
|
|
# them agree, so a rename drifts silently: the bundle builds under one name and
|
|
# the deploy script looks for another. This asserts they match, and that the
|
|
# identity constants are legal.
|
|
#
|
|
# In a template this matters more than usual: renaming is the first thing you do
|
|
# with this repo, and it touches every file below. Run this immediately after,
|
|
# and the STALE machinery will list whatever you missed.
|
|
#
|
|
# Usage: sh check-branding.sh (exit 0 = consistent, 1 = drift found)
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# CANONICAL IDENTITY - the single source of truth. Edit these to rename, then
|
|
# run this script; every failure it prints is a place still holding the old name.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
PKG="nih_plug_template" # Cargo package name == bundler.toml table key
|
|
DISPLAY="Plugin Name" # bundle name -> "<DISPLAY>.vst3" / "<DISPLAY>.clap"
|
|
PLUGIN_NAME="Plugin Name" # Plugin::NAME - what the DAW displays
|
|
VENDOR="Your Name" # Plugin::VENDOR
|
|
EMAIL="your@email.com" # Plugin::EMAIL
|
|
HOMEPAGE="https://github.com/YOUR-USERNAME/YOUR-PLUGIN-NAME" # Cargo homepage -> Plugin::URL
|
|
CLAP_ID="com.your-domain.plugin-name" # CLAP_ID - stable plugin identity
|
|
VST3_CLASS_ID="Unique16CharId!!" # VST3_CLASS_ID - stable identity, MUST be 16 bytes
|
|
DESCRIPTION="A minimal NIH-plug audio plugin" # Cargo package description
|
|
CLAP_DESCRIPTION="Your plugin description" # CLAP_DESCRIPTION - shown in some host browsers
|
|
|
|
# Rust type names. These never reach a host, so renaming them is cosmetic - but
|
|
# leaving "MyPlugin" in a shipped plugin is the sort of residue that says nobody
|
|
# read the file. Change these to make the checks below enforce your own names;
|
|
# leave them alone and they simply stay green.
|
|
STRUCT="MyPlugin" # the Plugin impl target
|
|
PARAMS_STRUCT="PluginParams" # the Params impl target
|
|
|
|
# Spellings that must no longer appear anywhere in tracked files. Seeded with
|
|
# this template's own placeholders, so that renaming is self-checking: each entry
|
|
# is skipped while it is still one of the canonical values above, and becomes a
|
|
# live check the moment you change that value. Add your own old names here after
|
|
# a later rename.
|
|
STALE="nih_plug_template
|
|
MyPlugin
|
|
PluginParams
|
|
A minimal NIH-plug audio plugin
|
|
Your plugin description
|
|
Plugin Name
|
|
Your Name
|
|
your@email.com
|
|
com.your-domain.plugin-name
|
|
Unique16CharId!!
|
|
YOUR-USERNAME
|
|
YOUR-PLUGIN-NAME
|
|
your-domain"
|
|
|
|
set -u
|
|
cd "$(dirname "$0")" || exit 1
|
|
|
|
pass=0; fail=0; skip=0
|
|
ok() { pass=$((pass+1)); printf ' ok %s\n' "$1"; }
|
|
bad() { fail=$((fail+1)); printf ' FAIL %s\n' "$1"; [ $# -gt 1 ] && printf ' %s\n' "$2"; return 0; }
|
|
note() { skip=$((skip+1)); printf ' skip %s\n' "$1"; }
|
|
# Reported for awareness only - never counted, never fails the run.
|
|
info() { printf ' -- %s\n' "$1"; }
|
|
|
|
# has FILE PATTERN -> fixed-string search
|
|
has() { grep -qF "$2" "$1" 2>/dev/null; }
|
|
|
|
check() { # check LABEL FILE LITERAL
|
|
if [ ! -f "$2" ]; then bad "$1" "missing file: $2"; return; fi
|
|
if has "$2" "$3"; then ok "$1"; else bad "$1" "$2 does not contain: $3"; fi
|
|
}
|
|
|
|
# Same as check, but a missing file is "not applicable yet" rather than drift.
|
|
# The template ships without a deploy script; this starts checking once you add one.
|
|
opt_check() { # opt_check LABEL FILE LITERAL
|
|
if [ ! -f "$2" ]; then note "$1 ($2 not present)"; return; fi
|
|
if has "$2" "$3"; then ok "$1"; else bad "$1" "$2 does not contain: $3"; fi
|
|
}
|
|
|
|
printf 'branding check (canonical: %s / "%s")\n\n' "$PKG" "$DISPLAY"
|
|
|
|
printf 'build manifests\n'
|
|
check "Cargo.toml package name" Cargo.toml "name = \"$PKG\""
|
|
check "Cargo.toml homepage" Cargo.toml "homepage = \"$HOMEPAGE\""
|
|
check "Cargo.toml description" Cargo.toml "description = \"$DESCRIPTION\""
|
|
check "bundler.toml table key" bundler.toml "[$PKG]"
|
|
check "bundler.toml display name" bundler.toml "name = \"$DISPLAY\""
|
|
|
|
printf '\nsource identity (src/lib.rs)\n'
|
|
check "Plugin::NAME" src/lib.rs "const NAME: &'static str = \"$PLUGIN_NAME\""
|
|
check "Plugin::VENDOR" src/lib.rs "const VENDOR: &'static str = \"$VENDOR\""
|
|
check "Plugin::EMAIL" src/lib.rs "const EMAIL: &'static str = \"$EMAIL\""
|
|
check "CLAP_ID" src/lib.rs "const CLAP_ID: &'static str = \"$CLAP_ID\""
|
|
check "CLAP_DESCRIPTION" src/lib.rs "const CLAP_DESCRIPTION: Option<&'static str> = Some(\"$CLAP_DESCRIPTION\")"
|
|
check "VST3_CLASS_ID" src/lib.rs "const VST3_CLASS_ID: [u8; 16] = *b\"$VST3_CLASS_ID\""
|
|
|
|
# Plugin::URL is env!("CARGO_PKG_HOMEPAGE"), so the manifest is the only place
|
|
# it is spelled. Assert the indirection is still in place rather than hardcoded.
|
|
check "Plugin::URL from manifest" src/lib.rs "const URL: &'static str = env!(\"CARGO_PKG_HOMEPAGE\")"
|
|
|
|
# VST3 class IDs are a fixed 16-byte array. A shorter or longer literal is a
|
|
# compile error, but it is far clearer to say so here than to read rustc on it.
|
|
n=$(printf '%s' "$VST3_CLASS_ID" | wc -c | tr -d ' ')
|
|
if [ "$n" -eq 16 ]; then ok "VST3_CLASS_ID is 16 bytes"
|
|
else bad "VST3_CLASS_ID is 16 bytes" "got $n bytes: \"$VST3_CLASS_ID\""; fi
|
|
|
|
# CLAP IDs are reverse-DNS by convention and are compared verbatim by hosts, so
|
|
# a stray space or capital is a silent identity change between machines.
|
|
case "$CLAP_ID" in
|
|
*\ *|*[A-Z]*) bad "CLAP_ID is reverse-DNS safe" "no spaces or capitals allowed: \"$CLAP_ID\"" ;;
|
|
*.*) ok "CLAP_ID is reverse-DNS safe" ;;
|
|
*) bad "CLAP_ID is reverse-DNS safe" "expected dotted reverse-DNS, got: \"$CLAP_ID\"" ;;
|
|
esac
|
|
|
|
printf '\nstructural names (src/lib.rs)\n'
|
|
# Every site the type names appear. A rename that misses one is a compile error
|
|
# rather than silent drift, but naming the site is faster than reading rustc,
|
|
# and the Vst3Plugin impl sits behind a cfg so a default build never reports it.
|
|
check "struct $STRUCT" src/lib.rs "struct $STRUCT {"
|
|
check "impl Plugin" src/lib.rs "impl Plugin for $STRUCT {"
|
|
check "impl ClapPlugin" src/lib.rs "impl ClapPlugin for $STRUCT {"
|
|
check "impl Vst3Plugin" src/lib.rs "impl Vst3Plugin for $STRUCT {"
|
|
check "nih_export_clap!" src/lib.rs "nih_export_clap!($STRUCT);"
|
|
check "nih_export_vst3!" src/lib.rs "nih_export_vst3!($STRUCT);"
|
|
check "struct $PARAMS_STRUCT" src/lib.rs "struct $PARAMS_STRUCT {"
|
|
check "impl Default for params" src/lib.rs "impl Default for $PARAMS_STRUCT {"
|
|
check "params field type" src/lib.rs "params: Arc<$PARAMS_STRUCT>,"
|
|
|
|
printf '\ndocs\n'
|
|
opt_check "README bundle command" README.md "cargo xtask bundle $PKG"
|
|
|
|
printf '\ndeploy script\n'
|
|
opt_check "deploy.ps1 default package" deploy.ps1 "\$Package = \"$PKG\""
|
|
opt_check "deploy.ps1 VST3 bundle" deploy.ps1 "\$vst3Name = \"$DISPLAY.vst3\""
|
|
opt_check "deploy.ps1 CLAP bundle" deploy.ps1 "\$clapName = \"$DISPLAY.clap\""
|
|
|
|
printf '\nstale spellings\n'
|
|
# File list for the scan below. Prefer git, so build output and any vendored
|
|
# tree stay out of it. Fall back to find when this is not a checkout - an
|
|
# exported tarball, or a CI step that fetched without git metadata - because
|
|
# `git ls-files` there returns nothing, and an empty list would report every
|
|
# stale spelling as absent. A check that passes hardest when it can see least
|
|
# is worse than no check.
|
|
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
file_list() { git ls-files; }
|
|
scan_source="git"
|
|
else
|
|
file_list() { find . -path ./.git -prune -o -path ./target -prune -o -type f -print | sed 's|^\./||'; }
|
|
scan_source="find (not a git checkout)"
|
|
fi
|
|
info "scanning tracked files via $scan_source"
|
|
# Every canonical spelling concatenated, for the substring test below.
|
|
CANONICAL_BLOB="$PKG
|
|
$DESCRIPTION
|
|
$CLAP_DESCRIPTION
|
|
$STRUCT
|
|
$PARAMS_STRUCT
|
|
$DISPLAY
|
|
$PLUGIN_NAME
|
|
$VENDOR
|
|
$EMAIL
|
|
$HOMEPAGE
|
|
$CLAP_ID
|
|
$VST3_CLASS_ID"
|
|
# Fed by here-doc rather than a pipe on purpose: a piped `while` runs in a
|
|
# subshell, and the pass/fail counters it increments would be discarded.
|
|
while IFS= read -r s; do
|
|
[ -n "$s" ] || continue
|
|
|
|
# Still part of a canonical value? Then it is current branding, not a leftover.
|
|
# This is what lets the list ship pre-seeded: entries arm themselves as you
|
|
# rename. Substring, not equality, because placeholders nest - "your-domain"
|
|
# lives inside the canonical CLAP_ID, and "YOUR-USERNAME" inside the homepage.
|
|
# Over-skipping is the safe direction: a false FAIL on a name you still use
|
|
# would train you to ignore this section.
|
|
case "$CANONICAL_BLOB" in
|
|
*"$s"*) note "\"$s\" (still canonical)"; continue ;;
|
|
esac
|
|
|
|
# This script names every placeholder by definition, so it can never be a hit.
|
|
hits=$(file_list 2>/dev/null | while read -r f; do
|
|
[ "$f" = "check-branding.sh" ] || { [ -f "$f" ] && grep -lF "$s" "$f" 2>/dev/null; }
|
|
done)
|
|
if [ -z "$hits" ]; then ok "no occurrences of \"$s\""
|
|
else bad "no occurrences of \"$s\"" "still present in: $(echo "$hits" | tr '\n' ' ')"; fi
|
|
done <<STALE_LIST
|
|
$STALE
|
|
STALE_LIST
|
|
|
|
# Template scaffolding, not drift: TODOs are legitimate while you are still
|
|
# building. Reported so a finished plugin does not quietly ship with them.
|
|
# `grep -c` prints 0 AND exits 1 when there are no matches, so `|| echo 0`
|
|
# would append a second zero and make the count unparseable. Swallow the
|
|
# status instead, and default an empty result (missing file) to zero.
|
|
todos=$(grep -c 'TODO' src/lib.rs 2>/dev/null || :)
|
|
[ -n "$todos" ] || todos=0
|
|
printf '\nscaffolding\n'
|
|
if [ "$todos" -eq 0 ]; then ok "no TODO markers left in src/lib.rs"
|
|
else info "$todos TODO marker(s) still in src/lib.rs (not a failure)"; fi
|
|
|
|
printf '\n%d passed, %d failed' "$pass" "$fail"
|
|
[ "$skip" -gt 0 ] && printf ', %d skipped' "$skip"
|
|
printf '\n'
|
|
[ "$fail" -eq 0 ] || exit 1
|