Files
codename-206/check-branding.sh
T
mikkeli 466ab478c9 chore: relicense to GPL-3.0-or-later and credit the ISC upstream
Commit 057d630 switched this repo from GPL-3.0 to Apache-2.0, which the
build contradicts: src/lib.rs calls nih_export_vst3! unconditionally and
nih_plug is taken with default features, so every build links vst3-sys —
GPLv3-or-later by its own authors' choice. deploy.ps1 then installs that
binary. The declared licence and the artifact's actual terms disagreed,
and the original GPL-3.0 was correct.

Given the intent to distribute non-profit and open-source, GPL costs
nothing here, so this restores it rather than dropping VST3 to keep a
permissive licence.

Also adds the ISC notice owed to Robbert van der Helm: the plugin
scaffolding derives from the NIH-plug cookiecutter template and example
plugins, whose one condition is that the copyright and permission notice
travel with all copies. The README credited the template under Reference
Material, which is courtesy, not compliance. ISC is GPL-compatible, so the
notice is retained in NOTICE rather than superseded.

Corrects the README's claim that Steinberg's SDK licence must be accepted
before distributing. No SDK source is vendored or redistributed, so there
is nothing to accept at build time. The binding constraint is vst3-sys's
GPLv3; Steinberg's trademark in "VST" is a separate regime 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
2026-08-31 22:32:05 +09:00

202 lines
9.8 KiB
Bash

#!/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 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.
#
# Kept in sync with musiikki/nih-plug-template's copy - fixes belong there
# first, then come back here. The differences are structural, not stylistic:
# this repo keeps its params in src/params.rs and wraps CLAP_DESCRIPTION.
#
# 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="codename_206" # Cargo package name == bundler.toml table key
DISPLAY="Codename 206" # bundle name -> "<DISPLAY>.vst3" / "<DISPLAY>.clap"
PLUGIN_NAME="206 prototype" # Plugin::NAME - what the DAW displays
VENDOR="Novoyuuparosk" # Plugin::VENDOR
EMAIL="mikkeli@novoyuuparosk.org" # Plugin::EMAIL
HOMEPAGE="https://github.com/mikkeli/codename-206" # Cargo homepage -> Plugin::URL
CLAP_ID="com.mikkeli.codename-206" # CLAP_ID - stable plugin identity
VST3_CLASS_ID="Codename206Maxi!" # VST3_CLASS_ID - stable identity, MUST be 16 bytes
DESCRIPTION="A VST3/CLAP multiband compressor/limiter with a custom gain-curve display"
CLAP_DESCRIPTION="Multiband compressor/limiter (stage 3: 3-band + 'All' channel)"
# Rust type names. Cosmetic - they never reach a host - but a rename that leaves
# half of them behind is the residue that says nobody read the file.
STRUCT="Codename206" # the Plugin impl target (src/lib.rs)
PARAMS_STRUCT="Codename206Params" # the Params impl target (src/params.rs)
# Seeded with this repo's CURRENT names, which is the point: each entry is
# skipped while it is still canonical above, and arms itself the moment you
# change that value. So the planned "codename 206" -> "206" rename is
# self-checking - every spelling you miss turns into a FAIL here on the next run.
STALE="codename_206
codename-206
Codename 206
Codename206
Codename206Params
Codename206Maxi!
206 prototype
com.mikkeli.codename-206"
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\""
# CLAP_DESCRIPTION wraps onto a second line here, so the const name and its
# value are never on one line. Match the value alone.
check "CLAP_DESCRIPTION" src/lib.rs "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/params.rs "struct $PARAMS_STRUCT {"
check "impl Default for params" src/params.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