Files
Qortal-Nextcloud-Integration/scripts/verify-qortal-integration-sync.sh

242 lines
6.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "${script_dir}/.." && pwd)"
source "${script_dir}/lib-compose-project.sh"
compose_file="${repo_root}/docker-compose.devprod.nossl.yml"
env_file="${repo_root}/.env.devprod"
repair=0
usage() {
cat <<'EOF'
Usage: scripts/verify-qortal-integration-sync.sh [options]
Options:
--compose-file <path> Compose file path (default: docker-compose.devprod.nossl.yml)
--env-file <path> Env file path (default: .env.devprod)
--repair Copy source app into mounted custom_apps path and refresh OCC if mismatched
--help Show this help
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--compose-file)
compose_file="$2"
shift 2
;;
--env-file)
env_file="$2"
shift 2
;;
--repair)
repair=1
shift
;;
--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1"
usage
exit 1
;;
esac
done
if [[ ! -f "${env_file}" ]]; then
echo "Missing env file: ${env_file}"
exit 1
fi
export_compose_project_name_from_env "${env_file}" || true
read_kv() {
local key="$1"
local file="$2"
local line
line="$(grep -m1 -E "^${key}=" "${file}" || true)"
if [[ -z "${line}" ]]; then
return 1
fi
echo "${line#*=}"
}
resolve_path_from_env() {
local key="$1"
local default_path="$2"
local value
value="$(read_kv "${key}" "${env_file}" || true)"
value="${value:-${default_path}}"
if [[ "${value}" == /* ]]; then
echo "${value}"
else
echo "${repo_root}/${value}"
fi
}
source_dir="${repo_root}/nextcloud/custom_apps/qortal_integration"
custom_apps_root="$(resolve_path_from_env "NEXTCLOUD_CUSTOM_APPS_PATH" "./nextcloud/custom_apps")"
target_dir="${custom_apps_root}/qortal_integration"
if [[ ! -f "${source_dir}/appinfo/info.xml" ]]; then
echo "Missing source app at ${source_dir}"
exit 1
fi
if [[ ! -d "${target_dir}" ]]; then
echo "Missing mounted app path ${target_dir}"
if [[ "${repair}" -eq 1 ]]; then
mkdir -p "${custom_apps_root}"
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete "${source_dir}/" "${target_dir}/"
else
rm -rf "${target_dir}"
mkdir -p "${target_dir}"
cp -R "${source_dir}/." "${target_dir}/"
fi
echo "Repaired mounted app path by copying source."
else
exit 1
fi
fi
files=(
"appinfo/info.xml"
"js/account.js"
"js/admin.js"
"templates/account.php"
"templates/admin.php"
"lib/Controller/ApiController.php"
)
hash_file() {
local path="$1"
sha256sum "${path}" | awk '{print $1}'
}
container_exec() {
local cmd="$1"
docker compose -f "${compose_file}" --env-file "${env_file}" exec -T app sh -lc "${cmd}" 2>/dev/null
}
container_app_path="$(docker compose -f "${compose_file}" --env-file "${env_file}" exec -T app php occ app:getpath qortal_integration 2>/dev/null | tr -d '\r' || true)"
if [[ -z "${container_app_path}" ]]; then
container_app_path="/var/www/html/custom_apps/qortal_integration"
fi
container_accessible=1
if ! container_exec "test -d '${container_app_path}'"; then
container_accessible=0
fi
container_hash() {
local rel="$1"
container_exec "if [ -f '${container_app_path}/${rel}' ]; then sha256sum '${container_app_path}/${rel}' | awk '{print \$1}'; fi" | tr -d '\r'
}
host_mismatch=0
container_mismatch=0
if [[ "${container_accessible}" -ne 1 ]]; then
container_mismatch=1
echo "Container app path is not accessible: ${container_app_path}"
fi
for rel in "${files[@]}"; do
src="${source_dir}/${rel}"
tgt="${target_dir}/${rel}"
if [[ ! -f "${src}" ]]; then
continue
fi
src_hash="$(hash_file "${src}")"
if [[ -f "${tgt}" ]]; then
tgt_hash="$(hash_file "${tgt}")"
if [[ "${src_hash}" != "${tgt_hash}" ]]; then
host_mismatch=1
echo "Mismatch host source vs mounted: ${rel}"
fi
else
host_mismatch=1
echo "Missing in mounted app path: ${rel}"
fi
if [[ "${container_accessible}" -ne 1 ]]; then
continue
fi
live_hash="$(container_hash "${rel}" || true)"
if [[ -n "${live_hash}" && "${src_hash}" != "${live_hash}" ]]; then
container_mismatch=1
echo "Mismatch source vs container live app: ${rel}"
fi
done
if [[ "${repair}" -eq 1 && "${host_mismatch}" -eq 1 ]]; then
echo "Repair: syncing source -> mounted custom apps path..."
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete "${source_dir}/" "${target_dir}/"
else
rm -rf "${target_dir}"
mkdir -p "${target_dir}"
cp -R "${source_dir}/." "${target_dir}/"
fi
fi
if [[ "${repair}" -eq 1 && ( "${host_mismatch}" -eq 1 || "${container_mismatch}" -eq 1 ) ]]; then
echo "Repair: refreshing app registration + caches..."
docker compose -f "${compose_file}" --env-file "${env_file}" exec -T app php occ app:disable qortal_integration >/dev/null 2>&1 || true
docker compose -f "${compose_file}" --env-file "${env_file}" exec -T app php occ app:enable qortal_integration >/dev/null 2>&1 || true
if [[ -x "${repo_root}/scripts/clear-nextcloud-appdata-assets.sh" ]]; then
"${repo_root}/scripts/clear-nextcloud-appdata-assets.sh" \
--compose-file "${compose_file}" \
--env-file "${env_file}" >/dev/null 2>&1 || true
fi
docker compose -f "${compose_file}" --env-file "${env_file}" exec -T app php occ maintenance:repair >/dev/null 2>&1 || true
host_mismatch=0
container_mismatch=0
container_accessible=1
if ! container_exec "test -d '${container_app_path}'"; then
container_accessible=0
container_mismatch=1
fi
for rel in "${files[@]}"; do
src="${source_dir}/${rel}"
tgt="${target_dir}/${rel}"
[[ -f "${src}" ]] || continue
src_hash="$(hash_file "${src}")"
if [[ ! -f "${tgt}" || "${src_hash}" != "$(hash_file "${tgt}")" ]]; then
host_mismatch=1
fi
if [[ "${container_accessible}" -ne 1 ]]; then
continue
fi
live_hash="$(container_hash "${rel}" || true)"
if [[ -n "${live_hash}" && "${src_hash}" != "${live_hash}" ]]; then
container_mismatch=1
fi
done
fi
if [[ "${host_mismatch}" -eq 0 && "${container_mismatch}" -eq 0 ]]; then
echo "qortal_integration app sync verified:"
echo " source=${source_dir}"
echo " mounted=${target_dir}"
echo " container=${container_app_path}"
exit 0
fi
echo "qortal_integration app sync verification failed."
echo " source=${source_dir}"
echo " mounted=${target_dir}"
echo " container=${container_app_path}"
if [[ "${repair}" -eq 0 ]]; then
echo "Re-run with --repair to auto-fix copy + OCC refresh."
fi
exit 1