docs: db-tool: ~ postgres-init and postgres-cleanup
This commit is contained in:
@@ -1,9 +1,46 @@
|
|||||||
#!/bin/dash
|
#!/bin/dash
|
||||||
|
|
||||||
|
# Stop a local PostgreSQL cluster started by postgres-init.
|
||||||
|
#
|
||||||
|
# Public contract:
|
||||||
|
# - Accepts PG_WORKING_DIR directly, or derives it from LOCAL_DIR.
|
||||||
|
# - If no cluster root can be resolved, exits successfully without doing
|
||||||
|
# anything. This keeps cleanup safe in traps and partial-init flows.
|
||||||
|
# - If no postmaster.pid exists, treats the cluster as already stopped.
|
||||||
|
# - NO_TTY=1 redirects pg_ctl output into a temp log file instead of writing to
|
||||||
|
# the current terminal.
|
||||||
|
|
||||||
|
postgres_cleanup_help() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: postgres-cleanup
|
||||||
|
|
||||||
|
Stop a local PostgreSQL cluster if it is running.
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
PG_WORKING_DIR Cluster root directory
|
||||||
|
LOCAL_DIR Fallback root used to derive PG_WORKING_DIR
|
||||||
|
NO_TTY Redirect pg_ctl output to a temp file
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
- Returns success if the cluster directory cannot be resolved.
|
||||||
|
- Returns success if postmaster.pid is already absent.
|
||||||
|
- Ignores pg_ctl stop errors so cleanup remains trap-safe.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
postgres_cleanup_main() {
|
postgres_cleanup_main() {
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help)
|
||||||
|
postgres_cleanup_help
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then return 0; fi
|
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then return 0; fi
|
||||||
: "${PG_WORKING_DIR:=$LOCAL_DIR/focus/postgresql}"
|
: "${PG_WORKING_DIR:=$LOCAL_DIR/focus/postgresql}"
|
||||||
if [ -f "${PG_WORKING_DIR}/data/postmaster.pid" ]; then
|
if [ -f "${PG_WORKING_DIR}/data/postmaster.pid" ]; then
|
||||||
|
# Cleanup is intentionally forgiving so it can be used in traps after
|
||||||
|
# partial startup failures without masking the real error.
|
||||||
if [ "${NO_TTY:-0}" = "1" ]; then
|
if [ "${NO_TTY:-0}" = "1" ]; then
|
||||||
_pg_log="$(mktemp /tmp/postgres-cleanup.XXXXXX.log)"
|
_pg_log="$(mktemp /tmp/postgres-cleanup.XXXXXX.log)"
|
||||||
pg_ctl -D "${PG_WORKING_DIR}/data" -m fast -w stop > "$_pg_log" 2>&1 || :
|
pg_ctl -D "${PG_WORKING_DIR}/data" -m fast -w stop > "$_pg_log" 2>&1 || :
|
||||||
|
|||||||
@@ -1,6 +1,58 @@
|
|||||||
#!/bin/dash
|
#!/bin/dash
|
||||||
|
|
||||||
|
# Initialize or reuse a local PostgreSQL cluster for development workflows.
|
||||||
|
#
|
||||||
|
# Public contract:
|
||||||
|
# - Requires either PG_WORKING_DIR or LOCAL_DIR.
|
||||||
|
# - Produces a ready-to-use database and exports:
|
||||||
|
# POSTGRESQL_HOST, POSTGRESQL_PORT, POSTGRESQL_USER, POSTGRESQL_DATABASE,
|
||||||
|
# PGURL, and also the variable named by PG_URL_VAR.
|
||||||
|
# - Reuses an existing cluster only when PG_REUSE is set and PG_VERSION exists.
|
||||||
|
# - If a reused cluster cannot start, it is reinitialized automatically.
|
||||||
|
#
|
||||||
|
# Important knobs:
|
||||||
|
# - PG_WORKING_DIR: cluster root (defaults to $LOCAL_DIR/focus/postgresql)
|
||||||
|
# - PG_DATABASE: database to create/ensure (default: testdb)
|
||||||
|
# - PG_PORT: socket port (default: 5432)
|
||||||
|
# - PG_URL_VAR: alternate URL variable to export in addition to PGURL
|
||||||
|
# - PG_CONF_FILE: base postgresql.conf to copy on fresh init
|
||||||
|
# - PG_SHARED_PRELOAD_LIBRARIES: preload list; empty string disables pg_cron
|
||||||
|
# - PG_DISABLE_LOGGING=1: disable logging_collector in generated config
|
||||||
|
# - NO_TTY=1: redirect pg_ctl stop/start output into temp log files
|
||||||
|
|
||||||
|
postgres_init_help() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: postgres-init
|
||||||
|
|
||||||
|
Initialize or reuse a local PostgreSQL cluster.
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
PG_WORKING_DIR Cluster root directory
|
||||||
|
LOCAL_DIR Fallback root used to derive PG_WORKING_DIR
|
||||||
|
PG_DATABASE Database name to create/ensure (default: testdb)
|
||||||
|
PG_PORT PostgreSQL port / unix socket port (default: 5432)
|
||||||
|
PG_URL_VAR Extra URL variable to export alongside PGURL
|
||||||
|
PG_CONF_FILE Base postgresql.conf copied on fresh init only
|
||||||
|
PG_SHARED_PRELOAD_LIBRARIES Preload list; empty disables pg_cron preload
|
||||||
|
PG_DISABLE_LOGGING Set to 1 to disable logging_collector
|
||||||
|
PG_REUSE Reuse existing cluster if PG_VERSION exists
|
||||||
|
NO_TTY Redirect pg_ctl output to temp files
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
- Rewrites runtime socket/port/cron settings on every launch.
|
||||||
|
- Creates the target database if missing.
|
||||||
|
- If a reused cluster exists but cannot start, reinitializes it automatically.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
postgres_init_main() {
|
postgres_init_main() {
|
||||||
|
case "${1:-}" in
|
||||||
|
-h|--help)
|
||||||
|
postgres_init_help
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then
|
if [ -z "${PG_WORKING_DIR:-}" ] && [ -z "${LOCAL_DIR:-}" ]; then
|
||||||
printf '%s\n' 'postgres-init: PG_WORKING_DIR or LOCAL_DIR is required' >&2
|
printf '%s\n' 'postgres-init: PG_WORKING_DIR or LOCAL_DIR is required' >&2
|
||||||
return 1
|
return 1
|
||||||
@@ -25,6 +77,9 @@ postgres_init_main() {
|
|||||||
fi
|
fi
|
||||||
mkdir -p "$sockdir" || return 1
|
mkdir -p "$sockdir" || return 1
|
||||||
|
|
||||||
|
# Reuse is optimistic: if a cluster exists on disk, try to start it first.
|
||||||
|
# We only destroy state after a real startup failure proves the cluster is
|
||||||
|
# broken, which keeps long-lived local DBs intact when possible.
|
||||||
if [ "${PG_REUSE+x}" ] && [ -f "$data/PG_VERSION" ]; then PG_REUSE=1; else PG_REUSE=0; fi
|
if [ "${PG_REUSE+x}" ] && [ -f "$data/PG_VERSION" ]; then PG_REUSE=1; else PG_REUSE=0; fi
|
||||||
|
|
||||||
if [ "$PG_REUSE" -eq 0 ]; then
|
if [ "$PG_REUSE" -eq 0 ]; then
|
||||||
@@ -32,6 +87,9 @@ postgres_init_main() {
|
|||||||
mkdir -p "$sockdir" || return 1
|
mkdir -p "$sockdir" || return 1
|
||||||
initdb -D "$data" --no-locale -E UTF8 || return 1
|
initdb -D "$data" --no-locale -E UTF8 || return 1
|
||||||
if [ -n "${PG_CONF_FILE:-}" ]; then
|
if [ -n "${PG_CONF_FILE:-}" ]; then
|
||||||
|
# PG_CONF_FILE replaces the base postgresql.conf on fresh init only. We
|
||||||
|
# still append runtime values later so the helper can relocate sockets,
|
||||||
|
# ports, and cron settings regardless of the custom file contents.
|
||||||
[ -r "$PG_CONF_FILE" ] || { printf '%s\n' "postgres-init: PG_CONF_FILE not readable: $PG_CONF_FILE" >&2; return 1; }
|
[ -r "$PG_CONF_FILE" ] || { printf '%s\n' "postgres-init: PG_CONF_FILE not readable: $PG_CONF_FILE" >&2; return 1; }
|
||||||
cp -f -- "$PG_CONF_FILE" "$data/postgresql.conf" || return 1
|
cp -f -- "$PG_CONF_FILE" "$data/postgresql.conf" || return 1
|
||||||
else
|
else
|
||||||
@@ -51,6 +109,9 @@ postgres_init_main() {
|
|||||||
sed -i "1ilocal all all trust" "$data/pg_hba.conf" || return 1
|
sed -i "1ilocal all all trust" "$data/pg_hba.conf" || return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Rewrite the runtime knobs on every launch. Reused clusters may have been
|
||||||
|
# started from another workspace/session, so we must override stale socket,
|
||||||
|
# port, and pg_cron wiring before attempting startup.
|
||||||
[ -f "$data/postgresql.auto.conf" ] || : > "$data/postgresql.auto.conf"
|
[ -f "$data/postgresql.auto.conf" ] || : > "$data/postgresql.auto.conf"
|
||||||
[ -f "$data/pg_ident.conf" ] || : > "$data/pg_ident.conf"
|
[ -f "$data/pg_ident.conf" ] || : > "$data/pg_ident.conf"
|
||||||
|
|
||||||
@@ -92,6 +153,9 @@ postgres_init_main() {
|
|||||||
|
|
||||||
if [ "$_pg_start_exit" -ne 0 ]; then
|
if [ "$_pg_start_exit" -ne 0 ]; then
|
||||||
if [ "$PG_REUSE" -eq 1 ]; then
|
if [ "$PG_REUSE" -eq 1 ]; then
|
||||||
|
# Self-heal path: the on-disk cluster exists but cannot complete startup
|
||||||
|
# (for example bad WAL / invalid checkpoint). At this point preserving
|
||||||
|
# the broken state is less useful than reinitializing automatically.
|
||||||
printf '%s\n' "postgres-init: reused cluster failed to start; reinitializing $wd" >&2
|
printf '%s\n' "postgres-init: reused cluster failed to start; reinitializing $wd" >&2
|
||||||
PG_REUSE=0
|
PG_REUSE=0
|
||||||
rm -rf "$data" "$sockdir" || return 1
|
rm -rf "$data" "$sockdir" || return 1
|
||||||
@@ -169,6 +233,9 @@ postgres_init_main() {
|
|||||||
psql -h "$sockdir" -p "$PG_PORT" -d "$db" -v ON_ERROR_STOP=1 -c 'select 1;' || return 1
|
psql -h "$sockdir" -p "$PG_PORT" -d "$db" -v ON_ERROR_STOP=1 -c 'select 1;' || return 1
|
||||||
|
|
||||||
export POSTGRESQL_HOST="$sockdir" POSTGRESQL_PORT="$PG_PORT" POSTGRESQL_USER="$user" POSTGRESQL_DATABASE="$db"
|
export POSTGRESQL_HOST="$sockdir" POSTGRESQL_PORT="$PG_PORT" POSTGRESQL_USER="$user" POSTGRESQL_DATABASE="$db"
|
||||||
|
# Export both names for compatibility: some callers consume plain PGURL,
|
||||||
|
# while multi-cluster shells also need a project-specific variable like
|
||||||
|
# WIPE_PGURL or BMSEARCH_PGURL in the same environment.
|
||||||
PGURL="postgresql://${POSTGRESQL_USER}@/${POSTGRESQL_DATABASE}?host=${POSTGRESQL_HOST}&port=${POSTGRESQL_PORT}"
|
PGURL="postgresql://${POSTGRESQL_USER}@/${POSTGRESQL_DATABASE}?host=${POSTGRESQL_HOST}&port=${POSTGRESQL_PORT}"
|
||||||
export PGURL
|
export PGURL
|
||||||
case $PG_URL_VAR in ''|*[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_]* ) printf '%s\n' 'postgres-init: invalid PG_URL_VAR' >&2; return 1 ;; esac
|
case $PG_URL_VAR in ''|*[!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_]* ) printf '%s\n' 'postgres-init: invalid PG_URL_VAR' >&2; return 1 ;; esac
|
||||||
|
|||||||
Reference in New Issue
Block a user