Add Nix dev shell with local MariaDB and dev orchestration script

This commit is contained in:
kurogeek committed 2026-10-14 10:19:36 +00:00
1 parent 6f8c8d7dfa
commit c8b08fe258
5 files changed
+245

No files matched your search

Executable
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env bash
# Local development orchestration. Run inside `nix develop`.
set -euo pipefail
ROOT="${DEV_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
FRONTEND="$ROOT/think.greaterchiangmai.com"
BACKEND="$ROOT/think-backend.greaterchiangmai.com"
STATE="$ROOT/.dev"
MYSQL_DATA="$STATE/mysql"
MYSQL_SOCK="$STATE/mysql.sock"
MYSQL_PID="$STATE/mysql.pid"
MYSQL_LOG="$STATE/mysql.log"
# Must match DB_* in both apps' .env (only the port differs, to avoid clashing with a system MySQL).
DB_PORT="${DEV_DB_PORT:-3307}"
DB_NAME="greaterc_db2024"
DB_USER="greaterc_dbname2024"
DB_PASS="6vK25y6Pz8LA6Z3y78qH"
FRONTEND_PORT="${DEV_FRONTEND_PORT:-8000}"
BACKEND_PORT="${DEV_BACKEND_PORT:-8001}"
# Process env beats .env in Laravel, so this redirects both apps to the local DB without editing .env.
export DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT="$DB_PORT" DB_DATABASE="$DB_NAME" DB_USERNAME="$DB_USER" DB_PASSWORD="$DB_PASS"
export APP_ENV=local APP_DEBUG=true TEST_LOCAL=true
usage() {
cat <<EOF
Usage: dev <command>
setup composer install both apps + init local MariaDB
db start|stop|status manage local MariaDB (data in .dev/mysql, port $DB_PORT)
db shell mysql client on the local DB
db import <dump.sql> load a production dump (schema lives only in the prod DB)
serve frontend php artisan serve -> http://127.0.0.1:$FRONTEND_PORT
serve backend php artisan serve -> http://127.0.0.1:$BACKEND_PORT
up db + both apps; Ctrl-C stops everything
down stop db and any background servers
artisan <app> ... run artisan for frontend|backend with local env
EOF
}
app_dir() {
case "$1" in
frontend) echo "$FRONTEND" ;;
backend) echo "$BACKEND" ;;
*) echo "unknown app: $1 (frontend|backend)" >&2; exit 2 ;;
esac
}
db_running() {
[ -f "$MYSQL_PID" ] && kill -0 "$(cat "$MYSQL_PID")" 2>/dev/null
}
db_init() {
[ -d "$MYSQL_DATA" ] && return
mkdir -p "$MYSQL_DATA"
mariadb-install-db --datadir="$MYSQL_DATA" --auth-root-authentication-method=normal >"$STATE/install.log" 2>&1
}
db_start() {
mkdir -p "$STATE"
db_init
if db_running; then
echo "db: already running (pid $(cat "$MYSQL_PID"))"
return
fi
mariadbd --datadir="$MYSQL_DATA" --socket="$MYSQL_SOCK" --pid-file="$MYSQL_PID" \
--port="$DB_PORT" --bind-address=127.0.0.1 --skip-name-resolve \
>"$MYSQL_LOG" 2>&1 &
for _ in $(seq 1 50); do
mariadb-admin --socket="$MYSQL_SOCK" -uroot ping >/dev/null 2>&1 && break
sleep 0.2
done
mariadb-admin --socket="$MYSQL_SOCK" -uroot ping >/dev/null 2>&1 || { echo "db: failed to start, see $MYSQL_LOG" >&2; exit 1; }
mariadb --socket="$MYSQL_SOCK" -uroot <<SQL
CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';
CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
GRANT ALL ON \`$DB_NAME\`.* TO '$DB_USER'@'127.0.0.1', '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
SQL
echo "db: listening on 127.0.0.1:$DB_PORT (pid $(cat "$MYSQL_PID"))"
}
db_stop() {
db_running || { echo "db: not running"; return; }
mariadb-admin --socket="$MYSQL_SOCK" -uroot shutdown
echo "db: stopped"
}
db_status() {
if db_running; then
echo "db: running on 127.0.0.1:$DB_PORT (pid $(cat "$MYSQL_PID"))"
mariadb --socket="$MYSQL_SOCK" -uroot "$DB_NAME" -e "SHOW TABLES"
else
echo "db: stopped"
fi
}
db_import() {
local dump="${1:?usage: dev db import <dump.sql>}"
db_running || db_start
mariadb --socket="$MYSQL_SOCK" -uroot "$DB_NAME" <"$dump"
echo "db: imported $dump"
mariadb --socket="$MYSQL_SOCK" -uroot "$DB_NAME" -e "SHOW TABLES"
}
composer_install() {
for app in "$FRONTEND" "$BACKEND"; do
[ -f "$app/.env" ] || { echo "missing $app/.env" >&2; exit 1; }
(cd "$app" && composer install --no-interaction)
done
}
serve() {
local dir port
dir="$(app_dir "$1")"
case "$1" in frontend) port="$FRONTEND_PORT" ;; backend) port="$BACKEND_PORT" ;; esac
cd "$dir" && exec php artisan serve --host=127.0.0.1 --port="$port"
}
up() {
db_start
local pids=()
trap 'kill "${pids[@]}" 2>/dev/null; wait; db_stop' EXIT INT TERM
(cd "$FRONTEND" && php artisan serve --host=127.0.0.1 --port="$FRONTEND_PORT") & pids+=($!)
(cd "$BACKEND" && php artisan serve --host=127.0.0.1 --port="$BACKEND_PORT") & pids+=($!)
echo "frontend: http://127.0.0.1:$FRONTEND_PORT"
echo "backend: http://127.0.0.1:$BACKEND_PORT"
wait
}
down() {
pkill -f "artisan serve --host=127.0.0.1 --port=($FRONTEND_PORT|$BACKEND_PORT)" 2>/dev/null || true
db_stop
}
cmd="${1:-help}"; shift || true
case "$cmd" in
setup) composer_install; db_start ;;
db)
sub="${1:-status}"; shift || true
case "$sub" in
start) db_start ;;
stop) db_stop ;;
status) db_status ;;
shell) db_running || db_start; exec mariadb --socket="$MYSQL_SOCK" -uroot "$DB_NAME" ;;
import) db_import "$@" ;;
*) usage; exit 2 ;;
esac ;;
serve) serve "${1:?usage: dev serve frontend|backend}" ;;
up) up ;;
down) down ;;
artisan) dir="$(app_dir "${1:?usage: dev artisan frontend|backend ...}")"; shift; cd "$dir" && exec php artisan "$@" ;;
help|-h|--help) usage ;;
*) usage; exit 2 ;;
esac