feat(local-build): Update all bundled plugins to their latest version for local dev

This commit is contained in:
barlind
2026-07-20 18:11:00 +02:00
parent 2a4396b7b7
commit 70deba5988
5 changed files with 277 additions and 75 deletions
+13 -1
View File
@@ -8,6 +8,19 @@ Unified build system for Slopsmith Desktop supporting Linux (via Docker), macOS,
./scripts/build-release.sh
```
To refresh the plugins in an installed development copy from GitHub:
```bash
./scripts/update-bundled-plugins.sh
```
Use `--dry-run` to preview planned replacements. The updater and release builds both
read `scripts/bundled-plugins.txt`, so newly bundled plugins are picked up
automatically. Set `GH_CLONE_TOKEN` when the repositories require authentication.
On Windows, run it from Git Bash; it automatically uses
`%APPDATA%/feedback-desktop/plugins` and does not require `rsync`. Close the
desktop app before applying updates so Windows does not lock plugin files.
## Call Hierarchy
```
@@ -183,4 +196,3 @@ This signs the bundled binaries but does **not** notarize — notarization requi
### Local cmake-js cache
`build-windows.sh` only force-clears `$HOME/.cmake-js` when `$CI` is set (or `CLEAN_CMAKE_JS=1` is exported). Local Windows builds reuse the cache by default; set `CLEAN_CMAKE_JS=1` if you need a fully fresh build to mirror CI behaviour.
+7 -74
View File
@@ -24,6 +24,7 @@ fi
# is_skipped_lib() — glibc/loader skip list, shared verbatim with
# bundle-binaries.sh so the bundler and the audit never disagree.
source "$SCRIPT_DIR/bundled-lib-skiplist.sh"
source "$SCRIPT_DIR/plugin-manifest.sh"
# Colors
if [[ -z "${RED:-}" ]]; then
@@ -130,87 +131,19 @@ clone_slopsmith() {
# @<branch> clones a non-default branch (used to ship in-review
# plugin work in a feature-branch test build).
cd "$clone_dir/plugins"
local plugins=(
# Bundled plugins — all under the got-feedback org after the migration.
got-feedback/feedback-plugin-bongocat
got-feedback/feedback-plugin-drums
got-feedback/feedback-plugin-editor
got-feedback/feedback-plugin-flappy-bend
got-feedback/feedback-plugin-fretboard
got-feedback/feedback-plugin-guitar-theory
got-feedback/feedback-plugin-invert-highway
got-feedback/feedback-plugin-jumpingtab
got-feedback/feedback-plugin-loosefolder:loose_folder
got-feedback/feedback-plugin-lyrics-karaoke
got-feedback/feedback-plugin-metronome
got-feedback/feedback-plugin-midi
got-feedback/feedback-plugin-multiplayer
got-feedback/feedback-plugin-musicxml-import
got-feedback/feedback-plugin-nam-tone
got-feedback/feedback-plugin-notedetect
got-feedback/feedback-plugin-piano
got-feedback/feedback-plugin-practice
got-feedback/feedback-plugin-sectionmap
got-feedback/feedback-plugin-song-preview
got-feedback/feedback-plugin-splitscreen
got-feedback/feedback-plugin-staffview
got-feedback/feedback-plugin-stem-mixer
# Stem Splitter — repo uses the feedBack-plugin-* casing (capital B),
# so the lowercase prefix strip doesn't apply; explicit dirname
# matching the plugin id, same as rig_builder below.
got-feedback/feedBack-plugin-stem-splitter:stem_splitter
got-feedback/feedback-plugin-stems
got-feedback/feedback-plugin-stepmode
got-feedback/feedback-plugin-strum-fighter
got-feedback/feedback-plugin-studio
got-feedback/feedback-plugin-tabview
got-feedback/feedback-plugin-themes
got-feedback/feedback-plugin-transpose-chords
got-feedback/feedback-plugin-tutorials
got-feedback/feedback-plugin-virtuoso
# Rig Builder (NAM tone builder) — the repo was renamed
# feedBack-plugin-rig-builder (capital B, so the lowercase prefix
# strip doesn't apply; explicit dirname instead). The old
# `got-feedback/rig_builder` name only worked via a GitHub rename
# redirect, which silently breaks if a new repo ever takes that name.
got-feedback/feedBack-plugin-rig-builder:rig_builder
# Camera Director (3D-highway free camera) — our fork of nimuart's plugin
# (v3 popover launcher + drum/piano support; PR upstream at
# nimuart/cameradirector_feedback#3). Repo isn't under the
# feedback-plugin-* prefix, so give an explicit dirname matching the id.
got-feedback/cameradirector_feedback:camera_director
)
local total=0
local cloned=0
for entry in "${plugins[@]}"; do
while IFS= read -r entry; do
total=$((total + 1))
# Split off an optional ":<dirname>" then an optional "@<branch>".
# Git branch names can't contain ':' so the dirname split is safe
# to do first; what's left is "<owner>/<repo>" or "<owner>/<repo>@<branch>".
local spec="$entry" dirname="" branch=""
if [[ "$spec" == *:* ]]; then
dirname="${spec##*:}"
spec="${spec%%:*}"
fi
local owner_repo="$spec"
if [[ "$spec" == *@* ]]; then
branch="${spec##*@}"
owner_repo="${spec%%@*}"
fi
if [[ -z "$dirname" ]]; then
dirname="${owner_repo##*/}"
dirname="${dirname#feedback-plugin-}"
dirname="${dirname//-/_}"
fi
parse_plugin_entry "$entry"
local clone_args=(--depth 1)
[[ -n "$branch" ]] && clone_args+=(--branch "$branch")
if git clone "${clone_args[@]}" "https://${_auth}github.com/${owner_repo}.git" "$dirname" 2>/dev/null; then
[[ -n "$PLUGIN_BRANCH" ]] && clone_args+=(--branch "$PLUGIN_BRANCH")
if git clone "${clone_args[@]}" "https://${_auth}github.com/${PLUGIN_OWNER_REPO}.git" "$PLUGIN_DIRNAME" 2>/dev/null; then
cloned=$((cloned + 1))
else
echo " skipped ${owner_repo}${branch:+@$branch}"
echo " skipped ${PLUGIN_OWNER_REPO}${PLUGIN_BRANCH:+@$PLUGIN_BRANCH}"
fi
done
done < <(plugin_manifest_entries "$SCRIPT_DIR/bundled-plugins.txt")
# Strip dangling symlinks from the bundled tree. Some plugins ship
# build-time symlinks into sources that aren't present at runtime (e.g.
+57
View File
@@ -0,0 +1,57 @@
# Plugins bundled in desktop releases.
#
# This is the single source of truth used by both build-common.sh and
# update-bundled-plugins.sh. Format:
# owner/repo[@branch][:directory]
#
# directory defaults to the repository name with a leading
# "feedback-plugin-" removed and hyphens changed to underscores.
# Bundled plugins — all under the got-feedback org after the migration.
got-feedback/feedback-plugin-bongocat
got-feedback/feedback-plugin-drums
got-feedback/feedback-plugin-editor
got-feedback/feedback-plugin-flappy-bend
got-feedback/feedback-plugin-fretboard
got-feedback/feedback-plugin-guitar-theory
got-feedback/feedback-plugin-invert-highway
got-feedback/feedback-plugin-jumpingtab
got-feedback/feedback-plugin-loosefolder:loose_folder
got-feedback/feedback-plugin-lyrics-karaoke
got-feedback/feedback-plugin-metronome
got-feedback/feedback-plugin-midi
got-feedback/feedback-plugin-multiplayer
got-feedback/feedback-plugin-musicxml-import
got-feedback/feedback-plugin-nam-tone
got-feedback/feedback-plugin-notedetect
got-feedback/feedback-plugin-piano
got-feedback/feedback-plugin-practice
got-feedback/feedback-plugin-sectionmap
got-feedback/feedback-plugin-song-preview
got-feedback/feedback-plugin-splitscreen
got-feedback/feedback-plugin-staffview
got-feedback/feedback-plugin-stem-mixer
# Stem Splitter — repo uses the feedBack-plugin-* casing (capital B),
# so the lowercase prefix strip doesn't apply; explicit dirname
# matching the plugin id, same as rig_builder below.
got-feedback/feedBack-plugin-stem-splitter:stem_splitter
got-feedback/feedback-plugin-stems
got-feedback/feedback-plugin-stepmode
got-feedback/feedback-plugin-strum-fighter
got-feedback/feedback-plugin-studio
got-feedback/feedback-plugin-tabview
got-feedback/feedback-plugin-themes
got-feedback/feedback-plugin-transpose-chords
got-feedback/feedback-plugin-tutorials
got-feedback/feedback-plugin-virtuoso
# Rig Builder (NAM tone builder) — the repo was renamed
# feedBack-plugin-rig-builder (capital B, so the lowercase prefix
# strip doesn't apply; explicit dirname instead). The old
# `got-feedback/rig_builder` name only worked via a GitHub rename
# redirect, which silently breaks if a new repo ever takes that name.
got-feedback/feedBack-plugin-rig-builder:rig_builder
# Camera Director (3D-highway free camera) — our fork of nimuart's plugin
# (v3 popover launcher + drum/piano support; PR upstream at
# nimuart/cameradirector_feedback#3). Repo isn't under the
# feedback-plugin-* prefix, so give an explicit dirname matching the id.
got-feedback/cameradirector_feedback:camera_director
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Shared parser for scripts/bundled-plugins.txt.
plugin_manifest_entries() {
local manifest="${1:?plugin manifest path is required}"
[[ -f "$manifest" ]] || {
echo "Error: plugin manifest not found: $manifest" >&2
return 1
}
# Remove comments and surrounding whitespace, then omit blank lines.
sed -e 's/[[:space:]]*#.*$//' \
-e 's/^[[:space:]]*//' \
-e 's/[[:space:]]*$//' \
-e '/^$/d' "$manifest"
}
parse_plugin_entry() {
local entry="${1:?plugin manifest entry is required}"
# Outputs are globals by design so callers can consume all parsed fields.
# shellcheck disable=SC2034
PLUGIN_REPO_SPEC="$entry"
PLUGIN_DIRNAME=""
# shellcheck disable=SC2034
PLUGIN_BRANCH=""
if [[ "$PLUGIN_REPO_SPEC" == *:* ]]; then
PLUGIN_DIRNAME="${PLUGIN_REPO_SPEC##*:}"
PLUGIN_REPO_SPEC="${PLUGIN_REPO_SPEC%%:*}"
fi
PLUGIN_OWNER_REPO="$PLUGIN_REPO_SPEC"
if [[ "$PLUGIN_REPO_SPEC" == *@* ]]; then
# shellcheck disable=SC2034
PLUGIN_BRANCH="${PLUGIN_REPO_SPEC##*@}"
PLUGIN_OWNER_REPO="${PLUGIN_REPO_SPEC%%@*}"
fi
if [[ -z "$PLUGIN_DIRNAME" ]]; then
PLUGIN_DIRNAME="${PLUGIN_OWNER_REPO##*/}"
PLUGIN_DIRNAME="${PLUGIN_DIRNAME#feedback-plugin-}"
PLUGIN_DIRNAME="${PLUGIN_DIRNAME//-/_}"
fi
[[ "$PLUGIN_OWNER_REPO" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || {
echo "Error: invalid plugin repository in manifest: $entry" >&2
return 1
}
[[ "$PLUGIN_DIRNAME" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]*$ ]] || {
echo "Error: invalid plugin directory in manifest: $entry" >&2
return 1
}
}
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env bash
# Refresh the installed desktop plugins from the same manifest used by CI.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MANIFEST="$SCRIPT_DIR/bundled-plugins.txt"
source "$SCRIPT_DIR/plugin-manifest.sh"
case "$(uname -s)" in
Darwin*) DEFAULT_PLUGIN_DIR="$HOME/Library/Application Support/feedback-desktop/plugins" ;;
MINGW*|MSYS*|CYGWIN*)
[[ -n "${APPDATA:-}" ]] || {
echo "Error: APPDATA is not set; cannot locate the Windows plugin directory" >&2
exit 1
}
windows_appdata="$APPDATA"
if command -v cygpath >/dev/null; then
windows_appdata="$(cygpath -u "$windows_appdata")"
fi
DEFAULT_PLUGIN_DIR="$windows_appdata/feedback-desktop/plugins"
;;
*) DEFAULT_PLUGIN_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/feedback-desktop/plugins" ;;
esac
PLUGIN_DIR="${FEEDBACK_PLUGIN_DIR:-$DEFAULT_PLUGIN_DIR}"
DRY_RUN=false
usage() {
cat <<EOF
Usage: $(basename "$0") [--dry-run] [plugin-directory]
Clones every release plugin at its configured branch (or its default branch)
and synchronizes it into the desktop plugin directory. Plugins newly added to
$MANIFEST are created automatically.
Run this script from Bash (Git Bash on Windows). Set GH_CLONE_TOKEN for private
repositories, or FEEDBACK_PLUGIN_DIR to change the platform default:
$DEFAULT_PLUGIN_DIR
Close feedBack Desktop before applying updates so Windows does not hold plugin
files open. --dry-run is safe while the application is running.
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true ;;
-h|--help) usage; exit 0 ;;
-*) echo "Error: unknown option: $1" >&2; usage >&2; exit 2 ;;
*) PLUGIN_DIR="$1" ;;
esac
shift
done
command -v git >/dev/null || { echo "Error: git is required" >&2; exit 1; }
[[ -d "$PLUGIN_DIR" ]] || {
echo "Error: plugin directory does not exist: $PLUGIN_DIR" >&2
echo "Start feedBack Desktop once, or pass the plugin directory explicitly." >&2
exit 1
}
tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/feedback-plugin-update.XXXXXX")"
trap 'rm -rf "$tmp_dir"' EXIT
auth=""
[[ -n "${GH_CLONE_TOKEN:-}" ]] && auth="x-access-token:${GH_CLONE_TOKEN}@"
total=0
updated=0
unchanged=0
failed=0
while IFS= read -r entry; do
total=$((total + 1))
parse_plugin_entry "$entry"
source_dir="$tmp_dir/$PLUGIN_DIRNAME"
destination="$PLUGIN_DIR/$PLUGIN_DIRNAME"
clone_args=(--depth 1)
[[ -n "$PLUGIN_BRANCH" ]] && clone_args+=(--branch "$PLUGIN_BRANCH")
printf '[%d] %s%s -> %s\n' "$total" "$PLUGIN_OWNER_REPO" \
"${PLUGIN_BRANCH:+@$PLUGIN_BRANCH}" "$PLUGIN_DIRNAME"
if ! git clone -q "${clone_args[@]}" \
"https://${auth}github.com/${PLUGIN_OWNER_REPO}.git" "$source_dir"; then
echo " ERROR: clone failed; installed copy was left unchanged" >&2
failed=$((failed + 1))
continue
fi
# Compare only files tracked by the fetched plugin commit. Runtime-created
# files in the installed directory (for example __pycache__) are deliberately
# ignored. --no-ext-diff and --no-textconv keep the check deterministic and
# prevent a contributor's Git configuration from launching external tools.
if [[ -d "$destination" ]] && git \
--git-dir="$source_dir/.git" \
--work-tree="$destination" \
-c core.safecrlf=false \
diff --quiet --no-ext-diff --no-textconv HEAD --; then
echo " already up to date"
unchanged=$((unchanged + 1))
continue
fi
# Release bundles do not contain repository metadata. Removing it here also
# avoids shipping Windows-incompatible Git worktree files into AppData.
rm -rf "$source_dir/.git"
if [[ "$DRY_RUN" == true ]]; then
if [[ -d "$destination" ]]; then
echo " would replace existing plugin"
else
echo " would install new plugin"
fi
else
# A directory swap works in macOS/Linux Bash and stock Git Bash, where
# rsync is not installed. Keep the old directory until the new one is
# successfully in place so an interrupted move can be rolled back.
backup="$PLUGIN_DIR/.feedback-plugin-backup-$PLUGIN_DIRNAME-$$"
if [[ -e "$backup" ]]; then
echo " ERROR: stale backup exists: $backup" >&2
failed=$((failed + 1))
continue
fi
if [[ -e "$destination" ]] && ! mv "$destination" "$backup"; then
echo " ERROR: could not move installed copy (is the app running?)" >&2
failed=$((failed + 1))
continue
fi
if mv "$source_dir" "$destination"; then
rm -rf "$backup"
else
echo " ERROR: install failed; restoring previous copy" >&2
rm -rf "$destination"
[[ ! -e "$backup" ]] || mv "$backup" "$destination"
failed=$((failed + 1))
continue
fi
fi
updated=$((updated + 1))
done < <(plugin_manifest_entries "$MANIFEST")
if [[ "$DRY_RUN" == true ]]; then
echo "Would update $updated of $total release plugins ($unchanged already up to date) in: $PLUGIN_DIR"
else
echo "Updated $updated of $total release plugins ($unchanged already up to date) in: $PLUGIN_DIR"
fi
if [[ "$failed" -gt 0 ]]; then
echo "Failed to fetch $failed plugin(s); see errors above." >&2
exit 1
fi