224 lines
11 KiB
Bash
224 lines
11 KiB
Bash
|
|
#!/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
|
||
|
|
cd "$(dirname "$0")" || exit 1
|
||
|
|
[ -f branding.conf ] || { printf 'branding.conf not found next to this script\n' >&2; exit 1; }
|
||
|
|
# shellcheck disable=SC1091
|
||
|
|
. ./branding.conf
|
||
|
|
|
||
|
|
OLD_PKG="$PKG"; OLD_DISPLAY="$DISPLAY"; OLD_PLUGIN_NAME="$PLUGIN_NAME"
|
||
|
|
OLD_VENDOR="$VENDOR"; OLD_EMAIL="$EMAIL"; OLD_HOMEPAGE="$HOMEPAGE"
|
||
|
|
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_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 ;;
|
||
|
|
--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
|
||
|
|
|
||
|
|
[ -n "$new_display" ] || { printf 'nothing to do: pass --display "New Name"\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_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 "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 ------------------------------------------------------------------
|
||
|
|
# 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"
|
||
|
|
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_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
|
||
|
|
case "$f" in 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|^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\"|" \
|
||
|
|
branding.conf > branding.conf.new
|
||
|
|
{ sed '$ s/"$//' branding.conf.new; printf '%s"\n' "$retired"; } > branding.conf
|
||
|
|
rm -f branding.conf.new
|
||
|
|
printf ' rewrote branding.conf (retired spellings appended to STALE)\n'
|
||
|
|
|
||
|
|
printf '\nverifying with check-branding.sh\n\n'
|
||
|
|
sh check-branding.sh
|