Restructure repo (#251)
* 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 <na>
This commit is contained in:
parent
3db6a010df
commit
6585849459
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -43,11 +43,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} }
|
perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} }
|
||||||
s/(our \$VERSION\s*=\s*'"'"')[^'"'"']*'"'"';/${1}$v'"'"';/
|
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
|
- name: Generate dynamic debian rules
|
||||||
run: |
|
run: |
|
||||||
bash src/gen-rules.sh >> debian/rules
|
bash build/gen-rules.sh >> debian/rules
|
||||||
|
|
||||||
- name: Build deb package
|
- name: Build deb package
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.github/workflows/test-release.yml
vendored
4
.github/workflows/test-release.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
BUILD_VERSION="${{ steps.version.outputs.build_version }}"
|
BUILD_VERSION="${{ steps.version.outputs.build_version }}"
|
||||||
sed -i -E "s/^our \\\$VERSION\\s*=.*/our \\\$VERSION = '${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
|
- name: Set package version in changelog
|
||||||
run: |
|
run: |
|
||||||
@ -46,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate dynamic debian rules
|
- name: Generate dynamic debian rules
|
||||||
run: |
|
run: |
|
||||||
bash src/gen-rules.sh >> debian/rules
|
bash build/gen-rules.sh >> debian/rules
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: dpkg-buildpackage -us -uc -b
|
run: dpkg-buildpackage -us -uc -b
|
||||||
|
|||||||
6
.github/workflows/validate-mods.yml
vendored
6
.github/workflows/validate-mods.yml
vendored
@ -32,13 +32,13 @@ jobs:
|
|||||||
path: deb
|
path: deb
|
||||||
|
|
||||||
- name: Fetch upstream Proxmox files
|
- 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
|
- name: Install built package
|
||||||
run: apt-get install -y ./deb/*.deb
|
run: apt-get install -y ./deb/*.deb
|
||||||
|
|
||||||
- name: Test all mods
|
- 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
|
- name: Validate source syntax
|
||||||
run: bash src/Scripts/test/test-syntax.sh all
|
run: bash build/test/test-syntax.sh all
|
||||||
|
|||||||
10
.github/workflows/weekly-patch-test.yml
vendored
10
.github/workflows/weekly-patch-test.yml
vendored
@ -58,19 +58,19 @@ jobs:
|
|||||||
export BUILD_VERSION="${VERSION}-test-${SHORT_SHA}"
|
export BUILD_VERSION="${VERSION}-test-${SHORT_SHA}"
|
||||||
perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} }
|
perl -i -pe 'BEGIN { $v = $ENV{BUILD_VERSION} }
|
||||||
s/(our \$VERSION\s*=\s*'"'"')[^'"'"']*'"'"';/$1'"'"'$v'"'"';/
|
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
|
- name: Generate dynamic debian rules
|
||||||
run: |
|
run: |
|
||||||
bash src/gen-rules.sh >> debian/rules
|
bash build/gen-rules.sh >> debian/rules
|
||||||
bash src/gen-rules.sh conffiles >> debian/pve-mod.conffiles
|
bash build/gen-rules.sh conffiles >> debian/pve-mod.conffiles
|
||||||
|
|
||||||
- name: Build package
|
- name: Build package
|
||||||
run: dpkg-buildpackage -us -uc -b
|
run: dpkg-buildpackage -us -uc -b
|
||||||
|
|
||||||
# ── Test ───────────────────────────────────────────────────────────────
|
# ── Test ───────────────────────────────────────────────────────────────
|
||||||
- name: Fetch upstream Proxmox files
|
- 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
|
- name: Install built package
|
||||||
run: sudo apt-get install -y ../pve-mod_*.deb
|
run: sudo apt-get install -y ../pve-mod_*.deb
|
||||||
@ -78,7 +78,7 @@ jobs:
|
|||||||
- name: Test mod
|
- name: Test mod
|
||||||
run: |
|
run: |
|
||||||
set -o pipefail
|
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
|
- name: Report failure as issue
|
||||||
if: failure()
|
if: failure()
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# src/gen-rules.sh
|
# build/gen-rules.sh
|
||||||
#
|
#
|
||||||
# Generates the per-module portion of the Debian build configuration from each
|
# Generates the per-module portion of the Debian build configuration from each
|
||||||
# module's metadata, so adding or changing a module never requires touching
|
# module's metadata, so adding or changing a module never requires touching
|
||||||
# debian/rules by hand.
|
# debian/rules by hand.
|
||||||
#
|
#
|
||||||
# A module is any directory under src/ that contains a files/ and/or patches/
|
# A module is any directory under src/modules/ that contains a files/ and/or
|
||||||
# subdirectory (so src/Scripts/, which has neither, is ignored). The module's
|
# patches/ subdirectory. The module's directory name is its canonical mod key
|
||||||
# directory name is its canonical mod key (matches the [modules] keys in
|
# (matches the [modules] keys in pve-mod.conf and the install path
|
||||||
# pve-mod.conf and the install path usr/lib/pve-mod/patches/<mod>/).
|
# usr/lib/pve-mod/patches/<mod>/).
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# gen-rules.sh Emit dpkg install lines (tab-indented, no header).
|
# gen-rules.sh Emit dpkg install lines (tab-indented, no header).
|
||||||
# Append to debian/rules' override_dh_install recipe:
|
# 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
|
# Conffiles under etc/ are detected automatically by
|
||||||
# debhelper (compat 13+); no separate conffiles step needed.
|
# debhelper (compat 13+); no separate conffiles step needed.
|
||||||
#
|
#
|
||||||
@ -37,7 +37,7 @@ set -euo pipefail
|
|||||||
# regardless of the caller's working directory.
|
# regardless of the caller's working directory.
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
SRC_DIR="$REPO_ROOT/src"
|
SRC_DIR="$REPO_ROOT/src/modules"
|
||||||
PKG_DIR="debian/pve-mod"
|
PKG_DIR="debian/pve-mod"
|
||||||
|
|
||||||
# Print the list of module directory names (basenames), sorted, that contain a
|
# Print the list of module directory names (basenames), sorted, that contain a
|
||||||
@ -62,7 +62,7 @@ emit_install() {
|
|||||||
emit_install_rules() {
|
emit_install_rules() {
|
||||||
local mod="$1"
|
local mod="$1"
|
||||||
local mod_dir="$SRC_DIR/$mod"
|
local mod_dir="$SRC_DIR/$mod"
|
||||||
local rel_mod="src/$mod"
|
local rel_mod="src/modules/$mod"
|
||||||
|
|
||||||
# 1. Mapped files from files/files.list.
|
# 1. Mapped files from files/files.list.
|
||||||
local manifest="$mod_dir/files/files.list"
|
local manifest="$mod_dir/files/files.list"
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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.
|
# Exercises pve-mod's patch engine against the installed Proxmox files.
|
||||||
#
|
#
|
||||||
144
build/test/test-syntax.sh
Normal file
144
build/test/test-syntax.sh
Normal file
@ -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 <mod> | 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 <mod>/files/
|
||||||
|
# 2. runs node --check on every .js file under <mod>/files/
|
||||||
|
# 3. runs bash -n on post-apply.sh and post-revert.sh in <mod>/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 <mod>: run perl -c on every .pm under <mod>/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 <mod>: run node --check on every .js under <mod>/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 <mod>: 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 <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 <mod>|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
|
||||||
10
debian/rules
vendored
10
debian/rules
vendored
@ -6,18 +6,18 @@ override_dh_install:
|
|||||||
# ── Static section ─────────────────────────────────────────────────────
|
# ── Static section ─────────────────────────────────────────────────────
|
||||||
# Generic, mod-independent files that never change when mods are added.
|
# Generic, mod-independent files that never change when mods are added.
|
||||||
# Everything mod-specific (module files, patches, per-mod configs) is
|
# 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.
|
# NOT committed to the repository.
|
||||||
#
|
#
|
||||||
# Patch helpers (generic, manifest-driven)
|
# 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/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/revert-patches.sh debian/pve-mod/usr/lib/pve-mod/revert-patches.sh
|
||||||
# Configure tool
|
# 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)
|
# Main config (conffile for user edits)
|
||||||
install -Dm644 src/pve-mod.conf debian/pve-mod/etc/pve-mod/pve-mod.conf
|
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)
|
# 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
|
install -Dm644 src/pve-mod.conf debian/pve-mod/usr/share/pve-mod/pve-mod.conf.default
|
||||||
# ── Dynamic section ────────────────────────────────────────────────────
|
# ── 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.
|
# here during CI, just before dpkg-buildpackage. Do not commit them.
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
# source - path relative to this files/ directory
|
# source - path relative to this files/ directory
|
||||||
# destination - path relative to the package root (no leading slash)
|
# destination - path relative to the package root (no leading slash)
|
||||||
# permission - octal mode, optional (defaults to 644)
|
# 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
|
# The nag_screen mod ships no new files - it only patches existing Proxmox
|
||||||
# files - so this manifest is intentionally empty.
|
# files - so this manifest is intentionally empty.
|
||||||
@ -4,7 +4,7 @@
|
|||||||
# source - path relative to this files/ directory
|
# source - path relative to this files/ directory
|
||||||
# destination - path relative to the package root (no leading slash)
|
# destination - path relative to the package root (no leading slash)
|
||||||
# permission - octal mode, optional (defaults to 644)
|
# 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
|
# PVE API2 facade
|
||||||
PveMod_SensorInfo.pm usr/share/perl5/PVE/API2/PVEMod_SensorInfo.pm
|
PveMod_SensorInfo.pm usr/share/perl5/PVE/API2/PVEMod_SensorInfo.pm
|
||||||
168
src/scripts/test/test-patches.sh
Normal file
168
src/scripts/test/test-patches.sh
Normal file
@ -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 <mod> | 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/<mod>/ 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 <file> <section> <key> <value>: 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: <patch-file> 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 <mod>|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
|
||||||
@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/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.
|
# Validates source syntax for all mod files without requiring a running system.
|
||||||
#
|
#
|
||||||
@ -16,7 +16,7 @@
|
|||||||
set -u
|
set -u
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
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] $*"; }
|
info() { echo "[syntax] $*"; }
|
||||||
warn() { echo "[syntax] WARNING: $*" >&2; }
|
warn() { echo "[syntax] WARNING: $*" >&2; }
|
||||||
Loading…
Reference in New Issue
Block a user