diff --git a/README.md b/README.md index 48a9708..ce90cde 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,14 @@ interactive menu. Update availability is checked in the background and cached; updates are installed only when explicitly selected or requested with `tapm update`. +The required iDSSYS Defaults repository is handled separately: it is +automatically refreshed before launch when its last successful check is more +than four hours old. If the remote is unavailable, the installed copy is used. + +The Utilities menu can safely switch TA-ProxMenu between branches published on +its Git origin. Branch switching is refused when the installed repository has +local changes. + ## Direct actions The menu script also supports these direct actions: diff --git a/defaults.inc b/defaults.inc index 0bd7e01..fe8ca86 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.7.25-16' +VERS='2026.7.25-17' noupdate=' ' diff --git a/proxmenu-scripts.sh b/proxmenu-scripts.sh index 01e4b0c..5c6a496 100755 --- a/proxmenu-scripts.sh +++ b/proxmenu-scripts.sh @@ -761,9 +761,124 @@ SERVICE_RECOVERY_MENU() { done } +SWITCH_SCRIPT_BRANCH() { + local target_branch="$1" + local current_branch + local choice + + current_branch="$(git -C "$FOLDER" branch --show-current 2>/dev/null)" + if [[ "$target_branch" == "$current_branch" ]]; then + echo -e "\n${idsCL[Green]}TA-ProxMenu is already using '${target_branch}'.${idsCL[Default]}" + ENTER2CONTINUE + return + fi + + if [[ -n "$(git -C "$FOLDER" status --porcelain --untracked-files=normal)" ]]; then + echo -e "\n${idsCL[Red]}The installed TA-ProxMenu repository has local changes.${idsCL[Default]}" + echo "Branch switching was refused to protect those files." + echo + git -C "$FOLDER" status --short + ENTER2CONTINUE + return + fi + + echo -en "\n${idsCL[LightCyan]}Switch TA-ProxMenu from '${current_branch}' to '${target_branch}' (y/N)?${idsCL[Default]} " + read -n 1 choice + echo + [[ "$choice" =~ ^[Yy]$ ]] || return + + if ! timeout 30 git -C "$FOLDER" fetch origin \ + "refs/heads/${target_branch}:refs/remotes/origin/${target_branch}"; then + echo -e "${idsCL[Red]}Failed to fetch '${target_branch}' from origin.${idsCL[Default]}" + ENTER2CONTINUE + return + fi + + if git -C "$FOLDER" show-ref --verify --quiet "refs/heads/${target_branch}"; then + git -C "$FOLDER" switch "$target_branch" || { + ENTER2CONTINUE + return + } + else + git -C "$FOLDER" switch --create "$target_branch" \ + --track "origin/${target_branch}" || { + ENTER2CONTINUE + return + } + fi + + if ! git -C "$FOLDER" reset --hard "origin/${target_branch}"; then + echo -e "${idsCL[Red]}Failed to synchronize '${target_branch}' with origin.${idsCL[Default]}" + ENTER2CONTINUE + return + fi + + rm -f "$UPDATE_CACHE_FILE" + echo -e "\n${idsCL[Green]}Now using TA-ProxMenu branch '${target_branch}'.${idsCL[Default]}" + sleep 1 + exec /opt/idssys/ta-proxmenu/run.sh +} + +BRANCH_MANAGEMENT_MENU() { + local -a labels=() + local -a values=() + local branch + local branch_version + local current_branch + + MENU_HEADER + echo + echo -e " ${idsCL[LightCyan]}Refreshing remote branch list...${idsCL[Default]}" + + if ! timeout 30 git -C "$FOLDER" fetch origin \ + '+refs/heads/*:refs/remotes/origin/*' --prune >/dev/null 2>&1; then + echo -e "\n${idsCL[Red]}Could not retrieve branches from origin.${idsCL[Default]}" + ENTER2CONTINUE + return + fi + + current_branch="$(git -C "$FOLDER" branch --show-current 2>/dev/null)" + while IFS= read -r branch; do + [[ -n "$branch" && "$branch" != "HEAD" ]] || continue + branch_version="$( + git -C "$FOLDER" show "refs/remotes/origin/${branch}:defaults.inc" \ + 2>/dev/null | + awk -F"'" '/^VERS=/{ print $2; exit }' + )" + + if [[ "$branch" == "$current_branch" ]]; then + labels+=("${branch} (current, version ${branch_version:-unknown})") + else + labels+=("${branch} (version ${branch_version:-unknown})") + fi + values+=("branch:${branch}") + done < <( + git -C "$FOLDER" for-each-ref \ + --format='%(refname:strip=3)' refs/remotes/origin | + sort -V + ) + + if (( ${#labels[@]} == 0 )); then + echo -e "\n${idsCL[Red]}No remote branches were found.${idsCL[Default]}" + ENTER2CONTINUE + return + fi + + while true; do + SELECT_MENU "Git Branch Management" labels values + case "$MENU_SELECTION" in + branch:*) + SWITCH_SCRIPT_BRANCH "${MENU_SELECTION#branch:}" + ;; + back) return;; + quit) EXIT1; exit 0;; + esac + done +} + UTILITIES_MENU() { local -a labels - local -a values=("install_update" "check_update" "about") + local -a values=("install_update" "check_update" "branches" "about") local choice while true; do @@ -782,7 +897,11 @@ UTILITIES_MENU() { labels=("Update status unavailable") ;; esac - labels+=("Check again now" "Version and installation information") + labels+=( + "Check again now" + "Git branch management" + "Version and installation information" + ) SELECT_MENU "Utilities" labels values case "$MENU_SELECTION" in @@ -802,6 +921,7 @@ UTILITIES_MENU() { ENTER2CONTINUE ;; check_update) FORCE_UPDATE_CHECK;; + branches) BRANCH_MANAGEMENT_MENU;; about) SHOW_ABOUT;; back) return;; quit) EXIT1; exit 0;; diff --git a/run.sh b/run.sh index 7b93878..357543e 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,69 @@ #!/usr/bin/env bash # TA-ProxMenu preloader +DEFAULTS_REPOSITORY='/opt/idssys/defaults' +DEFAULTS_CACHE_DIR='/var/cache/ta-proxmenu' +DEFAULTS_CHECK_FILE="${DEFAULTS_CACHE_DIR}/defaults-last-check" +DEFAULTS_CHECK_SECONDS=14400 + +AUTO_UPDATE_DEFAULTS() { + local checked_at=0 + local local_commit + local now + local remote_commit + + mkdir -p "$DEFAULTS_CACHE_DIR" 2>/dev/null || true + now="$(date +%s)" + [[ -r "$DEFAULTS_CHECK_FILE" ]] && read -r checked_at <"$DEFAULTS_CHECK_FILE" + + if [[ "$checked_at" =~ ^[0-9]+$ ]] && + (( now - checked_at < DEFAULTS_CHECK_SECONDS )); then + return + fi + + exec 9>"${DEFAULTS_CACHE_DIR}/defaults-update.lock" || return + flock -n 9 || return + + # Another process may have completed the update while this one waited. + checked_at=0 + [[ -r "$DEFAULTS_CHECK_FILE" ]] && read -r checked_at <"$DEFAULTS_CHECK_FILE" + if [[ "$checked_at" =~ ^[0-9]+$ ]] && + (( now - checked_at < DEFAULTS_CHECK_SECONDS )); then + return + fi + + if [[ ! -d "${DEFAULTS_REPOSITORY}/.git" ]]; then + echo "iDSSYS Defaults is missing; restoring it from origin..." + mkdir -p /opt/idssys + if ! timeout 60 git clone \ + https://git.scity.us/voltron/iDS-Defaults.git "$DEFAULTS_REPOSITORY"; then + echo "WARNING: Unable to restore iDSSYS Defaults." >&2 + return + fi + else + if ! timeout 20 git -C "$DEFAULTS_REPOSITORY" fetch origin master \ + >/dev/null 2>&1; then + echo "WARNING: Unable to check iDSSYS Defaults; using the installed copy." >&2 + return + fi + + local_commit="$(git -C "$DEFAULTS_REPOSITORY" rev-parse HEAD)" + remote_commit="$(git -C "$DEFAULTS_REPOSITORY" rev-parse origin/master)" + if [[ "$local_commit" != "$remote_commit" ]]; then + echo "Updating required iDSSYS Defaults..." + if ! git -C "$DEFAULTS_REPOSITORY" reset --hard origin/master \ + >/dev/null 2>&1; then + echo "WARNING: Unable to update iDSSYS Defaults; using the installed copy." >&2 + return + fi + fi + fi + + date +%s >"$DEFAULTS_CHECK_FILE" +} + +AUTO_UPDATE_DEFAULTS + [ "${2:-}" != "q" ] && source /opt/idssys/defaults/colors.inc source /opt/idssys/defaults/default.inc source /opt/idssys/ta-proxmenu/defaults.inc