185 lines
9.3 KiB
Markdown
185 lines
9.3 KiB
Markdown
# suse-professional-package-installer — spec
|
|
|
|
Spec-first entries per CE OS Script Development standards, one per
|
|
script, written before generation.
|
|
|
|
---
|
|
|
|
## `main.sh` (orchestrator)
|
|
|
|
- **Name:** `main.sh` — top-level entry point; parses arguments, sources
|
|
`lib/ce-common.sh`, invokes the requested subscript(s) in order.
|
|
- **Inputs:** CLI args — an optional package-list file path, default
|
|
`local/zypper.list` (gitignored, machine-specific real list — see
|
|
`.gitignore` and `packages/*.example` below).
|
|
- **Outputs:** stdout/log lines via `ce-common.sh` logging; exit 0 on
|
|
full success, non-zero if any subscript reports failure.
|
|
- **Error behaviour:** halt on missing/unreadable list file; otherwise
|
|
log-and-continue between independent subscripts (a zypper failure
|
|
doesn't block an unrelated later subscript), non-zero exit if any
|
|
subscript failed.
|
|
- **Privilege:** standard user — orchestrator never elevates itself or
|
|
carries elevation between subscripts (per CE OS privilege model).
|
|
- **Doc references:** `ceos_script_architecture.md` (orchestrator/
|
|
subscript model, privilege model).
|
|
- **Distro target:** common (dispatches to distro-specific subscripts).
|
|
- Exempt from the 100-line subscript boundary per the orchestrator
|
|
exemption.
|
|
|
|
---
|
|
|
|
## `lib/ce-common.sh` (shared library)
|
|
|
|
- **Name:** `ce-common.sh` — logging, privilege-command detection,
|
|
zypper wrapper functions, cleanup trap, user confirmation. Promoted/
|
|
generalized from the private `tinkerpad-stt` deployment's copy —
|
|
project-specific bits (`VOSK_HOME`, hardcoded installer name)
|
|
stripped for public reuse.
|
|
- **Inputs:** sourced only, not executed directly. Reads
|
|
`CE_INSTALLER_NAME` env var (optional, defaults to `suse-pkg-install`).
|
|
- **Outputs:** exported functions/vars for consuming scripts
|
|
(`log_info`, `run_test`, `detect_priv_cmd`, `test_package_available`,
|
|
`package_installed`, `install_packages`, `confirm_proceed`, etc.).
|
|
`run_test(desc, cmd, mode=fail|warn)` is the shared PASS/FAIL/WARN
|
|
check helper (matches the established pattern in
|
|
`~/.local/opt/package-installer/`) — used both by `00_preflight.sh`
|
|
and by `install_packages()` itself for a post-install presence check
|
|
per package (warn-mode: a verification miss is logged, not fatal).
|
|
- **Error behaviour:** `log_error` + `exit 1` on unrecoverable
|
|
conditions (no priv command found, no zypper found).
|
|
- **Privilege:** none itself — only detects what's available;
|
|
escalation happens per-subscript at the point of use.
|
|
- **Doc references:** `ceos_script_architecture.md`,
|
|
`ceos_script_source_discipline.md` (never assume sudo vs doas).
|
|
- **Distro target:** SUSE family (zypper only, scoped to this repo's
|
|
name/purpose — unlike the private multi-manager `ce-common.sh`).
|
|
- **Line count:** 188 non-blank lines — over the 100-line soft signal
|
|
but within the 200-line hard ceiling for non-orchestrator scripts
|
|
(RIS doc-set `65ppjj`, section `lin`, chunks `sft`/`hrd`/`exm` —
|
|
supersedes `0nxwoh`, the original text which omitted the 200-line
|
|
figure entirely; corrected 2026-08-06 per John's direct clarification
|
|
during this project's review). Also arguably orchestrator-like
|
|
itself, per John. Line limits are being deliberately not enforced
|
|
strictly at this early-dev stage, with the intent to split this file
|
|
further once real use/testing surfaces where the actual seams are —
|
|
splitting now, before that, would be guessing at boundaries rather
|
|
than finding them.
|
|
|
|
---
|
|
|
|
## `lib/00_preflight.sh` (subscript)
|
|
|
|
- **Name:** `00_preflight.sh` — environment checks only, no system
|
|
changes. This is the "dry run" step: it always runs, unconditionally,
|
|
before any privileged subscript, and never itself prompts for
|
|
privilege escalation.
|
|
- **Inputs:** none.
|
|
- **Outputs:** exit 0 if all `fail`-mode checks pass (warn-mode checks —
|
|
internet reachability, disk space — log but don't block); exit 1 on
|
|
the first fail-mode check that fails.
|
|
- **Error behaviour:** halt immediately via `run_test`'s fail mode
|
|
(not running as root, zypper present, sudo-or-doas present); warn
|
|
and continue for environmental checks that aren't hard requirements.
|
|
- **Privilege:** standard user only — this subscript makes no
|
|
privileged calls itself, by design.
|
|
- **Doc references:** matches the pre-flight phase pattern in
|
|
`~/.local/opt/package-installer/20260726-201557-package-installer.sh`
|
|
(the established local convention for this project's "dry-run and
|
|
tests" behaviour, per John, 2026-08-06).
|
|
- **Distro target:** SUSE family (zypper check), otherwise common.
|
|
|
|
---
|
|
|
|
## `tests/test_list_parsing.sh` (test script — kept separate, never merged into an install script)
|
|
|
|
- **Name:** `test_list_parsing.sh` — exercises `read_package_list()`
|
|
(comment stripping, whitespace trimming, blank-line skipping,
|
|
comment-only-file rejection, missing-file rejection) with no zypper
|
|
calls and no privilege escalation.
|
|
- **Inputs:** none (writes its own fixture files to a `mktemp -d`
|
|
registered via `register_temp_dir` for automatic cleanup).
|
|
- **Outputs:** exit 0 if every `run_test` check passes; exit 1 (via
|
|
`run_test`'s fail mode) on the first failing assertion.
|
|
- **Error behaviour:** fail-fast — every assertion in this file is
|
|
fail-mode, since a parsing regression should never be silently
|
|
downgraded to a warning.
|
|
- **Privilege:** standard user only.
|
|
- **Doc references:** `ceos_script_architecture.md` ("Test scripts
|
|
always remain separate — they are never merged into installation or
|
|
configuration scripts").
|
|
- **Distro target:** common (pure bash, no package-manager calls).
|
|
|
|
---
|
|
|
|
## `lib/10_zypper-packages.sh` (subscript)
|
|
|
|
- **Name:** `10_zypper-packages.sh` — installs every package listed in
|
|
a given zypper package-list file.
|
|
- **Inputs:** `$1` = path to a package-list file (one package name per
|
|
line, `#`-prefixed comments and blank lines ignored). Defaults to
|
|
`local/zypper.list` (gitignored) if not given.
|
|
- **Outputs:** exit 0 if every listed package ends up installed or was
|
|
already present; exit 1 if any install failed. Unavailable packages
|
|
are warned about, not treated as fatal (matches existing
|
|
`install_packages()` behaviour — a typo in one line shouldn't abort
|
|
the whole run).
|
|
- **Error behaviour:** halt immediately if the list file doesn't
|
|
exist or is empty; per-package log-and-continue during install.
|
|
- **Privilege:** requires escalation (installing system packages) —
|
|
prompts for it at the point `install_packages()` first needs it, via
|
|
`detect_priv_cmd`. Does not hold elevation before that point.
|
|
- **Doc references:** `ceos_script_architecture.md` (privilege model —
|
|
escalation isolated to the subscript that needs it).
|
|
- **Distro target:** SUSE family (zypper).
|
|
|
|
---
|
|
|
|
## Deferred (not built this pass)
|
|
|
|
- **`lib/20_pip-packages.sh`** — pip/pipx package-list subscript.
|
|
Not needed for the immediate target (`poppler-tools`, a zypper
|
|
package), and per the standing rule zypper/pip must stay fully
|
|
separate subscripts, never combined. Spec entry to be written when
|
|
an actual pip/pipx list is needed.
|
|
- **Multi-distro (`apk`/`apt`/`nix`) support** — deliberately out of
|
|
scope. This repo's name and purpose are SUSE-specific; a general
|
|
multi-distro engine already exists privately as `ce-common.sh` in
|
|
`~/.local/opt/tinkerpad-stt/lib/` and is not what this public repo
|
|
is for.
|
|
- **Textual list-authoring/validation TUI** — explicitly deferred
|
|
until the plain-text list format has been used for real and any
|
|
rough edges are known.
|
|
|
|
---
|
|
|
|
## Known gaps (Ambrosiana Gap Protocol — documented per `ceos_script_source_discipline.md`)
|
|
|
|
- **No Ambrosiana-sourced zypper/Tumbleweed documentation.** Per the
|
|
"no training-derived assumptions" rule, every zypper-specific
|
|
behavior used here (`zypper --non-interactive search -x`, cache
|
|
cleanup via `zypper clean --all`, `rpm -q` as the query mechanism)
|
|
was verified live against the real machine, not sourced from
|
|
Ambrosiana — it holds no zypper/Tumbleweed doc-set yet. Same gap
|
|
already logged privately for `tinkerpad-stt` in
|
|
`~/.local/opt/INSTALLER_NOTES.md`. Per protocol step 3 (no quality
|
|
alternative exists yet): proceeding with elevated live-verification
|
|
discipline instead of blocking on it; this note is that documentation
|
|
requirement being met. Should travel into the README's "Known bugs"
|
|
section at public-release time.
|
|
- **Full CE OS deployment workflow not implemented.** The methodology's
|
|
full sequence (full-stack discovery, conflict analysis, FHS Relocator,
|
|
offline USB preparation, formal two-stage QC with a specialised local
|
|
agent ahead of Claude Code) targets full service/system deployments.
|
|
This project is a lightweight package-list installer, not a service
|
|
deployer — no package here lands in a non-FHS default location the
|
|
Relocator would need to catch, and there's no service being deployed
|
|
to discover conflicts against. Treating those pieces as out of
|
|
proportion to scope rather than a compliance gap, but flagging
|
|
explicitly rather than silently omitting them — John's call to
|
|
confirm.
|
|
- **QC is single-stage in practice.** No specialised local agent is
|
|
currently trusted to run a Stage 1 pass ahead of Claude Code — local
|
|
fleet models aren't yet evaluated as reliable enough for this role.
|
|
Claude Code performs both drafting and QC (shellcheck + manual
|
|
review) in one pass, consistent with how this gap is already handled
|
|
elsewhere in this project ecosystem.
|