Spaces:
Paused
Paused
PNRxA commited on
Commit Β·
cca484c
1
Parent(s): 617b567
feat: add dev-worktree.sh to set up and run a worktree for local dev
Browse filesMakes a freshly created git worktree runnable in one command:
- Copies api/.env from the main worktree if the current one lacks it
(never overwrites an existing .env).
- --fresh wipes the worktree's api/db and api/cache for a clean slate.
On the main worktree this would delete primary data, so it prompts for
confirmation (or --yes); linked worktrees wipe without asking.
- Installs web deps (npm ci, falling back to npm install) when missing.
- Runs the Rust API (cargo run) and the Vite dev server (npm run dev)
together; Ctrl+C or either process exiting tears down both.
Also supports --release, --setup-only, and --help, and documents the
script in scripts/README.md.
- scripts/README.md +28 -0
- scripts/dev-worktree.sh +246 -0
scripts/README.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
| 2 |
|
| 3 |
Utility scripts for developing, testing, releasing, and seeding OpenPosterDB.
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
## seed.sh
|
| 6 |
|
| 7 |
Warms the OpenPosterDB cache by requesting posters for titles from the IMDB dataset. Entries are processed newest-first, using `endYear` for series (if available) and `startYear` otherwise.
|
|
|
|
| 2 |
|
| 3 |
Utility scripts for developing, testing, releasing, and seeding OpenPosterDB.
|
| 4 |
|
| 5 |
+
## dev-worktree.sh
|
| 6 |
+
|
| 7 |
+
Prepares a freshly created git worktree for local development and runs it. A new
|
| 8 |
+
worktree is missing all the gitignored bits the app needs (`api/.env`, `api/db`,
|
| 9 |
+
`api/cache`, `web/node_modules`); this gets one runnable in a single command.
|
| 10 |
+
|
| 11 |
+
```bash
|
| 12 |
+
./scripts/dev-worktree.sh # set up (if needed) then run API + web
|
| 13 |
+
./scripts/dev-worktree.sh --fresh # also wipe api/db + api/cache first
|
| 14 |
+
./scripts/dev-worktree.sh --release # build/run the API in release mode
|
| 15 |
+
./scripts/dev-worktree.sh --setup-only # copy env + install deps, don't run
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
Run it from inside the worktree you want to set up (any subdirectory is fine).
|
| 19 |
+
|
| 20 |
+
### What it does
|
| 21 |
+
|
| 22 |
+
1. Copies `api/.env` from the **main** worktree if the current worktree lacks one (never overwrites an existing one).
|
| 23 |
+
2. With `--fresh`, deletes the current worktree's `api/db` and `api/cache` for a clean slate before running. In the **main** worktree this would wipe your primary data, so it asks for confirmation first (or pass `--yes`); in a linked worktree it wipes without asking.
|
| 24 |
+
3. Installs web dependencies (`npm ci`, falling back to `npm install`) if `web/node_modules` is missing.
|
| 25 |
+
4. Runs the Rust API (`cargo run` in `api/`, on `http://localhost:3000`) and the Vite dev server (`npm run dev` in `web/`, usually `http://localhost:5173`) together. Press Ctrl+C β or let either process exit β to stop both.
|
| 26 |
+
|
| 27 |
+
> The dev UI is served by Vite over plain HTTP at `http://localhost:5173`. If login
|
| 28 |
+
> appears broken, add `COOKIE_SECURE=false` to `api/.env` (see the main README) β
|
| 29 |
+
> otherwise the browser drops the auth cookie.
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
## seed.sh
|
| 34 |
|
| 35 |
Warms the OpenPosterDB cache by requesting posters for titles from the IMDB dataset. Entries are processed newest-first, using `endYear` for series (if available) and `startYear` otherwise.
|
scripts/dev-worktree.sh
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env bash
|
| 2 |
+
#
|
| 3 |
+
# dev-worktree.sh β prepare and run an OpenPosterDB git worktree for local dev.
|
| 4 |
+
#
|
| 5 |
+
# A freshly created git worktree is missing all the gitignored bits that the
|
| 6 |
+
# app needs (api/.env, api/db, api/cache, web/node_modules). This script makes
|
| 7 |
+
# a new worktree runnable in one command:
|
| 8 |
+
#
|
| 9 |
+
# 1. Copies api/.env from the MAIN worktree if this worktree doesn't have one.
|
| 10 |
+
# 2. Installs web dependencies (npm) if web/node_modules is missing.
|
| 11 |
+
# 3. Runs the Rust API (api/) and the Vite web dev server (web/) together.
|
| 12 |
+
# Ctrl+C β or either process exiting on its own β stops both.
|
| 13 |
+
#
|
| 14 |
+
# Run it from inside the worktree you want to set up (any subdirectory is fine).
|
| 15 |
+
|
| 16 |
+
set -euo pipefail
|
| 17 |
+
|
| 18 |
+
usage() {
|
| 19 |
+
cat <<'EOF'
|
| 20 |
+
dev-worktree.sh β prepare and run an OpenPosterDB worktree for local dev.
|
| 21 |
+
|
| 22 |
+
Usage:
|
| 23 |
+
./scripts/dev-worktree.sh Set up (if needed) then run API + web.
|
| 24 |
+
./scripts/dev-worktree.sh --fresh Also delete this worktree's api/db and
|
| 25 |
+
api/cache first, for a clean slate.
|
| 26 |
+
./scripts/dev-worktree.sh --release Build/run the API in release mode.
|
| 27 |
+
./scripts/dev-worktree.sh --setup-only Copy env + install deps, but don't run.
|
| 28 |
+
./scripts/dev-worktree.sh --yes Skip the --fresh confirmation prompt
|
| 29 |
+
(needed for non-interactive use).
|
| 30 |
+
./scripts/dev-worktree.sh --help Show this help.
|
| 31 |
+
|
| 32 |
+
Note: --fresh in the MAIN worktree deletes your primary db/cache, so it asks
|
| 33 |
+
for confirmation first (or pass --yes). In a linked worktree it wipes without
|
| 34 |
+
asking.
|
| 35 |
+
|
| 36 |
+
What it does:
|
| 37 |
+
1. Copies api/.env from the main worktree if this one lacks it.
|
| 38 |
+
2. Installs web deps (npm) if web/node_modules is missing.
|
| 39 |
+
3. Runs the Rust API (api/) and the Vite dev server (web/) together;
|
| 40 |
+
Ctrl+C β or either process exiting β stops both.
|
| 41 |
+
|
| 42 |
+
Run it from inside the worktree you want to set up.
|
| 43 |
+
EOF
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
# --- Parse arguments --------------------------------------------------------
|
| 47 |
+
FRESH=0
|
| 48 |
+
SETUP_ONLY=0
|
| 49 |
+
ASSUME_YES=0
|
| 50 |
+
CARGO_RELEASE="" # "" = debug build, "--release" = release build
|
| 51 |
+
|
| 52 |
+
while [ $# -gt 0 ]; do
|
| 53 |
+
case "$1" in
|
| 54 |
+
--fresh|--clean) FRESH=1 ;;
|
| 55 |
+
--release) CARGO_RELEASE="--release" ;;
|
| 56 |
+
--setup-only) SETUP_ONLY=1 ;;
|
| 57 |
+
-y|--yes|--force) ASSUME_YES=1 ;;
|
| 58 |
+
-h|--help) usage; exit 0 ;;
|
| 59 |
+
*)
|
| 60 |
+
echo "Unknown option: $1" >&2
|
| 61 |
+
echo "Run '$0 --help' for usage." >&2
|
| 62 |
+
exit 2
|
| 63 |
+
;;
|
| 64 |
+
esac
|
| 65 |
+
shift
|
| 66 |
+
done
|
| 67 |
+
|
| 68 |
+
# --- Locate the current and main worktrees ----------------------------------
|
| 69 |
+
if ! WT="$(git rev-parse --show-toplevel 2>/dev/null)"; then
|
| 70 |
+
echo "Error: not inside a git repository. cd into your worktree first." >&2
|
| 71 |
+
exit 1
|
| 72 |
+
fi
|
| 73 |
+
|
| 74 |
+
# The main worktree is the parent directory of the shared git dir. For a linked
|
| 75 |
+
# worktree, --git-common-dir resolves to <main>/.git; for the main worktree it
|
| 76 |
+
# is the main repo's own .git. Either way, dirname gives the main worktree root.
|
| 77 |
+
# Capture into its own variable (rather than nesting inside dirname) so a git
|
| 78 |
+
# failure β e.g. git older than 2.31, which lacks --path-format β surfaces as a
|
| 79 |
+
# clear error instead of silently degrading MAIN_ROOT to ".".
|
| 80 |
+
if ! COMMON_GIT_DIR="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" || [ -z "$COMMON_GIT_DIR" ]; then
|
| 81 |
+
echo "Error: could not determine the main worktree (git rev-parse failed; needs git >= 2.31)." >&2
|
| 82 |
+
exit 1
|
| 83 |
+
fi
|
| 84 |
+
MAIN_ROOT="$(dirname "$COMMON_GIT_DIR")"
|
| 85 |
+
|
| 86 |
+
if [ ! -d "$WT/api" ] || [ ! -d "$WT/web" ]; then
|
| 87 |
+
echo "Error: $WT does not look like the OpenPosterDB repo (missing api/ or web/)." >&2
|
| 88 |
+
exit 1
|
| 89 |
+
fi
|
| 90 |
+
|
| 91 |
+
echo ">> Worktree : $WT"
|
| 92 |
+
echo ">> Main repo: $MAIN_ROOT"
|
| 93 |
+
|
| 94 |
+
# --- Tooling check ----------------------------------------------------------
|
| 95 |
+
for tool in cargo npm; do
|
| 96 |
+
if ! command -v "$tool" >/dev/null 2>&1; then
|
| 97 |
+
echo "Error: '$tool' not found in PATH." >&2
|
| 98 |
+
exit 1
|
| 99 |
+
fi
|
| 100 |
+
done
|
| 101 |
+
|
| 102 |
+
# --- 1. Copy api/.env if this worktree doesn't have one ---------------------
|
| 103 |
+
SRC_ENV="$MAIN_ROOT/api/.env"
|
| 104 |
+
DST_ENV="$WT/api/.env"
|
| 105 |
+
|
| 106 |
+
if [ -f "$DST_ENV" ]; then
|
| 107 |
+
echo ">> api/.env already present β leaving it untouched."
|
| 108 |
+
elif [ "$WT" = "$MAIN_ROOT" ]; then
|
| 109 |
+
echo "Error: this is the main worktree and it has no api/.env." >&2
|
| 110 |
+
echo " Create it first: (cd \"$WT/api\" && cp .env.example .env) then fill in your keys." >&2
|
| 111 |
+
exit 1
|
| 112 |
+
elif [ ! -d "$MAIN_ROOT/api" ]; then
|
| 113 |
+
# MAIN_ROOT isn't a usable checkout (e.g. a bare-repo-centric layout where
|
| 114 |
+
# the common git dir's parent is not a worktree). Point at THIS worktree.
|
| 115 |
+
echo "Error: couldn't find a main worktree with api/ to copy .env from (looked in $MAIN_ROOT)." >&2
|
| 116 |
+
echo " Create api/.env directly in this worktree:" >&2
|
| 117 |
+
echo " (cd \"$WT/api\" && cp .env.example .env) then fill in your keys." >&2
|
| 118 |
+
exit 1
|
| 119 |
+
elif [ -f "$SRC_ENV" ]; then
|
| 120 |
+
cp "$SRC_ENV" "$DST_ENV"
|
| 121 |
+
echo ">> Copied api/.env from main worktree -> $DST_ENV"
|
| 122 |
+
else
|
| 123 |
+
echo "Error: the main worktree has no api/.env to copy ($SRC_ENV)." >&2
|
| 124 |
+
echo " Create it first: (cd \"$MAIN_ROOT/api\" && cp .env.example .env) then fill in your keys." >&2
|
| 125 |
+
exit 1
|
| 126 |
+
fi
|
| 127 |
+
|
| 128 |
+
# --- 2. Optional fresh start: wipe this worktree's local DB + cache ---------
|
| 129 |
+
if [ "$FRESH" -eq 1 ]; then
|
| 130 |
+
# In the main worktree, --fresh would delete your PRIMARY db/cache, so
|
| 131 |
+
# require confirmation there β an interactive prompt, or --yes for
|
| 132 |
+
# non-interactive use. In a linked worktree the data is throwaway, so wipe
|
| 133 |
+
# it without asking.
|
| 134 |
+
if [ "$WT" = "$MAIN_ROOT" ] && [ "$ASSUME_YES" -ne 1 ]; then
|
| 135 |
+
echo "Warning: --fresh on the main worktree deletes your PRIMARY local data:" >&2
|
| 136 |
+
echo " $WT/api/db" >&2
|
| 137 |
+
echo " $WT/api/cache" >&2
|
| 138 |
+
if [ -t 0 ]; then
|
| 139 |
+
printf "Delete them and start fresh? [y/N] " >&2
|
| 140 |
+
read -r reply || reply=""
|
| 141 |
+
case "$reply" in
|
| 142 |
+
[yY]|[yY][eE][sS]) ;;
|
| 143 |
+
*) echo "Aborted β your data was left untouched." >&2; exit 1 ;;
|
| 144 |
+
esac
|
| 145 |
+
else
|
| 146 |
+
echo "Refusing: not an interactive terminal. Re-run with --yes to confirm." >&2
|
| 147 |
+
exit 1
|
| 148 |
+
fi
|
| 149 |
+
fi
|
| 150 |
+
echo ">> --fresh: wiping this worktree's local data before starting."
|
| 151 |
+
for sub in db cache; do
|
| 152 |
+
target="$WT/api/$sub"
|
| 153 |
+
if [ -e "$target" ]; then
|
| 154 |
+
echo " removing $target"
|
| 155 |
+
rm -rf "$target"
|
| 156 |
+
else
|
| 157 |
+
echo " (nothing at $target)"
|
| 158 |
+
fi
|
| 159 |
+
done
|
| 160 |
+
fi
|
| 161 |
+
|
| 162 |
+
# --- 3. Install web dependencies if missing ---------------------------------
|
| 163 |
+
if [ ! -d "$WT/web/node_modules" ]; then
|
| 164 |
+
echo ">> Installing web dependencies (first run for this worktree)..."
|
| 165 |
+
if ! ( cd "$WT/web" && npm ci ); then
|
| 166 |
+
echo ">> 'npm ci' failed; falling back to 'npm install'..."
|
| 167 |
+
( cd "$WT/web" && npm install )
|
| 168 |
+
fi
|
| 169 |
+
fi
|
| 170 |
+
|
| 171 |
+
if [ "$SETUP_ONLY" -eq 1 ]; then
|
| 172 |
+
echo ">> Setup complete (--setup-only). Run again without it to start the servers."
|
| 173 |
+
exit 0
|
| 174 |
+
fi
|
| 175 |
+
|
| 176 |
+
# --- 4. Run the API and the web dev server together -------------------------
|
| 177 |
+
# Both servers run as background subshells. On shutdown we must tear down the
|
| 178 |
+
# whole tree (cargo + the API binary, npm + vite), not just the subshells.
|
| 179 |
+
#
|
| 180 |
+
# When this script leads its own process group β the normal case when it is run
|
| 181 |
+
# as a foreground command from an interactive shell β `kill 0` signals every
|
| 182 |
+
# process in that group, reaching all descendants cleanly. If instead it was
|
| 183 |
+
# launched without job control (from a wrapper script, a Makefile, an npm
|
| 184 |
+
# script, nohup, or any non-interactive parent) it shares the caller's process
|
| 185 |
+
# group, where `kill 0` would also signal unrelated processes. We detect that
|
| 186 |
+
# case and fall back to killing the two services (and their children) directly.
|
| 187 |
+
SCRIPT_PGID="$(ps -o pgid= -p "$$" 2>/dev/null | tr -d ' ')" || SCRIPT_PGID=""
|
| 188 |
+
API_PID=""
|
| 189 |
+
WEB_PID=""
|
| 190 |
+
|
| 191 |
+
# Terminate a process and all of its descendants, deepest first, so that a
|
| 192 |
+
# grandchild (e.g. vite under npm, or the API binary under cargo) doesn't get
|
| 193 |
+
# reparented and orphaned when its parent dies. Used only in the fallback path.
|
| 194 |
+
kill_tree() {
|
| 195 |
+
local pid="$1" child
|
| 196 |
+
for child in $(pgrep -P "$pid" 2>/dev/null); do
|
| 197 |
+
kill_tree "$child"
|
| 198 |
+
done
|
| 199 |
+
kill -TERM "$pid" 2>/dev/null || true
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
cleanup() {
|
| 203 |
+
trap - INT TERM EXIT
|
| 204 |
+
printf '\n>> Shutting down API + web dev server...\n'
|
| 205 |
+
if [ -n "$SCRIPT_PGID" ] && [ "$SCRIPT_PGID" = "$$" ]; then
|
| 206 |
+
# We lead our own group: one signal reaps both servers and their kids.
|
| 207 |
+
kill 0 2>/dev/null || true
|
| 208 |
+
else
|
| 209 |
+
# Not a group leader β signal only our own service subtrees, so we
|
| 210 |
+
# never hit the caller's process group.
|
| 211 |
+
for p in "$API_PID" "$WEB_PID"; do
|
| 212 |
+
[ -n "$p" ] || continue
|
| 213 |
+
kill_tree "$p"
|
| 214 |
+
done
|
| 215 |
+
fi
|
| 216 |
+
}
|
| 217 |
+
trap cleanup INT TERM EXIT
|
| 218 |
+
|
| 219 |
+
if [ -n "$CARGO_RELEASE" ]; then
|
| 220 |
+
echo ">> API backend: http://localhost:3000 (cargo run --release)"
|
| 221 |
+
else
|
| 222 |
+
echo ">> API backend: http://localhost:3000 (cargo run)"
|
| 223 |
+
fi
|
| 224 |
+
echo ">> Open the app: http://localhost:5173 (Vite dev server β uses the next free port if 5173 is taken)"
|
| 225 |
+
echo ">> Press Ctrl+C to stop both."
|
| 226 |
+
echo
|
| 227 |
+
|
| 228 |
+
# Rust API. The 'if' wrapper keeps a non-zero exit (e.g. a compile error) from
|
| 229 |
+
# tripping 'set -e' before we notify the parent, so a crash tears down both.
|
| 230 |
+
# $$ inside a subshell is the parent script's PID, which is what we want here.
|
| 231 |
+
(
|
| 232 |
+
if cd "$WT/api" && cargo run $CARGO_RELEASE; then ec=0; else ec=$?; fi
|
| 233 |
+
echo ">> [api] cargo run exited (code $ec)"
|
| 234 |
+
kill -TERM $$ 2>/dev/null || true
|
| 235 |
+
) &
|
| 236 |
+
API_PID=$!
|
| 237 |
+
|
| 238 |
+
# Web dev server.
|
| 239 |
+
(
|
| 240 |
+
if cd "$WT/web" && npm run dev; then ec=0; else ec=$?; fi
|
| 241 |
+
echo ">> [web] dev server exited (code $ec)"
|
| 242 |
+
kill -TERM $$ 2>/dev/null || true
|
| 243 |
+
) &
|
| 244 |
+
WEB_PID=$!
|
| 245 |
+
|
| 246 |
+
wait
|