feat: adopt the template's branding toolkit

Replaces the single check-branding.sh with the four-file toolkit from
musiikki/nih-plug-template, moved under tools/ alongside where the deploy
scripts will eventually live.

The two scripts are byte-identical to the template's; everything specific
to this plugin lives in tools/branding.conf and tools/branding-sites.tsv.
That is the point of the split: syncing an improvement is now a file copy
rather than a shell merge, which is what the last two syncs had become.

This repo's data differs from the template's in ways that exercise the
design rather than fight it: params live in src/params.rs rather than
src/lib.rs, deploy.ps1 exists so its three rows check instead of skip, and
the CI bundle command carries no --features flag because VST3 is always on
here. All of that is table data now, not forked shell.

Nothing needed overriding: PKG, STRUCT and PARAMS_STRUCT all derive
correctly from PLUGIN_NAME ("Bari 206" -> bari_206 / Bari206 /
Bari206Params). AUTHOR is pinned because this plugin separates the person
who wrote it from the organisation that vends it — a distinction the
template could not express until integrating here surfaced it.

Adopting it required two upstream fixes, both made in the template first
so the scripts stay identical: cargo AUTHOR as a value distinct from
Plugin::VENDOR, and site patterns narrowed to the smallest distinctive
fragment after this repo's rustfmt-wrapped CLAP_DESCRIPTION proved a
statement-spanning pattern cannot match correctly formatted source.

