From 454e80bcd52aff42bc0057cbcc42b48bd24eb54c Mon Sep 17 00:00:00 2001 From: Mikkeli Date: Wed, 2 Sep 2026 16:36:34 +0900 Subject: [PATCH] fix: separate cargo AUTHOR from Plugin::VENDOR, and rewrite sites precisely Integrating this toolkit into Bari 206 surfaced two things the template could not express, both of which would have produced wrong output. **AUTHOR.** Cargo's authors entry names whoever wrote the plugin; VENDOR is the organisation that ships it. Bari 206 separates them - "Mikkeli Matlock" authored it, "Novoyuuparosk" vends it - while this template only happened to work because its two placeholders were identical. AUTHOR is now its own value defaulting to VENDOR, pinned in branding.conf only when it actually differs so the file keeps showing that it derives. **Site-directed rewriting.** That default is exactly what broke the rename: with AUTHOR defaulting to VENDOR, both fields hold the same old string, and a global value substitution cannot tell which occurrence belongs to which. Renaming the vendor put the org name in the authors field. The site table already holds the old resolved literal for every site it owns, and regeneration produces the new one, so rewriting by that pair is unambiguous. brand-plugin.sh now does that first and falls back to value substitution for everything the table does not enumerate - doc comments, use sites in other modules, prose. The order matters and is load-bearing: run the global pass first and it consumes the old literals, leaving the precise pass nothing to match. Verified on the ambiguous case: renaming with a distinct author now puts the person in Cargo.toml's authors and the org in Plugin::VENDOR, where the previous implementation put the org in both. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WHt4DykxXaQnyaJfyS8KCn --- tools/brand-plugin.sh | 121 ++++++++++++++++++++++++++++-------------- tools/branding.conf | 5 ++ 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/tools/brand-plugin.sh b/tools/brand-plugin.sh index 44764c9..298f90f 100755 --- a/tools/brand-plugin.sh +++ b/tools/brand-plugin.sh @@ -30,13 +30,13 @@ cd "$(dirname "$0")/.." || exit 1 . ./tools/branding.conf OLD_PKG="$PKG"; OLD_DISPLAY="$DISPLAY"; OLD_PLUGIN_NAME="$PLUGIN_NAME" -OLD_VENDOR="$VENDOR"; OLD_EMAIL="$EMAIL"; OLD_HOMEPAGE="$HOMEPAGE" +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_description=""; new_clap_description=""; new_struct=""; new_author="" new_clap_id=""; new_vst3=""; apply=0; allow_identity=0 while [ $# -gt 0 ]; do @@ -44,6 +44,7 @@ while [ $# -gt 0 ]; do --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 ;; @@ -72,7 +73,8 @@ ask() { # ask VARNAME PROMPT CURRENT 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 " "$OLD_VENDOR" + 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" @@ -99,6 +101,7 @@ derive_struct() { [ -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" @@ -158,6 +161,7 @@ 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" @@ -183,12 +187,75 @@ if [ "$apply" -eq 0 ]; then 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" + printf 'req%sdescription.clap%s%s%sconst CLAP_DESCRIPTION: Option<&'"'"'static str> = Some("%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. -subst_file="$(mktemp)" -trap 'rm -f "$subst_file"' EXIT { printf '%s\t%s\n' "$OLD_CLAP_ID" "$new_clap_id" printf '%s\t%s\n' "$OLD_HOMEPAGE" "$new_homepage" @@ -200,6 +267,7 @@ trap 'rm -f "$subst_file"' EXIT 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" @@ -233,6 +301,8 @@ 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\"|" \ @@ -244,6 +314,13 @@ sed -e "s|^PKG=.*|PKG=\"$new_pkg\"|" \ tools/branding.conf > tools/branding.conf.new { sed '$ s/"$//' tools/branding.conf.new; printf '%s"\n' "$retired"; } > tools/branding.conf 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 @@ -251,40 +328,6 @@ printf ' rewrote tools/branding.conf (retired spellings appended to STALE)\n' # 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" -gen="$(mktemp)"; keep="$(mktemp)" -trap 'rm -f "$subst_file" "$gen" "$keep"' 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_vendor" "$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" - printf 'req%sdescription.clap%s%s%sconst CLAP_DESCRIPTION: Option<&'"'"'static str> = Some("%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" owned=$(cut -f2 "$gen") if [ -f "$sites" ]; then diff --git a/tools/branding.conf b/tools/branding.conf index 089897c..72312a2 100644 --- a/tools/branding.conf +++ b/tools/branding.conf @@ -26,6 +26,10 @@ _derive_struct() { PLUGIN_NAME="Plugin Name" # the one name everything else derives from VENDOR="Your Name" # Plugin::VENDOR - the org, not the person EMAIL="your@email.com" # Plugin::EMAIL +# Cargo's authors entry names whoever wrote it, which is not always the vendor: +# an org ships the plugin, a person authored it. Defaults to VENDOR when the two +# are the same, which is the common case for a one-person project. +# AUTHOR="Your Name" HOMEPAGE="https://github.com/YOUR-USERNAME/YOUR-PLUGIN-NAME" # -> Plugin::URL DESCRIPTION="A minimal NIH-plug audio plugin" # Cargo description @@ -66,6 +70,7 @@ PKG="nih_plug_template" STRUCT="MyPlugin" PARAMS_STRUCT="PluginParams" # DISPLAY="Plugin Name" # defaults to PLUGIN_NAME +: "${AUTHOR:=$VENDOR}" : "${DISPLAY:=$PLUGIN_NAME}" : "${PKG:=$(_derive_pkg "$PLUGIN_NAME")}" : "${STRUCT:=$(_derive_struct "$PLUGIN_NAME")}"