Refactor migration unlock logic and improve setup

Updated the script to improve error handling and logging for SQLite and PostgreSQL migrations. Adjusted the way directories and files are created and linked, ensuring proper permissions and existence checks.
This commit is contained in:
Alexandre
2025-12-28 13:49:29 +01:00
committed by GitHub
parent 27aadbee17
commit 358a77c161

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env bashio
#!/command/with-contenv bashio
# shellcheck shell=bash
# shellcheck disable=SC2155
set -e
set -euo pipefail
bashio::log.warning "Warning - minimum configuration recommended : 2 cpu cores and 4 GB of memory. Otherwise the system will become unresponsive and crash."
@@ -10,108 +9,135 @@ unlock_sqlite_migrations() {
if ! command -v sqlite3 >/dev/null 2>&1; then
bashio::log.warning "sqlite3 not available; skipping SQLite migration lock check."
return
return 0
fi
if ! sqlite3 "$db_path" "SELECT name FROM sqlite_master WHERE type='table' AND name='knex_migrations_lock';" | grep -q "knex_migrations_lock"; then
return
# Only proceed if the DB file exists
if [[ ! -f "$db_path" ]]; then
bashio::log.warning "SQLite DB not found at $db_path; skipping migration unlock."
return 0
fi
# If the lock table doesn't exist yet, nothing to unlock
local has_table
has_table="$(sqlite3 "$db_path" "SELECT 1 FROM sqlite_master WHERE type='table' AND name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)"
[[ "$has_table" == "1" ]] || return 0
# Ensure the lock row exists (Knex expects one row)
# Typical schema: (index INTEGER PRIMARY KEY, is_locked INTEGER)
sqlite3 "$db_path" "
PRAGMA busy_timeout=5000;
INSERT OR IGNORE INTO knex_migrations_lock(\"index\", is_locked) VALUES (1, 0);
" >/dev/null 2>&1 || true
local is_locked
is_locked=$(sqlite3 "$db_path" "SELECT is_locked FROM knex_migrations_lock LIMIT 1;" 2>/dev/null || true)
is_locked="$(sqlite3 "$db_path" "PRAGMA busy_timeout=5000; SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2>/dev/null || true)"
if [[ "$is_locked" == "1" ]]; then
bashio::log.warning "Locked SQLite migration table detected, attempting to unlock."
sqlite3 "$db_path" "UPDATE knex_migrations_lock SET is_locked = 0;" || bashio::log.warning "Failed to clear SQLite migration lock."
sqlite3 "$db_path" "
PRAGMA busy_timeout=5000;
UPDATE knex_migrations_lock SET is_locked = 0 WHERE \"index\"=1 AND is_locked=1;
" >/dev/null 2>&1 || bashio::log.warning "Failed to clear SQLite migration lock."
fi
}
unlock_postgres_migrations() {
if ! command -v psql >/dev/null 2>&1; then
bashio::log.warning "psql not available; skipping PostgreSQL migration lock check."
return
return 0
fi
if [[ -z "${POSTGRES_DATABASE:-}" || -z "${POSTGRES_USER:-}" || -z "${POSTGRES_HOST:-}" ]]; then
bashio::log.warning "PostgreSQL configuration incomplete; skipping migration lock check."
return
return 0
fi
local pg_port="${POSTGRES_PORT:-5432}"
export PGPASSWORD="${POSTGRES_PASSWORD:-}"
# If table doesn't exist, skip
local has_table
has_table="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
"SELECT 1 FROM information_schema.tables WHERE table_name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)"
[[ "$has_table" == "1" ]] || { unset PGPASSWORD; return 0; }
# Ensure row exists
psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
"INSERT INTO knex_migrations_lock(\"index\", is_locked) VALUES (1, 0) ON CONFLICT (\"index\") DO NOTHING;" \
>/dev/null 2>&1 || true
local is_locked
is_locked=$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc "SELECT is_locked FROM knex_migrations_lock LIMIT 1;" 2>/dev/null || true)
is_locked="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
"SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2>/dev/null || true)"
if [[ "$is_locked" == "1" ]]; then
bashio::log.warning "Locked PostgreSQL migration table detected, attempting to unlock."
psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc "UPDATE knex_migrations_lock SET is_locked = 0;" || bashio::log.warning "Failed to clear PostgreSQL migration lock."
psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
"UPDATE knex_migrations_lock SET is_locked = 0 WHERE \"index\"=1 AND is_locked=1;" \
>/dev/null 2>&1 || bashio::log.warning "Failed to clear PostgreSQL migration lock."
fi
unset PGPASSWORD
}
# Check data location
LOCATION=$(bashio::config 'data_location')
if [[ "$LOCATION" = "null" || -z "$LOCATION" ]]; then
# Default location
# -------------------
# Data location
# -------------------
LOCATION="$(bashio::config 'data_location')"
if [[ "$LOCATION" == "null" || -z "$LOCATION" ]]; then
LOCATION="/config/addons_config/joplin"
else
bashio::log.warning "Warning : a custom data location was selected, but the previous folder will NOT be copied. You need to do it manually"
fi
# Create folder
if [ ! -d "$LOCATION" ]; then
echo "Creating $LOCATION"
mkdir -p "$LOCATION"
install -d -m 0755 -o joplin -g joplin "$LOCATION" "$LOCATION/resources"
# Ensure DB exists (touch does not truncate)
if [[ ! -f "$LOCATION/database.sqlite" ]]; then
install -m 0644 -o joplin -g joplin /dev/null "$LOCATION/database.sqlite"
fi
touch "$LOCATION"/database.sqlite
# Link resources into server dir
ln -sfn "$LOCATION/resources" /home/joplin/packages/server/resources
if [ ! -d "$LOCATION"/resources ]; then
mkdir -p "$LOCATION"/resources
fi
ln -s "$LOCATION"/resources /home/joplin/packages/server
chown -R joplin:joplin "$LOCATION"
chmod -R 777 "$LOCATION"
chmod 755 "$LOCATION/database.sqlite"
export SQLITE_DATABASE="$LOCATION/database.sqlite"
# -------------------
# DB selection + unlock
# -------------------
if bashio::config.has_value 'POSTGRES_DATABASE'; then
bashio::log.info "Using postgres"
bashio::config.has_value 'DB_CLIENT' && export DB_CLIENT=$(bashio::config 'DB_CLIENT') && bashio::log.info 'Database client set'
bashio::config.has_value 'POSTGRES_PASSWORD' && export POSTGRES_PASSWORD=$(bashio::config 'POSTGRES_PASSWORD') && bashio::log.info 'Postgrep Password set'
bashio::config.has_value 'POSTGRES_DATABASE' && export POSTGRES_DATABASE=$(bashio::config 'POSTGRES_DATABASE') && bashio::log.info 'Postgrep Database set'
bashio::config.has_value 'POSTGRES_USER' && export POSTGRES_USER=$(bashio::config 'POSTGRES_USER') && bashio::log.info 'Postgrep User set'
bashio::config.has_value 'POSTGRES_PORT' && export POSTGRES_PORT=$(bashio::config 'POSTGRES_PORT') && bashio::log.info 'Postgrep Port set'
bashio::config.has_value 'POSTGRES_HOST' && export POSTGRES_HOST=$(bashio::config 'POSTGRES_HOST') && bashio::log.info 'Postgrep Host set'
bashio::config.has_value 'DB_CLIENT' && export DB_CLIENT="$(bashio::config 'DB_CLIENT')"
bashio::config.has_value 'POSTGRES_PASSWORD' && export POSTGRES_PASSWORD="$(bashio::config 'POSTGRES_PASSWORD')"
bashio::config.has_value 'POSTGRES_DATABASE' && export POSTGRES_DATABASE="$(bashio::config 'POSTGRES_DATABASE')"
bashio::config.has_value 'POSTGRES_USER' && export POSTGRES_USER="$(bashio::config 'POSTGRES_USER')"
bashio::config.has_value 'POSTGRES_PORT' && export POSTGRES_PORT="$(bashio::config 'POSTGRES_PORT')"
bashio::config.has_value 'POSTGRES_HOST' && export POSTGRES_HOST="$(bashio::config 'POSTGRES_HOST')"
unlock_postgres_migrations
else
bashio::log.info "Using sqlite"
unlock_sqlite_migrations "$SQLITE_DATABASE"
fi
##############
# LAUNCH APP #
##############
# -------------------
# App env
# -------------------
bashio::config.has_value 'MAILER_HOST' && export MAILER_HOST="$(bashio::config 'MAILER_HOST')"
bashio::config.has_value 'MAILER_PORT' && export MAILER_PORT="$(bashio::config 'MAILER_PORT')"
bashio::config.has_value 'MAILER_SECURITY' && export MAILER_SECURITY="$(bashio::config 'MAILER_SECURITY')"
bashio::config.has_value 'MAILER_AUTH_USER' && export MAILER_AUTH_USER="$(bashio::config 'MAILER_AUTH_USER')"
bashio::config.has_value 'MAILER_AUTH_PASSWORD' && export MAILER_AUTH_PASSWORD="$(bashio::config 'MAILER_AUTH_PASSWORD')"
bashio::config.has_value 'MAILER_NOREPLY_NAME' && export MAILER_NOREPLY_NAME="$(bashio::config 'MAILER_NOREPLY_NAME')"
bashio::config.has_value 'MAILER_NOREPLY_EMAIL' && export MAILER_NOREPLY_EMAIL="$(bashio::config 'MAILER_NOREPLY_EMAIL')"
bashio::config.has_value 'MAILER_ENABLED' && export MAILER_ENABLED="$(bashio::config 'MAILER_ENABLED')"
# Configure app
bashio::config.has_value 'MAILER_HOST' && export MAILER_HOST=$(bashio::config 'MAILER_HOST') && bashio::log.info 'Mailer Host set'
bashio::config.has_value 'MAILER_PORT' && export MAILER_PORT=$(bashio::config 'MAILER_PORT') && bashio::log.info 'Mailer Port set'
bashio::config.has_value 'MAILER_SECURITY' && export MAILER_SECURITY=$(bashio::config 'MAILER_SECURITY') && bashio::log.info 'Mailer Security set'
bashio::config.has_value 'MAILER_AUTH_USER' && export MAILER_AUTH_USER=$(bashio::config 'MAILER_AUTH_USER') && bashio::log.info 'Mailer User set'
bashio::config.has_value 'MAILER_AUTH_PASSWORD' && export MAILER_AUTH_PASSWORD=$(bashio::config 'MAILER_AUTH_PASSWORD') && bashio::log.info 'Mailer Password set'
bashio::config.has_value 'MAILER_NOREPLY_NAME' && export MAILER_NOREPLY_NAME=$(bashio::config 'MAILER_NOREPLY_NAME') && bashio::log.info 'Mailer Noreply Name set'
bashio::config.has_value 'MAILER_NOREPLY_EMAIL' && export MAILER_NOREPLY_EMAIL=$(bashio::config 'MAILER_NOREPLY_EMAIL') && bashio::log.info 'Mailer Noreply Email set'
bashio::config.has_value 'MAILER_ENABLED' && export MAILER_ENABLED=$(bashio::config 'MAILER_ENABLED') && bashio::log.info 'Mailer Enabled set'
export APP_BASE_URL=$(bashio::config 'APP_BASE_URL')
export APP_BASE_URL="$(bashio::config 'APP_BASE_URL')"
export ALLOWED_HOSTS="*"
bashio::log.info 'Starting Joplin. Initial user is "admin@localhost" with password "admin"'
cd /home/joplin || true
npm --prefix packages/server start
cd /home/joplin || exit 1
exec npm --prefix packages/server start