#!/usr/bin/env bash set -euo pipefail script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd "${script_dir}/.." && pwd)" default_repo_url="https://github.com/Qortal/qortal.git" target_path="${repo_root}/../qortal" repo_url="${default_repo_url}" refresh="0" branch="" GIT_SUDO_PREFIX=() run_git() { "${GIT_SUDO_PREFIX[@]}" git -C "${target_path}" "$@" } fail_git_step() { local step="$1" echo "Failed during Qortal repo step: ${step}" exit 1 } run_git_clone() { "${GIT_SUDO_PREFIX[@]}" git clone "$@" } run_mkdir() { "${GIT_SUDO_PREFIX[@]}" mkdir -p "$@" } enable_git_sudo_if_needed() { local parent_dir="" local need_sudo="0" parent_dir="$(dirname "${target_path}")" if [[ -d "${target_path}/.git" ]]; then if [[ ! -w "${target_path}" || ! -w "${target_path}/.git" ]]; then need_sudo="1" fi elif [[ -e "${target_path}" ]]; then if [[ ! -w "${target_path}" ]]; then need_sudo="1" fi elif [[ ! -w "${parent_dir}" ]]; then need_sudo="1" fi if [[ "${need_sudo}" != "1" ]]; then return 0 fi if ! command -v sudo >/dev/null 2>&1; then echo "Qortal repo path requires elevated filesystem permissions, but sudo is unavailable." exit 1 fi if sudo -n true >/dev/null 2>&1; then GIT_SUDO_PREFIX=(sudo) echo "Using sudo for Qortal repo filesystem operations in ${target_path}" return 0 fi echo "Qortal repo path requires elevated filesystem permissions." echo "You may be prompted for your sudo password." if sudo true >/dev/null 2>&1; then GIT_SUDO_PREFIX=(sudo) echo "Using sudo for Qortal repo filesystem operations in ${target_path}" return 0 fi echo "Unable to obtain sudo for Qortal repo filesystem operations." exit 1 } usage() { cat < Target clone path (default: ../qortal relative to repo root) --repo-url Repo URL to clone (default: https://github.com/Qortal/qortal.git) --branch Branch to clone/refresh (default: origin default branch) --refresh Fetch latest from origin and hard-reset to selected branch -h, --help Show this help USAGE } normalize_repo_url() { local raw="${1:-}" local lower lower="$(echo "${raw}" | tr '[:upper:]' '[:lower:]')" lower="${lower%.git}" if [[ "${lower}" == git@github.com:qortal/qortal ]]; then lower="https://github.com/qortal/qortal" fi echo "${lower}" } is_primary_qortal_repo_url() { local normalized normalized="$(normalize_repo_url "${1:-}")" [[ "${normalized}" == "https://github.com/qortal/qortal" || "${normalized}" == "http://github.com/qortal/qortal" ]] } resolve_path() { local raw="${1:-}" if [[ "${raw}" == /* ]]; then echo "${raw}" else echo "${repo_root}/${raw}" fi } while [[ $# -gt 0 ]]; do case "$1" in --target-path) target_path="${2:-}" shift 2 ;; --target-path=*) target_path="${1#*=}" shift ;; --repo-url) repo_url="${2:-}" shift 2 ;; --repo-url=*) repo_url="${1#*=}" shift ;; --refresh) refresh="1" shift ;; --branch) branch="${2:-}" shift 2 ;; --branch=*) branch="${1#*=}" shift ;; -h|--help) usage exit 0 ;; *) echo "Unknown argument: $1" usage exit 1 ;; esac done target_path="$(resolve_path "${target_path}")" enable_git_sudo_if_needed if [[ -z "${target_path}" ]]; then echo "Target path is required." exit 1 fi if [[ -n "${branch}" ]] && ! git check-ref-format --branch "${branch}" >/dev/null 2>&1; then echo "Invalid branch name: ${branch}" exit 1 fi run_mkdir "$(dirname "${target_path}")" if [[ -e "${target_path}" && ! -d "${target_path}/.git" ]]; then echo "Qortal context exists but is not a git repo: ${target_path}" echo "Move/remove it, then rerun." exit 1 fi if [[ ! -d "${target_path}/.git" ]]; then if [[ -n "${branch}" ]]; then echo "Cloning Qortal Core branch '${branch}' into ${target_path}" run_git_clone --depth 1 --branch "${branch}" --single-branch "${repo_url}" "${target_path}" else echo "Cloning Qortal Core from primary repo into ${target_path}" run_git_clone --depth 1 "${repo_url}" "${target_path}" fi else echo "Using existing Qortal Core repo at ${target_path}" fi if [[ "${refresh}" != "1" ]]; then exit 0 fi current_origin="$(run_git remote get-url origin 2>/dev/null || true)" if ! is_primary_qortal_repo_url "${current_origin}"; then echo "Updating Qortal origin remote to primary repo for refresh (was: ${current_origin:-})" if run_git remote get-url origin >/dev/null 2>&1; then run_git remote set-url origin "${repo_url}" else run_git remote add origin "${repo_url}" fi fi target_branch="${branch:-}" echo "Refreshing Qortal Core checkout from primary upstream..." if [[ -n "${target_branch}" ]]; then echo "Fetching branch origin/${target_branch}..." if ! run_git fetch --depth 1 origin "refs/heads/${target_branch}:refs/remotes/origin/${target_branch}"; then echo "Origin branch not found: ${target_branch}" exit 1 fi else echo "Fetching origin default branch..." run_git fetch --depth 1 origin default_branch="$(run_git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##' || true)" if [[ -z "${default_branch}" ]]; then default_branch="$(run_git remote show origin 2>/dev/null | sed -n '/HEAD branch/s/.*: //p' | head -n1 || true)" fi if [[ -z "${default_branch}" ]]; then if run_git show-ref --verify --quiet refs/remotes/origin/main; then default_branch="main" elif run_git show-ref --verify --quiet refs/remotes/origin/master; then default_branch="master" else echo "Could not determine default branch from origin for ${target_path}" exit 1 fi fi target_branch="${default_branch}" fi if ! run_git show-ref --verify --quiet "refs/remotes/origin/${target_branch}"; then echo "Origin branch not found: ${target_branch}" exit 1 fi echo "Checking out local branch ${target_branch} from origin/${target_branch}..." run_git checkout -B "${target_branch}" "origin/${target_branch}" || fail_git_step "checkout ${target_branch}" echo "Resetting working tree to origin/${target_branch}..." run_git reset --hard "origin/${target_branch}" || fail_git_step "reset --hard origin/${target_branch}" echo "Cleaning untracked files in ${target_path}..." run_git clean -fd || fail_git_step "clean -fd" echo "Qortal Core refreshed to origin/${target_branch}."