From 6585849459ad70d3f58a49d915b5fba08ae3768f Mon Sep 17 00:00:00 2001 From: Meliox <5264368+Meliox@users.noreply.github.com> Date: Sat, 8 Aug 2026 23:46:46 +0200 Subject: [PATCH] Restructure repo (#251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: restructure src/ into modules/, scripts/, and build/ - src/nag_screen/ and src/node_info/ -> src/modules/ (mods grouped explicitly) - src/Scripts/ -> src/scripts/ (lowercase, consistent) - src/gen-rules.sh -> build/ (build tool separated from source) Update all references: debian/rules, .github/workflows/*, build/gen-rules.sh, src/scripts/test/test-syntax.sh (SRC_DIR now points to src/modules/), src/scripts/test/test-patches.sh, and files.list comments. * refactor: move CI test scripts from src/scripts/test/ to build/test/ Test scripts are not installed — they are CI/dev tooling and belong alongside build/gen-rules.sh. Update workflow references and fix the SRC_DIR path depth in build/test/test-syntax.sh (../ -> ../..). * d --------- Co-authored-by: Meliox --- .github/workflows/release.yml | 4 +- .github/workflows/test-release.yml | 4 +- .github/workflows/validate-mods.yml | 6 +- .github/workflows/weekly-patch-test.yml | 10 +- {src => build}/gen-rules.sh | 16 +- .../test/fetch-proxmox-files.sh | 0 {src/Scripts => build}/test/test-patches.sh | 2 +- build/test/test-syntax.sh | 144 +++++++++++++++ debian/rules | 10 +- src/{ => modules}/nag_screen/files/files.list | 2 +- src/{ => modules}/nag_screen/nag_screen.conf | 0 .../nag_screen/nag_screen.configure.sh | 0 .../patches/01-proxmoxlib-js-nagscreen.patch | 0 .../patches/02-index-html-tpl-mobilenag.patch | 0 .../nag_screen/patches/patches.list | 0 .../nag_screen/patches/post-apply.sh | 0 .../nag_screen/patches/post-revert.sh | 0 src/{ => modules}/nag_screen/readme.md | 0 .../node_info/files/Collector/Amd.pm | 0 .../node_info/files/Collector/Intel.pm | 0 .../node_info/files/Collector/LmSensors.pm | 0 .../node_info/files/Collector/Nvidia.pm | 0 .../node_info/files/Collector/Ups.pm | 0 .../files/Collector/systemInformation.pm | 0 src/{ => modules}/node_info/files/Config.pm | 0 .../node_info/files/ProcessManager.pm | 0 .../node_info/files/PveMod_SensorInfo.pm | 0 .../node_info/files/PveMod_pvemanagerlib.js | 0 src/{ => modules}/node_info/files/Store.pm | 0 src/{ => modules}/node_info/files/Utils.pm | 0 src/{ => modules}/node_info/files/files.list | 2 +- src/{ => modules}/node_info/node_info.conf | 0 .../node_info/node_info.configure.sh | 0 .../patches/01-nodes-pm-sensors.patch | 0 .../patches/02-nodes-pm-GPU-RRD-history.patch | 0 .../patches/03-pvemanager-js-sensors.patch | 0 .../node_info/patches/patches.list | 0 .../node_info/patches/post-apply.sh | 0 src/{ => modules}/node_info/readme.md | 0 src/{Scripts => scripts}/apply-patches.sh | 0 src/{Scripts => scripts}/pve-mod-configure | 0 src/{Scripts => scripts}/revert-patches.sh | 0 src/scripts/test/test-patches.sh | 168 ++++++++++++++++++ src/{Scripts => scripts}/test/test-syntax.sh | 4 +- 44 files changed, 342 insertions(+), 30 deletions(-) rename {src => build}/gen-rules.sh (90%) rename {src/Scripts => build}/test/fetch-proxmox-files.sh (100%) rename {src/Scripts => build}/test/test-patches.sh (99%) create mode 100644 build/test/test-syntax.sh rename src/{ => modules}/nag_screen/files/files.list (85%) rename src/{ => modules}/nag_screen/nag_screen.conf (100%) rename src/{ => modules}/nag_screen/nag_screen.configure.sh (100%) rename src/{ => modules}/nag_screen/patches/01-proxmoxlib-js-nagscreen.patch (100%) rename src/{ => modules}/nag_screen/patches/02-index-html-tpl-mobilenag.patch (100%) rename src/{ => modules}/nag_screen/patches/patches.list (100%) rename src/{ => modules}/nag_screen/patches/post-apply.sh (100%) rename src/{ => modules}/nag_screen/patches/post-revert.sh (100%) rename src/{ => modules}/nag_screen/readme.md (100%) rename src/{ => modules}/node_info/files/Collector/Amd.pm (100%) rename src/{ => modules}/node_info/files/Collector/Intel.pm (100%) rename src/{ => modules}/node_info/files/Collector/LmSensors.pm (100%) rename src/{ => modules}/node_info/files/Collector/Nvidia.pm (100%) rename src/{ => modules}/node_info/files/Collector/Ups.pm (100%) rename src/{ => modules}/node_info/files/Collector/systemInformation.pm (100%) rename src/{ => modules}/node_info/files/Config.pm (100%) rename src/{ => modules}/node_info/files/ProcessManager.pm (100%) rename src/{ => modules}/node_info/files/PveMod_SensorInfo.pm (100%) rename src/{ => modules}/node_info/files/PveMod_pvemanagerlib.js (100%) rename src/{ => modules}/node_info/files/Store.pm (100%) rename src/{ => modules}/node_info/files/Utils.pm (100%) rename src/{ => modules}/node_info/files/files.list (94%) rename src/{ => modules}/node_info/node_info.conf (100%) rename src/{ => modules}/node_info/node_info.configure.sh (100%) rename src/{ => modules}/node_info/patches/01-nodes-pm-sensors.patch (100%) rename src/{ => modules}/node_info/patches/02-nodes-pm-GPU-RRD-history.patch (100%) rename src/{ => modules}/node_info/patches/03-pvemanager-js-sensors.patch (100%) rename src/{ => modules}/node_info/patches/patches.list (100%) rename src/{ => modules}/node_info/patches/post-apply.sh (100%) rename src/{ => modules}/node_info/readme.md (100%) rename src/{Scripts => scripts}/apply-patches.sh (100%) rename src/{Scripts => scripts}/pve-mod-configure (100%) rename src/{Scripts => scripts}/revert-patches.sh (100%) create mode 100644 src/scripts/test/test-patches.sh rename src/{Scripts => scripts}/test/test-syntax.sh (98%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bf8447d..56a130a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,11 +43,11 @@ jobs: run: | perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} } s/(our \$VERSION\s*=\s*'"'"')[^'"'"']*'"'"';/${1}$v'"'"';/ - ' src/node_info/files/Config.pm + ' src/modules/node_info/files/Config.pm - name: Generate dynamic debian rules run: | - bash src/gen-rules.sh >> debian/rules + bash build/gen-rules.sh >> debian/rules - name: Build deb package run: | diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index 060ff3d..36b3e68 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -37,7 +37,7 @@ jobs: run: | BUILD_VERSION="${{ steps.version.outputs.build_version }}" sed -i -E "s/^our \\\$VERSION\\s*=.*/our \\\$VERSION = '${BUILD_VERSION}';/" \ - src/node_info/files/Config.pm + src/modules/node_info/files/Config.pm - name: Set package version in changelog run: | @@ -46,7 +46,7 @@ jobs: - name: Generate dynamic debian rules run: | - bash src/gen-rules.sh >> debian/rules + bash build/gen-rules.sh >> debian/rules - name: Build package run: dpkg-buildpackage -us -uc -b diff --git a/.github/workflows/validate-mods.yml b/.github/workflows/validate-mods.yml index e0e0046..92085ba 100644 --- a/.github/workflows/validate-mods.yml +++ b/.github/workflows/validate-mods.yml @@ -32,13 +32,13 @@ jobs: path: deb - name: Fetch upstream Proxmox files - run: bash src/Scripts/test/fetch-proxmox-files.sh + run: bash build/test/fetch-proxmox-files.sh - name: Install built package run: apt-get install -y ./deb/*.deb - name: Test all mods - run: bash src/Scripts/test/test-patches.sh all + run: bash build/test/test-patches.sh all - name: Validate source syntax - run: bash src/Scripts/test/test-syntax.sh all + run: bash build/test/test-syntax.sh all diff --git a/.github/workflows/weekly-patch-test.yml b/.github/workflows/weekly-patch-test.yml index 167b897..f234589 100644 --- a/.github/workflows/weekly-patch-test.yml +++ b/.github/workflows/weekly-patch-test.yml @@ -58,19 +58,19 @@ jobs: export BUILD_VERSION="${VERSION}-test-${SHORT_SHA}" perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} } s/(our \$VERSION\s*=\s*'"'"')[^'"'"']*'"'"';/$1'"'"'$v'"'"';/ - ' src/node_info/files/Config.pm + ' src/modules/node_info/files/Config.pm - name: Generate dynamic debian rules run: | - bash src/gen-rules.sh >> debian/rules - bash src/gen-rules.sh conffiles >> debian/pve-mod.conffiles + bash build/gen-rules.sh >> debian/rules + bash build/gen-rules.sh conffiles >> debian/pve-mod.conffiles - name: Build package run: dpkg-buildpackage -us -uc -b # ── Test ─────────────────────────────────────────────────────────────── - name: Fetch upstream Proxmox files - run: bash src/Scripts/test/fetch-proxmox-files.sh + run: bash build/test/fetch-proxmox-files.sh - name: Install built package run: sudo apt-get install -y ../pve-mod_*.deb @@ -78,7 +78,7 @@ jobs: - name: Test mod run: | set -o pipefail - sudo bash src/Scripts/test/test-patches.sh "${{ matrix.mod }}" 2>&1 | tee test-output.log + sudo bash build/test/test-patches.sh "${{ matrix.mod }}" 2>&1 | tee test-output.log - name: Report failure as issue if: failure() diff --git a/src/gen-rules.sh b/build/gen-rules.sh similarity index 90% rename from src/gen-rules.sh rename to build/gen-rules.sh index cef6578..efa74ec 100644 --- a/src/gen-rules.sh +++ b/build/gen-rules.sh @@ -1,19 +1,19 @@ #!/usr/bin/env bash -# src/gen-rules.sh +# build/gen-rules.sh # # Generates the per-module portion of the Debian build configuration from each # module's metadata, so adding or changing a module never requires touching # debian/rules by hand. # -# A module is any directory under src/ that contains a files/ and/or patches/ -# subdirectory (so src/Scripts/, which has neither, is ignored). The module's -# directory name is its canonical mod key (matches the [modules] keys in -# pve-mod.conf and the install path usr/lib/pve-mod/patches//). +# A module is any directory under src/modules/ that contains a files/ and/or +# patches/ subdirectory. The module's directory name is its canonical mod key +# (matches the [modules] keys in pve-mod.conf and the install path +# usr/lib/pve-mod/patches//). # # Usage: # gen-rules.sh Emit dpkg install lines (tab-indented, no header). # Append to debian/rules' override_dh_install recipe: -# bash src/gen-rules.sh >> debian/rules +# bash build/gen-rules.sh >> debian/rules # Conffiles under etc/ are detected automatically by # debhelper (compat 13+); no separate conffiles step needed. # @@ -37,7 +37,7 @@ set -euo pipefail # regardless of the caller's working directory. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -SRC_DIR="$REPO_ROOT/src" +SRC_DIR="$REPO_ROOT/src/modules" PKG_DIR="debian/pve-mod" # Print the list of module directory names (basenames), sorted, that contain a @@ -62,7 +62,7 @@ emit_install() { emit_install_rules() { local mod="$1" local mod_dir="$SRC_DIR/$mod" - local rel_mod="src/$mod" + local rel_mod="src/modules/$mod" # 1. Mapped files from files/files.list. local manifest="$mod_dir/files/files.list" diff --git a/src/Scripts/test/fetch-proxmox-files.sh b/build/test/fetch-proxmox-files.sh similarity index 100% rename from src/Scripts/test/fetch-proxmox-files.sh rename to build/test/fetch-proxmox-files.sh diff --git a/src/Scripts/test/test-patches.sh b/build/test/test-patches.sh similarity index 99% rename from src/Scripts/test/test-patches.sh rename to build/test/test-patches.sh index 71a3612..5a68e6f 100644 --- a/src/Scripts/test/test-patches.sh +++ b/build/test/test-patches.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# src/Scripts/test/test-mods.sh +# build/test/test-patches.sh # # Exercises pve-mod's patch engine against the installed Proxmox files. # diff --git a/build/test/test-syntax.sh b/build/test/test-syntax.sh new file mode 100644 index 0000000..8627d85 --- /dev/null +++ b/build/test/test-syntax.sh @@ -0,0 +1,144 @@ +#!/usr/bin/env bash +# build/test/test-syntax.sh +# +# Validates source syntax for all mod files without requiring a running system. +# +# Usage: test-syntax.sh | all +# +# Mods are auto-discovered by scanning for subdirectories of src/ that contain +# a files/ or patches/ directory. No installed package required. +# +# For each target mod it: +# 1. runs perl -c on every .pm file under /files/ +# 2. runs node --check on every .js file under /files/ +# 3. runs bash -n on post-apply.sh and post-revert.sh in /patches/ + +set -u + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SRC_DIR="${PVE_MOD_SRC_DIR:-$(cd "$SCRIPT_DIR/../.." && pwd)/src/modules}" + +info() { echo "[syntax] $*"; } +warn() { echo "[syntax] WARNING: $*" >&2; } + +# List mod names by scanning SRC_DIR for subdirs that contain files/ or patches/. +list_modules() { + local d name + for d in "$SRC_DIR"/*/; do + [[ -d "$d" ]] || continue + name="$(basename "$d")" + if [[ -d "$d/files" || -d "$d/patches" ]]; then + echo "$name" + fi + done | sort +} + +# check_perl_syntax : run perl -c on every .pm under /files/ +check_perl_syntax() { + local mod="$1" + local files_dir="$SRC_DIR/$mod/files" + [[ -d "$files_dir" ]] || return 0 + + local ok=0 f output + while IFS= read -r f; do + output="$(perl -c "$f" 2>&1)" + if [[ $? -ne 0 ]]; then + warn "perl -c FAILED: $f" + echo "$output" + ok=1 + fi + done < <(find "$files_dir" -name "*.pm" -type f | sort) + return $ok +} + +# check_js_syntax : run node --check on every .js under /files/ +check_js_syntax() { + local mod="$1" + local files_dir="$SRC_DIR/$mod/files" + [[ -d "$files_dir" ]] || return 0 + + local ok=0 f output + while IFS= read -r f; do + output="$(node --check "$f" 2>&1)" + if [[ $? -ne 0 ]]; then + warn "node --check FAILED: $f" + echo "$output" + ok=1 + fi + done < <(find "$files_dir" -name "*.js" -type f | sort) + return $ok +} + +# check_bash_syntax : run bash -n on post-apply.sh and post-revert.sh +check_bash_syntax() { + local mod="$1" + local patches_src="$SRC_DIR/$mod/patches" + [[ -d "$patches_src" ]] || return 0 + + local ok=0 script f output + for script in post-apply.sh post-revert.sh; do + f="$patches_src/$script" + [[ -f "$f" ]] || continue + output="$(bash -n "$f" 2>&1)" + if [[ $? -ne 0 ]]; then + warn "bash -n FAILED: $f" + echo "$output" + ok=1 + fi + done + return $ok +} + +# test_syntax_one_mod : run all syntax checks for one mod. +# Returns 0 on pass, 1 on any failure. +test_syntax_one_mod() { + local mod="$1" + echo "::group::Syntax check: $mod" + local ok=0 + + check_perl_syntax "$mod" || ok=1 + check_js_syntax "$mod" || ok=1 + check_bash_syntax "$mod" || ok=1 + + if [[ $ok -eq 0 ]]; then + info "PASS: $mod" + else + warn "FAIL: $mod" + fi + echo "::endgroup::" + return $ok +} + +# ── main ────────────────────────────────────────────────────────────────────── +[[ $# -eq 1 ]] || { echo "Usage: $0 |all" >&2; exit 2; } + +if ! command -v perl >/dev/null 2>&1; then + warn "'perl' command not found; install perl." + exit 1 +fi + +if ! command -v node >/dev/null 2>&1; then + warn "'node' command not found; install nodejs." + exit 1 +fi + +targets=() +if [[ "$1" == "all" ]]; then + mapfile -t targets < <(list_modules) + [[ ${#targets[@]} -gt 0 ]] || { warn "no mods found in $SRC_DIR"; exit 1; } +else + targets=("$1") +fi + +failed=() +for mod in "${targets[@]}"; do + test_syntax_one_mod "$mod" || failed+=("$mod") +done + +echo "" +if [[ ${#failed[@]} -gt 0 ]]; then + warn "Failed mods: ${failed[*]}" + exit 1 +fi +info "All tested mods passed: ${targets[*]}" +exit 0 diff --git a/debian/rules b/debian/rules index 4061449..e212617 100644 --- a/debian/rules +++ b/debian/rules @@ -6,18 +6,18 @@ override_dh_install: # ── Static section ───────────────────────────────────────────────────── # Generic, mod-independent files that never change when mods are added. # Everything mod-specific (module files, patches, per-mod configs) is - # generated and appended below by src/gen-rules.sh at build time and is + # generated and appended below by build/gen-rules.sh at build time and is # NOT committed to the repository. # # Patch helpers (generic, manifest-driven) - install -Dm755 src/Scripts/apply-patches.sh debian/pve-mod/usr/lib/pve-mod/apply-patches.sh - install -Dm755 src/Scripts/revert-patches.sh debian/pve-mod/usr/lib/pve-mod/revert-patches.sh + install -Dm755 src/scripts/apply-patches.sh debian/pve-mod/usr/lib/pve-mod/apply-patches.sh + install -Dm755 src/scripts/revert-patches.sh debian/pve-mod/usr/lib/pve-mod/revert-patches.sh # Configure tool - install -Dm755 src/Scripts/pve-mod-configure debian/pve-mod/usr/sbin/pve-mod-configure + install -Dm755 src/scripts/pve-mod-configure debian/pve-mod/usr/sbin/pve-mod-configure # Main config (conffile for user edits) install -Dm644 src/pve-mod.conf debian/pve-mod/etc/pve-mod/pve-mod.conf # Main config reference copy for upgrade key-diff (not a conffile) install -Dm644 src/pve-mod.conf debian/pve-mod/usr/share/pve-mod/pve-mod.conf.default # ── Dynamic section ──────────────────────────────────────────────────── - # `bash src/gen-rules.sh >> debian/rules` appends per-module install lines + # `bash build/gen-rules.sh >> debian/rules` appends per-module install lines # here during CI, just before dpkg-buildpackage. Do not commit them. diff --git a/src/nag_screen/files/files.list b/src/modules/nag_screen/files/files.list similarity index 85% rename from src/nag_screen/files/files.list rename to src/modules/nag_screen/files/files.list index 0b4bec3..93fcb6f 100644 --- a/src/nag_screen/files/files.list +++ b/src/modules/nag_screen/files/files.list @@ -4,7 +4,7 @@ # source - path relative to this files/ directory # destination - path relative to the package root (no leading slash) # permission - octal mode, optional (defaults to 644) -# Read by src/gen-rules.sh to generate the per-module debian install rules. +# Read by build/gen-rules.sh to generate the per-module debian install rules. # # The nag_screen mod ships no new files - it only patches existing Proxmox # files - so this manifest is intentionally empty. diff --git a/src/nag_screen/nag_screen.conf b/src/modules/nag_screen/nag_screen.conf similarity index 100% rename from src/nag_screen/nag_screen.conf rename to src/modules/nag_screen/nag_screen.conf diff --git a/src/nag_screen/nag_screen.configure.sh b/src/modules/nag_screen/nag_screen.configure.sh similarity index 100% rename from src/nag_screen/nag_screen.configure.sh rename to src/modules/nag_screen/nag_screen.configure.sh diff --git a/src/nag_screen/patches/01-proxmoxlib-js-nagscreen.patch b/src/modules/nag_screen/patches/01-proxmoxlib-js-nagscreen.patch similarity index 100% rename from src/nag_screen/patches/01-proxmoxlib-js-nagscreen.patch rename to src/modules/nag_screen/patches/01-proxmoxlib-js-nagscreen.patch diff --git a/src/nag_screen/patches/02-index-html-tpl-mobilenag.patch b/src/modules/nag_screen/patches/02-index-html-tpl-mobilenag.patch similarity index 100% rename from src/nag_screen/patches/02-index-html-tpl-mobilenag.patch rename to src/modules/nag_screen/patches/02-index-html-tpl-mobilenag.patch diff --git a/src/nag_screen/patches/patches.list b/src/modules/nag_screen/patches/patches.list similarity index 100% rename from src/nag_screen/patches/patches.list rename to src/modules/nag_screen/patches/patches.list diff --git a/src/nag_screen/patches/post-apply.sh b/src/modules/nag_screen/patches/post-apply.sh similarity index 100% rename from src/nag_screen/patches/post-apply.sh rename to src/modules/nag_screen/patches/post-apply.sh diff --git a/src/nag_screen/patches/post-revert.sh b/src/modules/nag_screen/patches/post-revert.sh similarity index 100% rename from src/nag_screen/patches/post-revert.sh rename to src/modules/nag_screen/patches/post-revert.sh diff --git a/src/nag_screen/readme.md b/src/modules/nag_screen/readme.md similarity index 100% rename from src/nag_screen/readme.md rename to src/modules/nag_screen/readme.md diff --git a/src/node_info/files/Collector/Amd.pm b/src/modules/node_info/files/Collector/Amd.pm similarity index 100% rename from src/node_info/files/Collector/Amd.pm rename to src/modules/node_info/files/Collector/Amd.pm diff --git a/src/node_info/files/Collector/Intel.pm b/src/modules/node_info/files/Collector/Intel.pm similarity index 100% rename from src/node_info/files/Collector/Intel.pm rename to src/modules/node_info/files/Collector/Intel.pm diff --git a/src/node_info/files/Collector/LmSensors.pm b/src/modules/node_info/files/Collector/LmSensors.pm similarity index 100% rename from src/node_info/files/Collector/LmSensors.pm rename to src/modules/node_info/files/Collector/LmSensors.pm diff --git a/src/node_info/files/Collector/Nvidia.pm b/src/modules/node_info/files/Collector/Nvidia.pm similarity index 100% rename from src/node_info/files/Collector/Nvidia.pm rename to src/modules/node_info/files/Collector/Nvidia.pm diff --git a/src/node_info/files/Collector/Ups.pm b/src/modules/node_info/files/Collector/Ups.pm similarity index 100% rename from src/node_info/files/Collector/Ups.pm rename to src/modules/node_info/files/Collector/Ups.pm diff --git a/src/node_info/files/Collector/systemInformation.pm b/src/modules/node_info/files/Collector/systemInformation.pm similarity index 100% rename from src/node_info/files/Collector/systemInformation.pm rename to src/modules/node_info/files/Collector/systemInformation.pm diff --git a/src/node_info/files/Config.pm b/src/modules/node_info/files/Config.pm similarity index 100% rename from src/node_info/files/Config.pm rename to src/modules/node_info/files/Config.pm diff --git a/src/node_info/files/ProcessManager.pm b/src/modules/node_info/files/ProcessManager.pm similarity index 100% rename from src/node_info/files/ProcessManager.pm rename to src/modules/node_info/files/ProcessManager.pm diff --git a/src/node_info/files/PveMod_SensorInfo.pm b/src/modules/node_info/files/PveMod_SensorInfo.pm similarity index 100% rename from src/node_info/files/PveMod_SensorInfo.pm rename to src/modules/node_info/files/PveMod_SensorInfo.pm diff --git a/src/node_info/files/PveMod_pvemanagerlib.js b/src/modules/node_info/files/PveMod_pvemanagerlib.js similarity index 100% rename from src/node_info/files/PveMod_pvemanagerlib.js rename to src/modules/node_info/files/PveMod_pvemanagerlib.js diff --git a/src/node_info/files/Store.pm b/src/modules/node_info/files/Store.pm similarity index 100% rename from src/node_info/files/Store.pm rename to src/modules/node_info/files/Store.pm diff --git a/src/node_info/files/Utils.pm b/src/modules/node_info/files/Utils.pm similarity index 100% rename from src/node_info/files/Utils.pm rename to src/modules/node_info/files/Utils.pm diff --git a/src/node_info/files/files.list b/src/modules/node_info/files/files.list similarity index 94% rename from src/node_info/files/files.list rename to src/modules/node_info/files/files.list index 9639ae7..30276dc 100644 --- a/src/node_info/files/files.list +++ b/src/modules/node_info/files/files.list @@ -4,7 +4,7 @@ # source - path relative to this files/ directory # destination - path relative to the package root (no leading slash) # permission - octal mode, optional (defaults to 644) -# Read by src/gen-rules.sh to generate the per-module debian install rules. +# Read by build/gen-rules.sh to generate the per-module debian install rules. # PVE API2 facade PveMod_SensorInfo.pm usr/share/perl5/PVE/API2/PVEMod_SensorInfo.pm diff --git a/src/node_info/node_info.conf b/src/modules/node_info/node_info.conf similarity index 100% rename from src/node_info/node_info.conf rename to src/modules/node_info/node_info.conf diff --git a/src/node_info/node_info.configure.sh b/src/modules/node_info/node_info.configure.sh similarity index 100% rename from src/node_info/node_info.configure.sh rename to src/modules/node_info/node_info.configure.sh diff --git a/src/node_info/patches/01-nodes-pm-sensors.patch b/src/modules/node_info/patches/01-nodes-pm-sensors.patch similarity index 100% rename from src/node_info/patches/01-nodes-pm-sensors.patch rename to src/modules/node_info/patches/01-nodes-pm-sensors.patch diff --git a/src/node_info/patches/02-nodes-pm-GPU-RRD-history.patch b/src/modules/node_info/patches/02-nodes-pm-GPU-RRD-history.patch similarity index 100% rename from src/node_info/patches/02-nodes-pm-GPU-RRD-history.patch rename to src/modules/node_info/patches/02-nodes-pm-GPU-RRD-history.patch diff --git a/src/node_info/patches/03-pvemanager-js-sensors.patch b/src/modules/node_info/patches/03-pvemanager-js-sensors.patch similarity index 100% rename from src/node_info/patches/03-pvemanager-js-sensors.patch rename to src/modules/node_info/patches/03-pvemanager-js-sensors.patch diff --git a/src/node_info/patches/patches.list b/src/modules/node_info/patches/patches.list similarity index 100% rename from src/node_info/patches/patches.list rename to src/modules/node_info/patches/patches.list diff --git a/src/node_info/patches/post-apply.sh b/src/modules/node_info/patches/post-apply.sh similarity index 100% rename from src/node_info/patches/post-apply.sh rename to src/modules/node_info/patches/post-apply.sh diff --git a/src/node_info/readme.md b/src/modules/node_info/readme.md similarity index 100% rename from src/node_info/readme.md rename to src/modules/node_info/readme.md diff --git a/src/Scripts/apply-patches.sh b/src/scripts/apply-patches.sh similarity index 100% rename from src/Scripts/apply-patches.sh rename to src/scripts/apply-patches.sh diff --git a/src/Scripts/pve-mod-configure b/src/scripts/pve-mod-configure similarity index 100% rename from src/Scripts/pve-mod-configure rename to src/scripts/pve-mod-configure diff --git a/src/Scripts/revert-patches.sh b/src/scripts/revert-patches.sh similarity index 100% rename from src/Scripts/revert-patches.sh rename to src/scripts/revert-patches.sh diff --git a/src/scripts/test/test-patches.sh b/src/scripts/test/test-patches.sh new file mode 100644 index 0000000..6e5f1f3 --- /dev/null +++ b/src/scripts/test/test-patches.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# src/scripts/test/test-patches.sh +# +# Exercises pve-mod's patch engine against the installed Proxmox files. +# +# Usage: test-mods.sh | all +# +# Mods are auto-discovered from the [modules] section of the main config, so +# adding a new mod (a new [modules] key plus a patches// directory) is +# picked up automatically - no edits to this script are required. +# +# For each target mod it: +# 1. enables only that mod in the main config +# 2. turns on every conditional flag referenced by the mod's patches.list, +# so all of the mod's patches are exercised (e.g. node_info's gpu_history) +# 3. runs apply-patches.sh and asserts it exits 0 +# 4. runs revert-patches.sh and asserts it reports no unclean reversions +# +# Failure detection relies on the apply exit code: the patch engine performs an +# atomic preflight dry-run and exits non-zero if any mod cannot apply cleanly. +# +# Must run as root (it edits /etc/pve-mod and the patched system files). + +set -u + +MAIN_CONF="${PVE_MOD_MAIN_CONF:-/etc/pve-mod/pve-mod.conf}" +CONFD_DIR="${PVE_MOD_CONFD_DIR:-/etc/pve-mod/conf.d}" +PATCHES_DIR="${PVE_MOD_PATCHES_DIR:-/usr/lib/pve-mod/patches}" +APPLY="${PVE_MOD_APPLY:-/usr/lib/pve-mod/apply-patches.sh}" +REVERT="${PVE_MOD_REVERT:-/usr/lib/pve-mod/revert-patches.sh}" + +info() { echo "[test] $*"; } +warn() { echo "[test] WARNING: $*" >&2; } + +# List the keys of the [modules] section in the main config, one per line. +list_modules() { + [[ -f "$MAIN_CONF" ]] || return 0 + awk -F= ' + /^\[/ { in_sec = ($0 == "[modules]") } + in_sec && /^[^#=]+=/ { + gsub(/^[[:space:]]+|[[:space:]]+$/, "", $1) + print $1 + } + ' "$MAIN_CONF" +} + +# set_conf
: set an existing key within a section. +set_conf() { + local file="$1" section="$2" key="$3" value="$4" + [[ -f "$file" ]] || { warn "config not found: $file"; return 1; } + awk -v sec="[$section]" -v k="$key" -v v="$value" ' + /^\[/ { in_sec = ($0 == sec) } + { + if (in_sec && $0 ~ "^[[:space:]]*"k"[[:space:]]*=") { + print k"="v + } else { + print + } + } + ' "$file" > "$file.tmp" && mv "$file.tmp" "$file" +} + +# Disable every discovered mod in the main config. +disable_all_modules() { + local m + for m in $(list_modules); do + set_conf "$MAIN_CONF" modules "$m" 0 + done +} + +# Turn on every conditional flag a mod's patches.list references, so all of its +# patches become active. Conditions look like: section.key=value +enable_conditions() { + local mod="$1" + local manifest="$PATCHES_DIR/$mod/patches.list" + local mod_conf="$CONFD_DIR/$mod.conf" + [[ -f "$manifest" ]] || return 0 + local line cond local_key want sect ckey + while IFS= read -r line; do + line="${line%%#*}" + line="$(echo "$line" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')" + [[ -z "$line" ]] && continue + # Skip lines without a condition (no whitespace after the patch name). + [[ "$line" == *[[:space:]]* ]] || continue + cond="$(echo "${line#*[[:space:]]}" | sed -E 's/^[[:space:]]+//')" + [[ "$cond" == *=* ]] || continue + local_key="${cond%%=*}" + want="${cond#*=}" + sect="${local_key%%.*}" + ckey="${local_key#*.}" + set_conf "$mod_conf" "$sect" "$ckey" "$want" \ + && info " enabled condition $local_key=$want in $(basename "$mod_conf")" + done < "$manifest" +} + +# Test a single mod end to end. Returns 0 on success, 1 on failure. +test_one_mod() { + local mod="$1" + echo "::group::Testing mod: $mod" + local ok=0 + + if [[ ! -f "$PATCHES_DIR/$mod/patches.list" ]]; then + warn "no patch manifest for mod '$mod' ($PATCHES_DIR/$mod/patches.list)" + echo "::endgroup::" + return 1 + fi + + disable_all_modules + set_conf "$MAIN_CONF" modules "$mod" 1 + enable_conditions "$mod" + + info "Applying patches for '$mod'..." + local apply_log apply_rc + apply_log="$("$APPLY" 2>&1)"; apply_rc=$? + echo "$apply_log" + if [[ $apply_rc -ne 0 ]]; then + warn "apply-patches.sh failed for mod '$mod' (exit $apply_rc)" + ok=1 + fi + + if [[ $ok -eq 0 ]]; then + info "Reverting patches for '$mod'..." + local revert_log + revert_log="$("$REVERT" 2>&1)" + echo "$revert_log" + if echo "$revert_log" | grep -qE "could not be reverted cleanly|reported an error"; then + warn "revert-patches.sh reported an unclean revert for mod '$mod'" + ok=1 + fi + fi + + if [[ $ok -eq 0 ]]; then + info "PASS: $mod" + else + warn "FAIL: $mod" + fi + echo "::endgroup::" + return $ok +} + +# ── main ────────────────────────────────────────────────────────────────────── +[[ $# -eq 1 ]] || { echo "Usage: $0 |all" >&2; exit 2; } + +if ! command -v patch >/dev/null 2>&1; then + warn "'patch' command not found; install the 'patch' package." + exit 1 +fi + +targets=() +if [[ "$1" == "all" ]]; then + mapfile -t targets < <(list_modules) + [[ ${#targets[@]} -gt 0 ]] || { warn "no mods found in [modules] of $MAIN_CONF"; exit 1; } +else + targets=("$1") +fi + +failed=() +for mod in "${targets[@]}"; do + test_one_mod "$mod" || failed+=("$mod") +done + +echo "" +if [[ ${#failed[@]} -gt 0 ]]; then + warn "Failed mods: ${failed[*]}" + exit 1 +fi +info "All tested mods passed: ${targets[*]}" +exit 0 diff --git a/src/Scripts/test/test-syntax.sh b/src/scripts/test/test-syntax.sh similarity index 98% rename from src/Scripts/test/test-syntax.sh rename to src/scripts/test/test-syntax.sh index b52e43e..a274bfe 100644 --- a/src/Scripts/test/test-syntax.sh +++ b/src/scripts/test/test-syntax.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# src/Scripts/test/test-syntax.sh +# src/scripts/test/test-syntax.sh # # Validates source syntax for all mod files without requiring a running system. # @@ -16,7 +16,7 @@ set -u SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SRC_DIR="${PVE_MOD_SRC_DIR:-$(cd "$SCRIPT_DIR/../../.." && pwd)/src}" +SRC_DIR="${PVE_MOD_SRC_DIR:-$(cd "$SCRIPT_DIR/../../.." && pwd)/src/modules}" info() { echo "[syntax] $*"; } warn() { echo "[syntax] WARNING: $*" >&2; }