git clone https://github.com/otectus/Archer.git
cd Archer- Bash 5.0+
- ShellCheck for linting
- Bats for testing
- Python 3.10+ (for GUI development)
Install on Arch:
sudo pacman -S shellcheck bash-bats python# Run all tests
bats tests/
# Run a specific test file
bats tests/detect.bats
# Run with verbose output
bats -t tests/# Lint all shell scripts
find . -name '*.sh' -not -path './.git/*' -exec shellcheck -x -s bash {} \;
# Lint Python GUI code
flake8 gui/ --max-line-length=120Archer/
install.sh # Main entry point, CLI parsing, interactive menu
uninstall.sh # Manifest-aware uninstaller
lib/
utils.sh # Logging, run/run_sudo, helpers (shared by all scripts)
detect.sh # Hardware detection engine (DMI, GPU, WiFi, kernel, distro)
manifest.sh # JSON manifest for tracking installed state
modules/ # 13 independent modules (see below)
gui/ # GTK4/Adwaita application + D-Bus daemon
tests/ # Bats test suite
- Create
modules/<id>.shimplementing the module interface:
MODULE_NAME="Display Name"
MODULE_ID="module-id"
MODULE_DESCRIPTION="What this module does"
module_detect() # Return 0 if relevant to current hardware
module_check_installed() # Return 0 if already installed
module_install() # Perform installation
module_uninstall() # Reverse installation
module_verify() # Return 0 if working correctly-
Register in
install.sh:- Add the ID to
MODULE_IDSarray - Add the label to
MODULE_LABELSarray
- Add the ID to
-
Add recommendation logic in
lib/detect.shbuild_recommendations(). -
Add a test in
tests/modules.batsverifying the module defines all required functions. -
Update the README with a description of the module.
- Use
#!/usr/bin/env bashshebang - Always
set -euo pipefailin entry scripts - Use
[[ ]]for conditionals (not[ ]) - Quote all variables:
"$var"not$var - Use
localfor function-scoped variables - Use
has_cmd(fromutils.sh) instead ofcommand -vdirectly - Use
run/run_sudofor commands that should respect--dry-run - Prefix module-private variables with
_(e.g.,_BATTERY_DKMS_NAME) - Keep modules self-contained: each module sources
utils.shglobals but defines its own functions
- Follow PEP 8 with max line length of 120
- Use type hints where practical
- GTK4/Adwaita patterns:
Adw.Application,Adw.ApplicationWindow - D-Bus client calls go through
archer/client.py
- Use imperative mood: "Add battery module" not "Added battery module"
- First line: concise summary (under 72 chars)
- Body: explain why, not just what
Some modules are mutually exclusive:
- driver (Linuwu-Sense) and thermal (Kernel Thermal Profiles) both interact with
acer_wmi. The driver blacklists it; thermal requires it. The installer enforces this conflict incheck_conflicts().
When adding modules that conflict with existing ones, update check_conflicts() in install.sh and add conflict tags in display_menu().
All PRs are checked by GitHub Actions:
- ShellCheck: Lints all
.shfiles - Bash syntax:
bash -non all scripts - Bats tests: Runs
tests/*.bats - Python lint: flake8 on
gui/
Ensure all checks pass before submitting a PR.