Update beta 1.2.2.2

This commit is contained in:
MacRimi
2026-06-10 19:53:40 +02:00
parent 7ad5508623
commit df95b50f8c
11 changed files with 1355 additions and 960 deletions

View File

@@ -36,7 +36,10 @@ TRANSLATE_CALL_RE = re.compile(
) )
def iter_script_files(scripts_dir: Path) -> Iterable[Path]: def iter_script_files(
scripts_dir: Path, extra_files: Iterable[Path] = ()
) -> Iterable[Path]:
# Walk the main scripts tree.
for path in sorted(scripts_dir.rglob("*")): for path in sorted(scripts_dir.rglob("*")):
if not path.is_file(): if not path.is_file():
continue continue
@@ -45,6 +48,14 @@ def iter_script_files(scripts_dir: Path) -> Iterable[Path]:
if path.suffix not in {".sh", ".func"}: if path.suffix not in {".sh", ".func"}:
continue continue
yield path yield path
# Yield additional files passed explicitly (e.g. the root-level `menu`
# entry point or install_proxmenux*.sh). These live outside scripts/
# but still contain translate "..." calls we want in the cache.
# No extension filter and no utils.sh skip — the caller decided
# they belong, we just check the file actually exists.
for extra in extra_files:
if extra.is_file():
yield extra
def decode_shell_string(raw: str, quote_char: str) -> str: def decode_shell_string(raw: str, quote_char: str) -> str:
@@ -56,9 +67,11 @@ def decode_shell_string(raw: str, quote_char: str) -> str:
return raw.replace(r"\"", '"').replace(r"\\", "\\") return raw.replace(r"\"", '"').replace(r"\\", "\\")
def extract_translate_texts(scripts_dir: Path) -> list[str]: def extract_translate_texts(
scripts_dir: Path, extra_files: Iterable[Path] = ()
) -> list[str]:
found: dict[str, None] = {} found: dict[str, None] = {}
for path in iter_script_files(scripts_dir): for path in iter_script_files(scripts_dir, extra_files):
try: try:
content = path.read_text(encoding="utf-8") content = path.read_text(encoding="utf-8")
except UnicodeDecodeError: except UnicodeDecodeError:
@@ -219,6 +232,19 @@ def build_arg_parser() -> argparse.ArgumentParser:
description="Extract translate calls from scripts/ and build json/cache.json." description="Extract translate calls from scripts/ and build json/cache.json."
) )
parser.add_argument("--scripts-dir", default="scripts", type=Path) parser.add_argument("--scripts-dir", default="scripts", type=Path)
parser.add_argument(
"--extra-file",
action="append",
default=[],
type=Path,
metavar="PATH",
help=(
"Extra individual files to scan for translate calls in addition "
"to --scripts-dir. Useful for the root-level `menu` entry point "
"and install_proxmenux*.sh, which sit outside scripts/. "
"Pass multiple times to add more than one file."
),
)
parser.add_argument( parser.add_argument(
"--output-dir", "--output-dir",
default=Path("lang"), default=Path("lang"),
@@ -292,7 +318,7 @@ def main() -> int:
print("No destination languages selected.", file=sys.stderr) print("No destination languages selected.", file=sys.stderr)
return 1 return 1
texts = extract_translate_texts(scripts_dir) texts = extract_translate_texts(scripts_dir, args.extra_file)
if args.limit > 0: if args.limit > 0:
texts = texts[: args.limit] texts = texts[: args.limit]
existing_by_lang = { existing_by_lang = {

View File

@@ -15,6 +15,9 @@ on:
branches: [develop] branches: [develop]
paths: paths:
- 'scripts/**/*.sh' - 'scripts/**/*.sh'
- 'menu'
- 'install_proxmenux.sh'
- 'install_proxmenux_beta.sh'
- '.github/scripts/build_translation_cache.py' - '.github/scripts/build_translation_cache.py'
- '.github/workflows/build-translation-cache.yml' - '.github/workflows/build-translation-cache.yml'
workflow_dispatch: workflow_dispatch:
@@ -69,8 +72,13 @@ jobs:
if [[ "${{ github.event.inputs.refresh }}" == "true" ]]; then if [[ "${{ github.event.inputs.refresh }}" == "true" ]]; then
REFRESH_FLAG="--refresh" REFRESH_FLAG="--refresh"
fi fi
# Extra files outside scripts/ that also contain translate "..."
# calls. Keep this list in sync with the `paths` trigger above.
python .github/scripts/build_translation_cache.py \ python .github/scripts/build_translation_cache.py \
--scripts-dir scripts \ --scripts-dir scripts \
--extra-file menu \
--extra-file install_proxmenux.sh \
--extra-file install_proxmenux_beta.sh \
--output-dir lang \ --output-dir lang \
--provider googletrans \ --provider googletrans \
$REFRESH_FLAG $REFRESH_FLAG

View File

@@ -35,12 +35,16 @@
INSTALL_DIR="/usr/local/bin" INSTALL_DIR="/usr/local/bin"
BASE_DIR="/usr/local/share/proxmenux" BASE_DIR="/usr/local/share/proxmenux"
CONFIG_FILE="$BASE_DIR/config.json" CONFIG_FILE="$BASE_DIR/config.json"
CACHE_FILE="$BASE_DIR/cache.json"
UTILS_FILE="$BASE_DIR/utils.sh" UTILS_FILE="$BASE_DIR/utils.sh"
LOCAL_VERSION_FILE="$BASE_DIR/version.txt" LOCAL_VERSION_FILE="$BASE_DIR/version.txt"
BETA_VERSION_FILE="$BASE_DIR/beta_version.txt" BETA_VERSION_FILE="$BASE_DIR/beta_version.txt"
MENU_SCRIPT="menu" MENU_SCRIPT="menu"
# Legacy path that existed during the Python+googletrans era. Purged on
# install if present — the current translate flow uses pre-built JSON
# files in lang/ and has no runtime venv dependency.
LEGACY_VENV_PATH="/opt/googletrans-env"
MONITOR_INSTALL_DIR="$BASE_DIR" MONITOR_INSTALL_DIR="$BASE_DIR"
MONITOR_RUNTIME_DIR="$BASE_DIR/monitor-app" MONITOR_RUNTIME_DIR="$BASE_DIR/monitor-app"
MONITOR_SERVICE_FILE="/etc/systemd/system/proxmenux-monitor.service" MONITOR_SERVICE_FILE="/etc/systemd/system/proxmenux-monitor.service"
@@ -304,9 +308,6 @@ cleanup_corrupted_files() {
if [ -f "$CONFIG_FILE" ] && ! jq empty "$CONFIG_FILE" >/dev/null 2>&1; then if [ -f "$CONFIG_FILE" ] && ! jq empty "$CONFIG_FILE" >/dev/null 2>&1; then
rm -f "$CONFIG_FILE" rm -f "$CONFIG_FILE"
fi fi
if [ -f "$CACHE_FILE" ] && ! jq empty "$CACHE_FILE" >/dev/null 2>&1; then
rm -f "$CACHE_FILE"
fi
} }
detect_latest_appimage() { detect_latest_appimage() {
@@ -541,11 +542,70 @@ EOF
} }
# ── Main install ─────────────────────────────────────────── # ── Main install ───────────────────────────────────────────
select_language() {
if [ -f "$CONFIG_FILE" ] && jq empty "$CONFIG_FILE" >/dev/null 2>&1; then
local existing_language=$(jq -r '.language // empty' "$CONFIG_FILE" 2>/dev/null)
if [[ -n "$existing_language" && "$existing_language" != "null" && "$existing_language" != "empty" ]]; then
LANGUAGE="$existing_language"
msg_ok "Using existing language configuration: $LANGUAGE"
return 0
fi
fi
LANGUAGE=$(whiptail --title "Select Language" --menu "Choose a language for the menu:" 20 60 12 \
"en" "English (Recommended)" \
"es" "Spanish" \
"fr" "French" \
"de" "German" \
"it" "Italian" \
"pt" "Portuguese" 3>&1 1>&2 2>&3)
if [ -z "$LANGUAGE" ]; then
msg_error "No language selected. Exiting."
exit 1
fi
mkdir -p "$(dirname "$CONFIG_FILE")"
if [ ! -f "$CONFIG_FILE" ] || ! jq empty "$CONFIG_FILE" >/dev/null 2>&1; then
echo '{}' > "$CONFIG_FILE"
fi
local tmp_file
tmp_file=$(mktemp)
if jq --arg lang "$LANGUAGE" '. + {language: $lang}' "$CONFIG_FILE" > "$tmp_file" 2>/dev/null; then
mv "$tmp_file" "$CONFIG_FILE"
else
echo "{\"language\": \"$LANGUAGE\"}" > "$CONFIG_FILE"
fi
[ -f "$tmp_file" ] && rm -f "$tmp_file"
msg_ok "Language set to: $LANGUAGE"
}
install_beta() { install_beta() {
local total_steps=4 local total_steps=5
local current_step=1 local current_step=1
# ── Step 1: Dependencies ────────────────────────────── # ── Step 1: Language selection ────────────────────────
# Pre-built translations in lang/<locale>.json make every beta install
# multilingual-capable. Ask the operator once up front; subsequent
# update runs reuse the saved choice without re-prompting.
show_progress $current_step $total_steps "Language selection"
select_language
((current_step++))
# Purge the legacy googletrans virtualenv if a previous install left it
# behind. Runtime translation is now a static JSON lookup — the venv
# is dead weight on disk now.
if [[ -d "$LEGACY_VENV_PATH" ]]; then
msg_info "Removing legacy translation virtualenv at $LEGACY_VENV_PATH..."
rm -rf "$LEGACY_VENV_PATH"
msg_ok "Legacy translation virtualenv removed."
fi
# ── Step 2: Dependencies ──────────────────────────────
show_progress $current_step $total_steps "Installing system dependencies" show_progress $current_step $total_steps "Installing system dependencies"
if ! command -v jq > /dev/null 2>&1; then if ! command -v jq > /dev/null 2>&1; then
@@ -593,7 +653,7 @@ install_beta() {
msg_ok "Dependencies installed: jq, dialog, curl, git." msg_ok "Dependencies installed: jq, dialog, curl, git."
# ── Step 2: Clone develop branch ───────────────────── # ── Step 3: Clone develop branch ─────────────────────
((current_step++)) ((current_step++))
show_progress $current_step $total_steps "Cloning ProxMenux develop branch" show_progress $current_step $total_steps "Cloning ProxMenux develop branch"
@@ -612,7 +672,7 @@ install_beta() {
cd "$TEMP_DIR" cd "$TEMP_DIR"
# ── Step 3: Files ───────────────────────────────────── # ── Step 4: Files ─────────────────────────────────────
((current_step++)) ((current_step++))
show_progress $current_step $total_steps "Creating directories and copying files" show_progress $current_step $total_steps "Creating directories and copying files"
@@ -640,11 +700,23 @@ install_beta() {
cp "./install_proxmenux.sh" "$BASE_DIR/install_proxmenux.sh" 2>/dev/null || true cp "./install_proxmenux.sh" "$BASE_DIR/install_proxmenux.sh" 2>/dev/null || true
cp "./install_proxmenux_beta.sh" "$BASE_DIR/install_proxmenux_beta.sh" 2>/dev/null || true cp "./install_proxmenux_beta.sh" "$BASE_DIR/install_proxmenux_beta.sh" 2>/dev/null || true
# Pre-built translation cache. The runtime translate() in utils.sh
# reads $BASE_DIR/lang/<lang>.json — these files ship with the repo
# (one per supported language) so every beta install is multilingual
# without any runtime download or Python dependency. Refresh the
# whole dir on every install so a language that was renamed or
# dropped upstream disappears here too.
if [ -d "./lang" ]; then
rm -rf "$BASE_DIR/lang"
mkdir -p "$BASE_DIR/lang"
cp -r "./lang/"* "$BASE_DIR/lang/" 2>/dev/null || true
fi
# Wipe the scripts tree before copying so any file removed upstream # Wipe the scripts tree before copying so any file removed upstream
# (renamed, consolidated, deprecated) disappears from the user install. # (renamed, consolidated, deprecated) disappears from the user install.
# Only $BASE_DIR/scripts/ is cleared; config.json, cache.json, # Only $BASE_DIR/scripts/ is cleared; config.json, components_status.json,
# components_status.json, version.txt, beta_version.txt, monitor.db, # version.txt, beta_version.txt, monitor.db, smart/, oci/ and the
# smart/, oci/ and the AppImage live outside this path and are preserved. # AppImage live outside this path and are preserved.
rm -rf "$BASE_DIR/scripts" rm -rf "$BASE_DIR/scripts"
mkdir -p "$BASE_DIR/scripts" mkdir -p "$BASE_DIR/scripts"
cp -r "./scripts/"* "$BASE_DIR/scripts/" cp -r "./scripts/"* "$BASE_DIR/scripts/"
@@ -667,7 +739,7 @@ install_beta() {
msg_ok "Files installed. Beta version: ${beta_version}." msg_ok "Files installed. Beta version: ${beta_version}."
# ── Step 4: Monitor ─────────────────────────────────── # ── Step 5: Monitor ───────────────────────────────────
((current_step++)) ((current_step++))
show_progress $current_step $total_steps "Installing ProxMenux Monitor (beta)" show_progress $current_step $total_steps "Installing ProxMenux Monitor (beta)"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -343,7 +343,7 @@ _bk_local() {
# Fallback: gzip (rename archive) # Fallback: gzip (rename archive)
archive="${archive%.zst}" archive="${archive%.zst}"
archive="${archive%.tar}.tar.gz" archive="${archive%.tar}.tar.gz"
if command -v pv >/dev/null 2>&1; then if hb_ensure_pv; then
local stage_bytes local stage_bytes
local pipefail_state local pipefail_state
stage_bytes=$(du -sb "$staging_root" 2>/dev/null | awk '{print $1}') stage_bytes=$(du -sb "$staging_root" 2>/dev/null | awk '{print $1}')
@@ -1115,7 +1115,7 @@ _rs_export_to_file() {
tar_ok=0 tar_ok=0
: > "$log_file" : > "$log_file"
if command -v pv >/dev/null 2>&1; then if hb_ensure_pv; then
# Stream tar through pv so the operator sees a live progress # Stream tar through pv so the operator sees a live progress
# bar instead of staring at a frozen title for minutes. We # bar instead of staring at a frozen title for minutes. We
# mirror the same pattern used by the local backup path # mirror the same pattern used by the local backup path
@@ -1132,10 +1132,11 @@ _rs_export_to_file() {
fi fi
[[ "$pipefail_state" == "off" ]] && set +o pipefail [[ "$pipefail_state" == "off" ]] && set +o pipefail
else else
# pv isn't installedat least tell the operator something # Offline / apt unavailable — silently fall back to a plain
# is happening and hint at the package they can install for # tar so we still produce the archive. No "install pv" message:
# a better experience next time. # if we couldn't install it ourselves, sending the operator off
msg_info "$(translate "Creating export archive (install 'pv' for a live progress bar)...")" # to apt is just shifting our problem onto them.
msg_info "$(translate "Creating export archive...")"
stop_spinner stop_spinner
if tar -czf "$archive" -C "$staging_root" . >>"$log_file" 2>&1; then if tar -czf "$archive" -C "$staging_root" . >>"$log_file" 2>&1; then
tar_ok=1 tar_ok=1

View File

@@ -1889,6 +1889,18 @@ hb_require_cmd() {
command -v "$cmd" >/dev/null 2>&1 command -v "$cmd" >/dev/null 2>&1
} }
# Silent best-effort install of `pv` so callers can pipe tar through it
# for a live progress bar. Returns 0 if pv ends up available, 1 if not.
# Never speaks — pv is purely an UX improvement, asking the operator to
# install it themselves would be backwards (we have apt; they shouldn't).
hb_ensure_pv() {
command -v pv >/dev/null 2>&1 && return 0
if command -v apt-get >/dev/null 2>&1; then
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq pv >/dev/null 2>&1
fi
command -v pv >/dev/null 2>&1
}
# ========================================================== # ==========================================================
# Compatibility check — compares backup metadata against the # Compatibility check — compares backup metadata against the
# current host and surfaces hostname / PVE version / kernel / # current host and surfaces hostname / PVE version / kernel /

View File

@@ -111,13 +111,6 @@ uninstall_proxmenux_monitor() {
} }
detect_installation_type() {
# The Translation/Normal split is gone after the googletrans removal.
# All installs are multilingual via pre-built lang/*.json. Keeping the
# function name + a fixed value so callers don't have to change.
echo "normal"
}
check_monitor_status() { check_monitor_status() {
if systemctl list-unit-files | grep -q "$MONITOR_SERVICE"; then if systemctl list-unit-files | grep -q "$MONITOR_SERVICE"; then
if systemctl is-active --quiet "$MONITOR_SERVICE"; then if systemctl is-active --quiet "$MONITOR_SERVICE"; then
@@ -528,9 +521,6 @@ show_monitor_status() {
# ========================================================== # ==========================================================
show_config_menu() { show_config_menu() {
local install_type
install_type=$(detect_installation_type)
while true; do while true; do
local menu_options=() local menu_options=()
local option_actions=() local option_actions=()
@@ -561,8 +551,8 @@ show_config_menu() {
option_actions[$option_num]="change_release_channel" option_actions[$option_num]="change_release_channel"
((option_num++)) ((option_num++))
# Build menu based on installation type # Translation/Normal split is gone — single menu now. Change Language
if [ "$install_type" = "translation" ]; then # is always available since every install ships the lang/*.json cache.
menu_options+=("$option_num" "$(translate "Change Language")") menu_options+=("$option_num" "$(translate "Change Language")")
option_actions[$option_num]="change_language" option_actions[$option_num]="change_language"
((option_num++)) ((option_num++))
@@ -577,19 +567,6 @@ show_config_menu() {
menu_options+=("$option_num" "$(translate "Return to Main Menu")") menu_options+=("$option_num" "$(translate "Return to Main Menu")")
option_actions[$option_num]="return_main" option_actions[$option_num]="return_main"
else
# Normal version (English only)
menu_options+=("$option_num" "Show Version Information")
option_actions[$option_num]="show_version_info"
((option_num++))
menu_options+=("$option_num" "Uninstall ProxMenux")
option_actions[$option_num]="uninstall_proxmenu"
((option_num++))
menu_options+=("$option_num" "Return to Main Menu")
option_actions[$option_num]="return_main"
fi
# Show menu # Show menu
OPTION=$(dialog --clear --backtitle "ProxMenux Configuration" \ OPTION=$(dialog --clear --backtitle "ProxMenux Configuration" \
@@ -665,8 +642,7 @@ change_language() {
# ========================================================== # ==========================================================
show_version_info() { show_version_info() {
local version info_message install_type release_channel beta_version local version info_message release_channel beta_version
install_type=$(detect_installation_type)
release_channel=$(get_release_channel) release_channel=$(get_release_channel)
if [ -f "$LOCAL_VERSION_FILE" ]; then if [ -f "$LOCAL_VERSION_FILE" ]; then
@@ -683,15 +659,8 @@ show_version_info() {
fi fi
info_message+="\n" info_message+="\n"
# Show installation type # Translation/Normal split is gone — single install path now.
info_message+="$(translate "Installation type:")\n" # Translation support is always present via the lang/*.json cache.
if [ "$install_type" = "translation" ]; then
info_message+="$(translate "Translation Version (Multi-language support)")\n"
else
info_message+="$(translate "Normal Version (English only - Lightweight)")\n"
fi
info_message+="\n"
info_message+="$(translate "Installed components:")\n" info_message+="$(translate "Installed components:")\n"
if [ -f "$CONFIG_FILE" ]; then if [ -f "$CONFIG_FILE" ]; then
while IFS=': ' read -r component value; do while IFS=': ' read -r component value; do
@@ -749,9 +718,6 @@ show_version_info() {
# ========================================================== # ==========================================================
uninstall_proxmenu() { uninstall_proxmenu() {
local install_type
install_type=$(detect_installation_type)
if ! dialog --clear --backtitle "ProxMenux Configuration" \ if ! dialog --clear --backtitle "ProxMenux Configuration" \
--title "Uninstall ProxMenux" \ --title "Uninstall ProxMenux" \
--yesno "\n$(translate "Are you sure you want to uninstall ProxMenux?")" 8 60; then --yesno "\n$(translate "Are you sure you want to uninstall ProxMenux?")" 8 60; then