242 lines
6.5 KiB
Bash
Executable File
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
|