generated from boboko/starter
147 lines
5.7 KiB
Bash
Executable File
147 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Switch how this app consumes boboko-core, then restart the dev stack so the
|
|
# entrypoints re-resolve it.
|
|
#
|
|
# bin/core-mode local ../boboko-core checkout (Composer path repo + npm file:)
|
|
# bin/core-mode repo tagged releases from the forge (Composer VCS repo + npm git+semver)
|
|
# bin/core-mode print the current mode
|
|
#
|
|
# Running it for the mode you're already in skips the file edits but still
|
|
# restarts the stack — that's how repo mode picks up a newly pushed tag.
|
|
#
|
|
# The toggle lives in composer.json ("repositories" <-> "_repositories") and
|
|
# package.json (@boboko/core in "dependencies" <-> "_dependencies"). The dev
|
|
# entrypoints run `composer update boboko/*` and `npm update @boboko/core` on
|
|
# every boot, which rewrites composer.lock / package-lock.json for the mode.
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
fail() { echo "!!! $*" >&2; exit 1; }
|
|
|
|
# Escape a string for use as a sed regex / replacement with "|" as delimiter.
|
|
sed_pattern() { printf '%s' "$1" | sed 's/[][\.*^$|]/\\&/g'; }
|
|
sed_replacement() { printf '%s' "$1" | sed 's/[\&|]/\\&/g'; }
|
|
|
|
current_mode() {
|
|
local composer_type npm_dep composer_mode npm_mode
|
|
# The live block is "repositories" — the leading quote keeps "_repositories" out.
|
|
composer_type=$(sed -n '/"repositories": \[/,/"type"/p' composer.json | grep -o '"type": "[a-z]*"' | head -1)
|
|
npm_dep=$(sed -n '/"dependencies": {/,/}/p' package.json | grep -o '"@boboko/core": "[^"]*"' | head -1)
|
|
|
|
case "$composer_type" in
|
|
*'"path"') composer_mode=local ;;
|
|
*'"vcs"') composer_mode=repo ;;
|
|
*) fail "Can't tell the mode from composer.json's \"repositories\" block." ;;
|
|
esac
|
|
case "$npm_dep" in
|
|
*'"file:'*) npm_mode=local ;;
|
|
*'"git+'*) npm_mode=repo ;;
|
|
*) fail "Can't tell the mode from package.json's @boboko/core dependency." ;;
|
|
esac
|
|
[ "$composer_mode" = "$npm_mode" ] ||
|
|
fail "composer.json ($composer_mode) and package.json ($npm_mode) disagree — fix by hand first."
|
|
|
|
echo "$composer_mode"
|
|
}
|
|
|
|
swap_files() {
|
|
# composer.json: swap the key names, values stay where they are.
|
|
sed -i \
|
|
-e 's/"_repositories":/"__core_mode_swap__":/' \
|
|
-e 's/"repositories":/"_repositories":/' \
|
|
-e 's/"__core_mode_swap__":/"repositories":/' \
|
|
composer.json
|
|
|
|
# package.json: swap the two @boboko/core values (live and parked).
|
|
local a b
|
|
a=$(grep -o '"@boboko/core": "[^"]*"' package.json | sed -n 1p)
|
|
b=$(grep -o '"@boboko/core": "[^"]*"' package.json | sed -n 2p)
|
|
[ -n "$a" ] && [ -n "$b" ] || fail "Expected two @boboko/core entries in package.json."
|
|
sed -i \
|
|
-e "s|$(sed_pattern "$a")|__core_mode_swap__|" \
|
|
-e "s|$(sed_pattern "$b")|$(sed_replacement "$a")|" \
|
|
-e "s|__core_mode_swap__|$(sed_replacement "$b")|" \
|
|
package.json
|
|
}
|
|
|
|
wrapper_for() {
|
|
if [ "$1" = local ]; then echo bin/dc-core.sh; else echo bin/dc; fi
|
|
}
|
|
|
|
# The app healthcheck (php-fpm -t) passes before the entrypoint finishes, so
|
|
# wait on the entrypoints' own log lines instead: the app's composer block is
|
|
# done once it clears caches, the vite container's npm block once Vite is up.
|
|
wait_for_log() {
|
|
local dc=$1 service=$2 pattern=$3 label=$4 waited=0
|
|
printf '>>> Waiting for %s' "$label"
|
|
until $dc logs --no-color "$service" 2>&1 | grep -q "$pattern"; do
|
|
if [ -z "$($dc ps -q --status running "$service")" ]; then
|
|
echo
|
|
$dc logs --no-color --tail 40 "$service"
|
|
fail "$service stopped before finishing (logs above)."
|
|
fi
|
|
if [ "$waited" -ge 600 ]; then
|
|
echo
|
|
$dc logs --no-color --tail 40 "$service"
|
|
fail "Timed out after 600s waiting for $service (logs above)."
|
|
fi
|
|
printf '.'
|
|
sleep 3
|
|
waited=$((waited + 3))
|
|
done
|
|
echo " done"
|
|
}
|
|
|
|
mode=$(current_mode)
|
|
|
|
if [ $# -eq 0 ]; then
|
|
echo "$mode"
|
|
exit 0
|
|
fi
|
|
|
|
target=$1
|
|
[ "$target" = local ] || [ "$target" = repo ] || fail "Usage: bin/core-mode [local|repo]"
|
|
if [ "$target" = local ] && [ ! -d ../boboko-core ]; then
|
|
fail "../boboko-core not found — local mode needs the core checkout next to this repo."
|
|
fi
|
|
|
|
old_dc=$(wrapper_for "$mode")
|
|
new_dc=$(wrapper_for "$target")
|
|
|
|
echo ">>> Stopping stack ($mode mode)..."
|
|
$old_dc down
|
|
|
|
if [ "$mode" != "$target" ]; then
|
|
echo ">>> Switching composer.json / package.json: $mode -> $target"
|
|
swap_files
|
|
[ "$(current_mode)" = "$target" ] || fail "Switch didn't take — check composer.json / package.json."
|
|
else
|
|
echo ">>> Already in $target mode, restarting to re-resolve boboko-core"
|
|
fi
|
|
|
|
# The entrypoints run `composer install` / `npm install` from the lockfiles
|
|
# BEFORE re-resolving core. Local-mode lockfiles point at ../boboko-core,
|
|
# which isn't mounted in repo mode, so the install fails. The committed
|
|
# lockfiles are always repo mode — restore those and let the entrypoints bump
|
|
# them to the newest tag.
|
|
if [ "$target" = repo ]; then
|
|
if grep -A14 '"name": "boboko/core"' composer.lock | grep -q '"type": "path"' ||
|
|
grep -A6 '"node_modules/@boboko/core": {' package-lock.json | grep -q '"link": true'; then
|
|
echo ">>> Lockfiles still point at ../boboko-core — restoring the committed ones"
|
|
git checkout HEAD -- composer.lock package-lock.json
|
|
fi
|
|
fi
|
|
|
|
echo ">>> Starting stack ($target mode)..."
|
|
if ! $new_dc up -d; then
|
|
$new_dc logs --no-color --tail 40 app
|
|
fail "Stack failed to start (app logs above)."
|
|
fi
|
|
|
|
wait_for_log "$new_dc" app '\[entrypoint\] Caches cleared' "composer to re-resolve boboko/core"
|
|
wait_for_log "$new_dc" vite 'ready in' "npm to re-resolve @boboko/core"
|
|
|
|
version=$(grep -A1 '"name": "boboko/core"' composer.lock | grep -o '"version": "[^"]*"' | cut -d'"' -f4)
|
|
echo ">>> Now in $target mode — boboko/core $version"
|