CI is repointed at tools/check-branding.sh, and its path filter widened to
tools/** — the old filter named a file that no longer exists, so a change
to the toolkit would have triggered no CI at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WHt4DykxXaQnyaJfyS8KCn
This commit is contained in:
2026-09-02 16:39:12 +09:00
parent 3161aa9388
commit 3a144064e3
6 changed files with 640 additions and 219 deletions
+355
View File
@@ -0,0 +1,355 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-3.0-or-later
# brand-plugin.sh - rename this plugin, everywhere, in one go.
#
# check-branding.sh tells you what disagrees. This changes it. They share
# branding.conf: this script rewrites that file and every copy of the old values
# in tracked files, then runs the checker and reports what it says. A run that
# ends with the checker green is a rename that landed.
#
# Dry run by default:
# sh brand-plugin.sh --display "Bari 206"
# sh brand-plugin.sh --display "Bari 206" --vendor Novoyuuparosk --apply
#
# Options:
# --display NAME the product name, with spaces and capitals. Everything
# else that can be derived, is derived from this.
# --pkg NAME override the derived Cargo package name.
# --vendor NAME --email ADDR --homepage URL
# --description D --clap-description D
# --struct NAME override the derived Rust type name.
# --allow-identity-change permit CLAP_ID / VST3_CLASS_ID to move. See below.
# --apply actually write. Without it, nothing is modified.
set -u
# Resolve the repo root: these live in tools/, every path they touch is
# repo-relative, and they must behave the same wherever they are invoked from.
cd "$(dirname "$0")/.." || exit 1
[ -f tools/branding.conf ] || { printf 'tools/branding.conf not found\n' >&2; exit 1; }
# shellcheck disable=SC1091
. ./tools/branding.conf
OLD_PKG="$PKG"; OLD_DISPLAY="$DISPLAY"; OLD_PLUGIN_NAME="$PLUGIN_NAME"
OLD_VENDOR="$VENDOR"; OLD_EMAIL="$EMAIL"; OLD_HOMEPAGE="$HOMEPAGE"; OLD_AUTHOR="$AUTHOR"
OLD_DESCRIPTION="$DESCRIPTION"; OLD_CLAP_DESCRIPTION="$CLAP_DESCRIPTION"
OLD_CLAP_ID="$CLAP_ID"; OLD_VST3="$VST3_CLASS_ID"
OLD_STRUCT="$STRUCT"; OLD_PARAMS_STRUCT="$PARAMS_STRUCT"
new_display=""; new_pkg=""; new_vendor=""; new_email=""; new_homepage=""
new_description=""; new_clap_description=""; new_struct=""; new_author=""
new_clap_id=""; new_vst3=""; apply=0; allow_identity=0
while [ $# -gt 0 ]; do
case "$1" in
--display) new_display="${2:?}"; shift 2 ;;
--pkg) new_pkg="${2:?}"; shift 2 ;;
--vendor) new_vendor="${2:?}"; shift 2 ;;
--author) new_author="${2:?}"; shift 2 ;;
--email) new_email="${2:?}"; shift 2 ;;
--homepage) new_homepage="${2:?}"; shift 2 ;;
--description) new_description="${2:?}"; shift 2 ;;
--clap-description) new_clap_description="${2:?}"; shift 2 ;;
--struct) new_struct="${2:?}"; shift 2 ;;
--clap-id) new_clap_id="${2:?}"; shift 2 ;;
--vst3-class-id) new_vst3="${2:?}"; shift 2 ;;
--allow-identity-change) allow_identity=1; shift ;;
--apply) apply=1; shift ;;
-h|--help) sed -n '3,25p' "$0"; exit 0 ;;
*) printf 'unknown option: %s\n' "$1" >&2; exit 2 ;;
esac
done
# Interactive when nothing was passed and there is a terminal to ask at. Every
# prompt offers the current value; Enter keeps it, so a run that answers nothing
# is a no-op rather than a surprise. Optional fields additionally accept "-" to
# clear them.
ask() { # ask VARNAME PROMPT CURRENT
printf ' %s [%s]: ' "$2" "$3" > /dev/tty
IFS= read -r _reply < /dev/tty || _reply=""
[ -n "$_reply" ] || _reply="$3"
[ "$_reply" = "-" ] && _reply=""
eval "$1=\$_reply"
}
if [ -z "$new_display" ] && [ -t 0 ] && [ -c /dev/tty ]; then
printf 'branding this plugin - Enter keeps the current value, "-" clears an optional one\n\n'
ask new_display "display name " "$OLD_DISPLAY"
ask new_vendor "vendor (org) " "$OLD_VENDOR"
ask new_author "cargo author " "$OLD_AUTHOR"
ask new_email "email " "$OLD_EMAIL"
ask new_homepage "homepage " "$OLD_HOMEPAGE"
ask new_description "cargo description" "$OLD_DESCRIPTION"
ask new_clap_description "clap description" "$OLD_CLAP_DESCRIPTION"
printf '\n'
fi
[ -n "$new_display" ] || { printf 'nothing to do: pass --display "New Name" (or run interactively)\n' >&2; exit 2; }
# --- derivation -------------------------------------------------------------
# Package name: lowercase, every run of non-alphanumerics becomes one separator,
# ends trimmed. Cargo accepts both hyphens and underscores in a package name and
# converts to underscores for the built artifact, which nih_plug_xtask already
# accounts for; underscores are used here to match the Rust convention.
derive_pkg() {
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' \
| sed -e 's/[^a-z0-9]\{1,\}/_/g' -e 's/^_//' -e 's/_$//'
}
# Rust type name: CamelCase, non-alphanumerics dropped entirely.
derive_struct() {
printf '%s' "$1" | sed -e 's/[^A-Za-z0-9]\{1,\}/ /g' \
| awk '{for(i=1;i<=NF;i++) printf "%s%s", toupper(substr($i,1,1)), substr($i,2); print ""}'
}
[ -n "$new_pkg" ] || new_pkg=$(derive_pkg "$new_display")
[ -n "$new_struct" ] || new_struct=$(derive_struct "$new_display")
new_params_struct="${new_struct}Params"
[ -n "$new_vendor" ] || new_vendor="$OLD_VENDOR"
[ -n "$new_author" ] || new_author="$OLD_AUTHOR"
[ -n "$new_email" ] || new_email="$OLD_EMAIL"
[ -n "$new_homepage" ] || new_homepage="$OLD_HOMEPAGE"
[ -n "$new_description" ] || new_description="$OLD_DESCRIPTION"
[ -n "$new_clap_description" ] || new_clap_description="$OLD_CLAP_DESCRIPTION"
# --- validation -------------------------------------------------------------
fail=0
die() { printf ' INVALID %s\n' "$1"; fail=$((fail+1)); }
case "$new_pkg" in
"") die "derived package name is empty" ;;
[0-9]*) die "package name \"$new_pkg\" starts with a digit - cargo rejects this outright" ;;
esac
case "$new_pkg" in
test|core|std|alloc|proc_macro)
die "package name \"$new_pkg\" collides with a built-in crate" ;;
as|break|const|continue|crate|dyn|else|enum|extern|false|fn|for|if|impl|in|let|loop|match|mod|move|mut|pub|ref|return|self|static|struct|super|trait|true|type|unsafe|use|where|while|async|await|box|do|final|macro|override|priv|typeof|unsized|virtual|yield|try)
die "package name \"$new_pkg\" is a Rust keyword - cargo rejects this" ;;
esac
# bundler.toml uses the package name as a TOML bare key.
case "$new_pkg" in *[!a-zA-Z0-9_-]*) die "package name \"$new_pkg\" is not a valid TOML bare key" ;; esac
case "$new_struct" in ""|[0-9]*) die "derived type name \"$new_struct\" is not a valid Rust identifier" ;; esac
# --- frozen identity --------------------------------------------------------
identity_note=""
if [ -n "$new_clap_id" ] || [ -n "$new_vst3" ]; then
if [ "$allow_identity" -eq 0 ]; then
die "CLAP_ID / VST3_CLASS_ID are frozen identity; pass --allow-identity-change to move them"
fi
fi
[ -n "$new_clap_id" ] || new_clap_id="$OLD_CLAP_ID"
[ -n "$new_vst3" ] || new_vst3="$OLD_VST3"
# VST3_CLASS_ID is a fixed 16-byte array, so it cannot simply be derived. Propose
# one from the new name and let a human decide - it is frozen the moment it ships.
proposed_vst3=$(printf '%s' "${new_struct}Plugin000000000000" | cut -c1-16)
n=$(printf '%s' "$new_vst3" | wc -c | tr -d ' ')
[ "$n" -eq 16 ] || die "VST3_CLASS_ID \"$new_vst3\" is $n bytes, must be exactly 16"
case "$new_clap_id" in
*\ *|*[A-Z]*) die "CLAP_ID \"$new_clap_id\" must be lowercase with no spaces" ;;
*.*) ;;
*) die "CLAP_ID \"$new_clap_id\" should be dotted reverse-DNS" ;;
esac
# CLAP_DESCRIPTION is user-facing: keep development history out of it.
for hist in "$CODENAME" "$OLD_DISPLAY" "$OLD_PKG"; do
case "$new_clap_description" in
*"$hist"*) die "CLAP_DESCRIPTION still mentions \"$hist\" - it is shown to users, who never knew the development name" ;;
esac
done
# --- plan -------------------------------------------------------------------
printf 'rename plan\n\n'
row() { [ "$2" = "$3" ] && printf ' %-18s %s (unchanged)\n' "$1" "$2" || printf ' %-18s %s -> %s\n' "$1" "$2" "$3"; }
row "package" "$OLD_PKG" "$new_pkg"
row "display" "$OLD_DISPLAY" "$new_display"
row "Plugin::NAME" "$OLD_PLUGIN_NAME" "$new_display"
row "vendor" "$OLD_VENDOR" "$new_vendor"
row "cargo author" "$OLD_AUTHOR" "$new_author"
row "email" "$OLD_EMAIL" "$new_email"
row "homepage" "$OLD_HOMEPAGE" "$new_homepage"
row "description" "$OLD_DESCRIPTION" "$new_description"
row "clap desc" "$OLD_CLAP_DESCRIPTION" "$new_clap_description"
row "struct" "$OLD_STRUCT" "$new_struct"
row "params struct" "$OLD_PARAMS_STRUCT" "$new_params_struct"
row "CLAP_ID" "$OLD_CLAP_ID" "$new_clap_id"
row "VST3_CLASS_ID" "$OLD_VST3" "$new_vst3"
printf '\n repo codename stays %s - fixed at creation, never renamed\n' "$CODENAME"
if [ "$new_vst3" = "$OLD_VST3" ]; then
printf ' suggested VST3_CLASS_ID for this name (16 bytes): "%s"\n' "$proposed_vst3"
printf ' apply with --vst3-class-id "%s" --allow-identity-change, and only before first release\n' "$proposed_vst3"
fi
if [ "$fail" -ne 0 ]; then
printf '\n%d problem(s); nothing written.\n' "$fail"
exit 1
fi
if [ "$apply" -eq 0 ]; then
printf '\nDry run. Re-run with --apply to write these changes.\n'
exit 0
fi
# --- apply ------------------------------------------------------------------
# Three scratch files, one trap: the regenerated site table, the rows carried
# through from the old one, and the value-substitution pairs.
gen="$(mktemp)"; keep="$(mktemp)"; subst_file="$(mktemp)"
trap 'rm -f "$gen" "$keep" "$subst_file"' EXIT
T="$(printf '\t')"
{
printf 'req%spkg.cargo%sCargo.toml%sname = "%s"\n' "$T" "$T" "$T" "$new_pkg"
printf 'req%spkg.bundler%sbundler.toml%s[%s]\n' "$T" "$T" "$T" "$new_pkg"
printf 'opt%spkg.lock%sCargo.lock%sname = "%s"\n' "$T" "$T" "$T" "$new_pkg"
printf 'opt%spkg.ci%s.github/workflows/ci.yaml%scargo xtask bundle %s\n' "$T" "$T" "$T" "$new_pkg"
printf 'opt%spkg.readme%sREADME.md%scargo xtask bundle %s\n' "$T" "$T" "$T" "$new_pkg"
printf 'req%sdisplay.bundler%sbundler.toml%sname = "%s"\n' "$T" "$T" "$T" "$new_display"
printf 'opt%sdisplay.notice%sNOTICE%s%s\n' "$T" "$T" "$T" "$new_display"
printf 'req%sname.plugin%s%s%sconst NAME: &'"'"'static str = "%s"\n' "$T" "$T" "$LIB_FILE" "$T" "$new_display"
printf 'req%svendor.plugin%s%s%sconst VENDOR: &'"'"'static str = "%s"\n' "$T" "$T" "$LIB_FILE" "$T" "$new_vendor"
printf 'req%semail.plugin%s%s%sconst EMAIL: &'"'"'static str = "%s"\n' "$T" "$T" "$LIB_FILE" "$T" "$new_email"
printf 'req%sauthors.cargo%sCargo.toml%sauthors = ["%s <%s>"]\n' "$T" "$T" "$T" "$new_author" "$new_email"
printf 'req%shomepage.cargo%sCargo.toml%shomepage = "%s"\n' "$T" "$T" "$T" "$new_homepage"
printf 'req%surl.plugin%s%s%sconst URL: &'"'"'static str = env!("CARGO_PKG_HOMEPAGE")\n' "$T" "$T" "$LIB_FILE" "$T"
printf 'req%sdescription.cargo%sCargo.toml%sdescription = "%s"\n' "$T" "$T" "$T" "$new_description"
# Narrowest distinctive fragment, not the whole statement: rustfmt wraps a long
# CLAP_DESCRIPTION onto its own line, and a pattern spanning the assignment
# would then never match a correctly formatted file.
printf 'req%sdescription.clap%s%s%sSome("%s")\n' "$T" "$T" "$LIB_FILE" "$T" "$new_clap_description"
printf 'req%sclapid.plugin%s%s%sconst CLAP_ID: &'"'"'static str = "%s"\n' "$T" "$T" "$LIB_FILE" "$T" "$new_clap_id"
printf 'req%svst3id.plugin%s%s%sconst VST3_CLASS_ID: [u8; 16] = *b"%s"\n' "$T" "$T" "$LIB_FILE" "$T" "$new_vst3"
printf 'req%sstruct.def%s%s%sstruct %s {\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sstruct.plugin%s%s%simpl Plugin for %s {\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sstruct.clap%s%s%simpl ClapPlugin for %s {\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sstruct.vst3%s%s%simpl Vst3Plugin for %s {\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sstruct.exportclap%s%s%snih_export_clap!(%s);\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sstruct.exportvst3%s%s%snih_export_vst3!(%s);\n' "$T" "$T" "$LIB_FILE" "$T" "$new_struct"
printf 'req%sparams.def%s%s%sstruct %s {\n' "$T" "$T" "$PARAMS_FILE" "$T" "$new_params_struct"
printf 'req%sparams.default%s%s%simpl Default for %s {\n' "$T" "$T" "$PARAMS_FILE" "$T" "$new_params_struct"
printf 'req%sparams.field%s%s%sparams: Arc<%s>,\n' "$T" "$T" "$LIB_FILE" "$T" "$new_params_struct"
printf 'opt%sdeploy.pkg%sdeploy.ps1%s$Package = "%s"\n' "$T" "$T" "$T" "$new_pkg"
printf 'opt%sdeploy.vst3%sdeploy.ps1%s$vst3Name = "%s.vst3"\n' "$T" "$T" "$T" "$new_display"
printf 'opt%sdeploy.clap%sdeploy.ps1%s$clapName = "%s.clap"\n' "$T" "$T" "$T" "$new_display"
} > "$gen"
# Pass 1 - site-directed. Each owned row in the existing table carries the OLD
# resolved literal for its site; the regenerated row carries the new one. Rewriting
# by that pair is unambiguous, which plain value substitution is not: AUTHOR
# defaults to VENDOR, so both fields can hold the same old string and a global
# replace cannot tell which occurrence belongs to which. This must run BEFORE
# pass 2, or the global replace consumes the old literals first and leaves the
# precise rewrite with nothing to match.
sites="tools/branding-sites.tsv"
T="$(printf '\t')"
if [ -f "$sites" ]; then
while IFS="$T" read -r ok_ oo_ of_ op_; do
case "$ok_" in ''|\#*) continue ;; esac
np_=$(awk -F"$T" -v o="$oo_" '$2==o {print $4; exit}' "$gen")
[ -n "$np_" ] || continue
[ "$np_" != "$op_" ] || continue
[ -f "$of_" ] || continue
esc_o=$(printf '%s' "$op_" | sed 's/[][\.*^$/|&]/\\&/g')
esc_n=$(printf '%s' "$np_" | sed 's/[\\/&|]/\\&/g')
tmp_=$(mktemp)
sed "s|$esc_o|$esc_n|g" "$of_" > "$tmp_" && cat "$tmp_" > "$of_"
rm -f "$tmp_"
done < "$sites"
printf ' pass 1: rewrote known sites from the table\n'
fi
# Pass 2 - value substitution, for everything the table does not enumerate:
# doc comments, use sites in other modules, prose in the README.
# Longest values first: a shorter spelling can be a substring of a longer one
# (the package name inside a URL, say), and replacing it first would corrupt the
# longer match. branding.conf is excluded and rewritten wholesale below, so its
# STALE list is never rewritten into meaninglessness.
{
printf '%s\t%s\n' "$OLD_CLAP_ID" "$new_clap_id"
printf '%s\t%s\n' "$OLD_HOMEPAGE" "$new_homepage"
printf '%s\t%s\n' "$OLD_CLAP_DESCRIPTION" "$new_clap_description"
printf '%s\t%s\n' "$OLD_DESCRIPTION" "$new_description"
printf '%s\t%s\n' "$OLD_PARAMS_STRUCT" "$new_params_struct"
printf '%s\t%s\n' "$OLD_VST3" "$new_vst3"
printf '%s\t%s\n' "$OLD_PLUGIN_NAME" "$new_display"
printf '%s\t%s\n' "$OLD_DISPLAY" "$new_display"
printf '%s\t%s\n' "$OLD_STRUCT" "$new_struct"
printf '%s\t%s\n' "$OLD_EMAIL" "$new_email"
printf '%s\t%s\n' "$OLD_AUTHOR" "$new_author"
printf '%s\t%s\n' "$OLD_VENDOR" "$new_vendor"
printf '%s\t%s\n' "$OLD_PKG" "$new_pkg"
} | awk -F'\t' '$1 != $2 { print length($1)"\t"$0 }' | sort -rn | cut -f2- > "$subst_file"
changed=0
git ls-files 2>/dev/null | while IFS= read -r f; do
[ -f "$f" ] || continue
# branding.conf alone is excluded: it is rewritten wholesale below, and its
# STALE list names every retired spelling by design. The site table IS
# substituted, so hand-added custom rows track the rename; owned rows are
# regenerated afterwards regardless.
case "$f" in tools/branding.conf) continue ;; esac
before=$(cat "$f")
after="$before"
while IFS="$(printf '\t')" read -r old new; do
[ -n "$old" ] || continue
after=$(printf '%s' "$after" | sed "s|$(printf '%s' "$old" | sed 's/[][\.*^$/|&]/\\&/g')|$(printf '%s' "$new" | sed 's/[\\/&|]/\\&/g')|g")
done < "$subst_file"
if [ "$before" != "$after" ]; then printf '%s\n' "$after" > "$f"; printf ' rewrote %s\n' "$f"; fi
done
# branding.conf last, with the retired spellings appended to STALE so the next
# run of the checker sweeps for anything this pass missed.
# Deduplicated: two fields can retire to the same spelling - DISPLAY and
# PLUGIN_NAME are commonly identical - and listing it twice makes the checker
# report the same drift twice. Note that neither this script nor the checker
# contains a branding literal anywhere: both read every name from
# branding.conf, so a rename never has to rewrite its own tooling.
retired=$(cut -f1 "$subst_file" | awk '!seen[$0]++')
sed -e "s|^PKG=.*|PKG=\"$new_pkg\"|" \
-e "s|^DISPLAY=.*|DISPLAY=\"$new_display\"|" \
-e "s|^PLUGIN_NAME=.*|PLUGIN_NAME=\"$new_display\"|" \
-e "s|^VENDOR=.*|VENDOR=\"$new_vendor\"|" \
-e "s|^# *AUTHOR=.*|AUTHOR=\"$new_author\"|" \
-e "s|^AUTHOR=.*|AUTHOR=\"$new_author\"|" \
-e "s|^EMAIL=.*|EMAIL=\"$new_email\"|" \
-e "s|^HOMEPAGE=.*|HOMEPAGE=\"$new_homepage\"|" \
-e "s|^DESCRIPTION=.*|DESCRIPTION=\"$new_description\"|" \
-e "s|^CLAP_DESCRIPTION=.*|CLAP_DESCRIPTION=\"$new_clap_description\"|" \
-e "s|^CLAP_ID=.*|CLAP_ID=\"$new_clap_id\"|" \
-e "s|^VST3_CLASS_ID=.*|VST3_CLASS_ID=\"$new_vst3\"|" \
-e "s|^STRUCT=.*|STRUCT=\"$new_struct\"|" \
-e "s|^PARAMS_STRUCT=.*|PARAMS_STRUCT=\"$new_params_struct\"|" \
tools/branding.conf > tools/branding.conf.new
if [ -n "$retired" ]; then
{ sed '$ s/"$//' tools/branding.conf.new; printf '%s"\n' "$retired"; } > tools/branding.conf
else
# Nothing retired (a no-op rename, or a regeneration): leave STALE untouched
# rather than appending a blank line to it on every run.
cat tools/branding.conf.new > tools/branding.conf
fi
rm -f tools/branding.conf.new
if [ "$new_author" = "$new_vendor" ]; then
# Identical to VENDOR, so re-comment it: the conf should keep showing that this
# value derives rather than pinning a duplicate that then has to be maintained.
tmp_c=$(mktemp)
sed "s|^AUTHOR=.*|# AUTHOR=\"$new_author\"|" tools/branding.conf > "$tmp_c" && cat "$tmp_c" > tools/branding.conf
rm -f "$tmp_c"
fi
printf ' rewrote tools/branding.conf (retired spellings appended to STALE)\n'
# Regenerate the site table. Rows whose owner this script recognises are
# rewritten with the new resolved literals; every other row - anything marked
# custom, or added by hand for a file this template does not ship - is carried
# through untouched. Clobbering those silently is how a tool stops being trusted.
sites="tools/branding-sites.tsv"
owned=$(cut -f2 "$gen")
if [ -f "$sites" ]; then
grep '^#' "$sites" > "$keep" 2>/dev/null || : > "$keep"
while IFS="$T" read -r k o f pat; do
case "$k" in ''|\#*) continue ;; esac
printf '%s\n' "$owned" | grep -qxF "$o" || printf '%s%s%s%s%s%s%s\n' "$k" "$T" "$o" "$T" "$f" "$T" "$pat" >> "$keep"
done < "$sites"
else
: > "$keep"
fi
{ cat "$keep"; cat "$gen"; } > "$sites"
printf ' rewrote %s (%s owned rows, %s preserved)\n' "$sites" "$(wc -l < "$gen" | tr -d ' ')" "$(grep -cv '^#' "$keep" 2>/dev/null || echo 0)"
printf '\nverifying with check-branding.sh\n\n'
sh tools/check-branding.sh
+29
View File
@@ -0,0 +1,29 @@
req pkg.cargo Cargo.toml name = "bari_206"
req pkg.bundler bundler.toml [bari_206]
opt pkg.lock Cargo.lock name = "bari_206"
opt pkg.ci .github/workflows/ci.yaml cargo xtask bundle bari_206
opt pkg.readme README.md cargo xtask bundle bari_206
req display.bundler bundler.toml name = "Bari 206"
opt display.notice NOTICE Bari 206
req name.plugin src/lib.rs const NAME: &'static str = "Bari 206"
req vendor.plugin src/lib.rs const VENDOR: &'static str = "Novoyuuparosk"
req email.plugin src/lib.rs const EMAIL: &'static str = "mikkeli@novoyuuparosk.org"
req authors.cargo Cargo.toml authors = ["Mikkeli Matlock <mikkeli@novoyuuparosk.org>"]
req homepage.cargo Cargo.toml homepage = "https://github.com/mikkeli/codename-206"
req url.plugin src/lib.rs const URL: &'static str = env!("CARGO_PKG_HOMEPAGE")
req description.cargo Cargo.toml description = "A VST3/CLAP multiband compressor/limiter with a custom gain-curve display"
req description.clap src/lib.rs Some("Multiband compressor/limiter (stage 3: 3-band + 'All' channel)")
req clapid.plugin src/lib.rs const CLAP_ID: &'static str = "org.novoyuuparosk.bari-206"
req vst3id.plugin src/lib.rs const VST3_CLASS_ID: [u8; 16] = *b"Bari206Multiband"
req struct.def src/lib.rs struct Bari206 {
req struct.plugin src/lib.rs impl Plugin for Bari206 {
req struct.clap src/lib.rs impl ClapPlugin for Bari206 {
req struct.vst3 src/lib.rs impl Vst3Plugin for Bari206 {
req struct.exportclap src/lib.rs nih_export_clap!(Bari206);
req struct.exportvst3 src/lib.rs nih_export_vst3!(Bari206);
req params.def src/params.rs struct Bari206Params {
req params.default src/params.rs impl Default for Bari206Params {
req params.field src/lib.rs params: Arc<Bari206Params>,
opt deploy.pkg deploy.ps1 $Package = "bari_206"
opt deploy.vst3 deploy.ps1 $vst3Name = "Bari 206.vst3"
opt deploy.clap deploy.ps1 $clapName = "Bari 206.clap"
Can't render this file because it contains an unexpected character in line 1 and column 33.
+66
View File
@@ -0,0 +1,66 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# branding.conf - this plugin's canonical identity.
#
# Managed by tools/brand-plugin.sh, read by tools/check-branding.sh. Hand-editing
# works and is sometimes the quickest thing, but the helper is what keeps this
# file, the source tree and tools/branding-sites.tsv agreeing with each other.
# Edit here and you are on the hook for running the checker afterwards.
# --- derivations ------------------------------------------------------------
_derive_pkg() {
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' \
| sed -e 's/[^a-z0-9]\{1,\}/_/g' -e 's/^_//' -e 's/_$//'
}
_derive_struct() {
printf '%s' "$1" | sed -e 's/[^A-Za-z0-9]\{1,\}/ /g' \
| awk '{for(i=1;i<=NF;i++) printf "%s%s", toupper(substr($i,1,1)), substr($i,2); print ""}'
}
# --- the names ---------------------------------------------------------------
PLUGIN_NAME="Bari 206"
VENDOR="Novoyuuparosk"
EMAIL="mikkeli@novoyuuparosk.org"
AUTHOR="Mikkeli Matlock"
HOMEPAGE="https://github.com/mikkeli/codename-206"
DESCRIPTION="A VST3/CLAP multiband compressor/limiter with a custom gain-curve display"
# What the plugin does *now*. No codename, no development stage.
CLAP_DESCRIPTION="Multiband compressor/limiter (stage 3: 3-band + 'All' channel)"
# --- frozen identity ---------------------------------------------------------
# Hosts key saved projects and presets off these two. Never move them after the
# first release: every existing session silently loses the plugin.
CLAP_ID="org.novoyuuparosk.bari-206"
VST3_CLASS_ID="Bari206Multiband"
# --- fixed at repo creation --------------------------------------------------
# The repo keeps its development codename while the plugin carries the product
# name. Recorded only so it can be kept out of user-facing text.
CODENAME="codename-206"
LIB_FILE="src/lib.rs"
PARAMS_FILE="src/params.rs"
# --- derived unless overridden -----------------------------------------------
# PKG, STRUCT and PARAMS_STRUCT all derive correctly from PLUGIN_NAME here, so
# none is pinned. DISPLAY defaults to PLUGIN_NAME.
: "${AUTHOR:=$VENDOR}"
: "${DISPLAY:=$PLUGIN_NAME}"
: "${PKG:=$(_derive_pkg "$PLUGIN_NAME")}"
: "${STRUCT:=$(_derive_struct "$PLUGIN_NAME")}"
: "${PARAMS_STRUCT:=${STRUCT}Params}"
# --- retired spellings -------------------------------------------------------
STALE="codename_206
Codename 206
Codename206
Codename206Params
Codename206Maxi!
206 prototype
com.mikkeli.codename-206
bari_206
Bari 206
Bari206
Bari206Params
Bari206Multiband
org.novoyuuparosk.bari-206"
+188
View File
@@ -0,0 +1,188 @@
#!/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 tools/check-branding.sh (exit 0 = consistent, 1 = drift found)
#
# The canonical identity lives in branding.conf, shared with brand-plugin.sh.
# Edit it there, then run this to find every copy that still holds the old value.
set -u
# Resolve the repo root: these live in tools/, every path they touch is
# repo-relative, and they must behave the same wherever they are invoked from.
cd "$(dirname "$0")/.." || exit 1
if [ ! -f tools/branding.conf ]; then
printf 'tools/branding.conf not found\n' >&2
exit 1
fi
# shellcheck disable=SC1091
. ./tools/branding.conf
# 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"
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"
# --- consistency: every site in the table holds its resolved literal ----------
# The table is data, so adding a site is a row rather than a shell edit, and the
# same script runs unmodified across every plugin built from this template.
SITES="tools/branding-sites.tsv"
if [ ! -f "$SITES" ]; then
bad "site table" "$SITES not found - run tools/brand-plugin.sh to generate it"
else
printf 'sites\n'
while IFS="$(printf '\t')" read -r kind owner file pattern; do
case "$kind" in ''|\#*) continue ;; esac
[ -n "$pattern" ] || continue
label="$owner"
if [ ! -f "$file" ]; then
case "$kind" in
opt) note "$label ($file not present)" ;;
*) bad "$label" "missing file: $file" ;;
esac
continue
fi
if has "$file" "$pattern"; then ok "$label"
else bad "$label" "$file does not contain: $pattern"; fi
done < "$SITES"
fi
# --- validity: rules the table cannot express --------------------------------
printf '\nvalidity\n'
# VST3 class IDs are a fixed 16-byte array. A wrong length is a compile error,
# but saying so here is clearer than reading 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 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
# An overridden package name is legitimate - the derivation is sometimes invalid
# - but a display rename that forgot the package is not, and looks identical
# from here. Reported, never failed.
derived_pkg=$(_derive_pkg "$PLUGIN_NAME")
[ "$PKG" = "$derived_pkg" ] || info "PKG \"$PKG\" differs from the derivation of PLUGIN_NAME (\"$derived_pkg\") - fine if deliberate"
# CLAP_DESCRIPTION is shown to users in a host's plugin browser. "Free of
# development history" is a judgement a script cannot make, but the failure it
# produces is mechanical: a retired name or the repo codename surviving in it.
hygiene_hits=""
while IFS= read -r s_entry; do
[ -n "$s_entry" ] || continue
case "$CANONICAL_BLOB" in *"$s_entry"*) continue ;; esac
case "$CLAP_DESCRIPTION" in *"$s_entry"*) hygiene_hits="$hygiene_hits \"$s_entry\"" ;; esac
done <<HYGIENE_LIST
$STALE
$CODENAME
HYGIENE_LIST
if [ -z "$hygiene_hits" ]; then ok "CLAP_DESCRIPTION carries no retired name or codename"
else bad "CLAP_DESCRIPTION carries no retired name or codename" "found:$hygiene_hits"; fi
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"
# 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
# These two name every retired spelling by definition - the STALE list lives in
# branding.conf and this script reads it - so neither can ever be a real hit.
hits=$(file_list 2>/dev/null | while read -r f; do
case "$f" in tools/check-branding.sh|tools/branding.conf) continue ;; esac
[ -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