#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "${script_dir}/.." && pwd)" env_file="${repo_root}/.env.devprod" custom_apps_path="./nextcloud/custom_apps_appstore" refresh_qortal_copy="1" additional_apps=( "custom_pwa" "chd_admin" "qortal_files_bridge" "qortal_talk_bridge" "nuqloud_scrum" ) usage() { cat < Env file to modify (default: .env.devprod) --custom-apps-path Host path for NEXTCLOUD_CUSTOM_APPS_PATH (default: ./nextcloud/custom_apps_appstore) --no-refresh-qortal Do not overwrite existing qortal_integration copy -h, --help Show this help USAGE } read_kv() { local key="$1" local line line="$(grep -m1 -E "^${key}=" "${env_file}" || true)" if [[ -z "${line}" ]]; then return 1 fi echo "${line#*=}" } set_kv() { local key="$1" local value="$2" local esc esc="${value//\\/\\\\}" esc="${esc//&/\\&}" esc="${esc//|/\\|}" if grep -q -E "^${key}=" "${env_file}"; then sed -i -E "s|^${key}=.*|${key}=${esc}|" "${env_file}" else echo "${key}=${value}" >> "${env_file}" fi } resolve_path() { local raw_path="$1" if [[ "${raw_path}" == /* ]]; then echo "${raw_path}" else echo "${repo_root}/${raw_path}" fi } copy_app_dir() { local app_name="$1" local dst_root="$2" local src="${repo_root}/nextcloud/custom_apps/${app_name}" local dst="${dst_root}/${app_name}" if [[ ! -d "${src}" || ! -f "${src}/appinfo/info.xml" ]]; then if [[ "${app_name}" == "qortal_integration" ]]; then echo "Missing source app directory: ${src}" exit 1 fi echo "Skipping optional app copy: ${app_name} (not found)" return fi if [[ "${app_name}" == "qortal_integration" && "${refresh_qortal_copy}" != "1" && -d "${dst}" ]]; then echo "Keeping existing qortal_integration copy at ${dst}" return fi echo "Copying ${app_name} into isolated custom_apps path..." mkdir -p "${dst_root}" if command -v rsync >/dev/null 2>&1; then rsync -a --delete "${src}/" "${dst}/" else rm -rf "${dst}" mkdir -p "${dst}" cp -R "${src}/." "${dst}/" fi } while [[ $# -gt 0 ]]; do case "$1" in --env-file) env_file="${2:-}" shift 2 ;; --env-file=*) env_file="${1#*=}" shift ;; --custom-apps-path) custom_apps_path="${2:-}" shift 2 ;; --custom-apps-path=*) custom_apps_path="${1#*=}" shift ;; --no-refresh-qortal) refresh_qortal_copy="0" shift ;; -h|--help) usage exit 0 ;; *) echo "Unknown option: $1" usage exit 1 ;; esac done if [[ "${env_file}" != /* ]]; then env_file="${repo_root}/${env_file}" fi if [[ ! -f "${env_file}" ]]; then echo "Missing env file: ${env_file}" exit 1 fi set_kv "NEXTCLOUD_CUSTOM_APPS_PATH" "${custom_apps_path}" custom_apps_abs="$(resolve_path "${custom_apps_path}")" mkdir -p "${custom_apps_abs}" copy_app_dir "qortal_integration" "${custom_apps_abs}" for app_name in "${additional_apps[@]}"; do copy_app_dir "${app_name}" "${custom_apps_abs}" done if [[ -x "${repo_root}/scripts/ensure-user-oidc-app.sh" ]]; then NEXTCLOUD_CUSTOM_APPS_PATH="${custom_apps_abs}" "${repo_root}/scripts/ensure-user-oidc-app.sh" fi echo echo "App-store mimic preparation complete." echo "Env file: ${env_file}" echo "NEXTCLOUD_CUSTOM_APPS_PATH=${custom_apps_path}" echo "Resolved custom_apps path: ${custom_apps_abs}" echo echo "Next steps:" echo "1) Start or recreate your stack (example):" echo " ./scripts/install-production-docker.sh --mode nossl --with-external-auth --env-file ${env_file}" echo " or" echo " ./recreate-devprod.sh --nossl --extauth" echo "2) Validate mounted path in app container:" echo " docker compose -f docker-compose.devprod.nossl.yml --env-file ${env_file} exec -T app sh -lc 'ls -1 /var/www/html/custom_apps'" echo "3) Confirm app list:" echo " docker compose -f docker-compose.devprod.nossl.yml --env-file ${env_file} exec -T app php occ app:list | rg -n \"qortal_integration|custom_pwa|chd_admin|qortal_files_bridge|qortal_talk_bridge|nuqloud_scrum|user_oidc\""