Skip to content

feat(systemd): Systemd trait + LiveSystemd + MockSystemd + parsers#12

Merged
UnbreakableMJ merged 1 commit into
mainfrom
feat/systemd-adapter
Apr 27, 2026
Merged

feat(systemd): Systemd trait + LiveSystemd + MockSystemd + parsers#12
UnbreakableMJ merged 1 commit into
mainfrom
feat/systemd-adapter

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

Plan §6.8 — third M1 Week 2 adapter probe path. Inventory only at M1; enable/disable/mask/restart arrive in M2.

Public surface

  • trait Systemd { fn inventory() -> Result<ServiceInventory, SystemdError>; }
  • struct LiveSystemd — invokes systemctl list-unit-files + list-units.
  • struct MockSystemd — feature-gated, canned inventory.
  • fn parse_list_unit_files / parse_list_units / compose_inventory exposed pub for direct use.

Parser semantics

  • list-unit-files: enabled + enabled-runtime → enabled; disabled → disabled; masked + masked-runtime → masked. static / alias / indirect / generated / transient skipped.
  • list-units: filter LOAD == loaded && ACTIVE == active — excludes not-found, error, masked, inactive.

Tests (10 passing)

  • inventory: distinguishes states, skips non-configurable states, filters loaded+active, empty inputs, composes both streams, defensive on truncated lines.
  • live: systemctl_not_in_path_error_class, live_systemd_inventory_succeeds_when_systemctl_present (silent-skips when systemctl missing).
  • mock: empty + with_inventory round-trip.

Verification

  • cargo test -p pearlite-systemd — 10 passed; 0 failed
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all --check
  • scripts/ci/check-spdx.sh
  • pearlite-audit check . — 1 check, 0 violations

🤖 Generated with Claude Code

Plan §6.8 — third M1 Week 2 adapter probe path. Inventory only at M1;
enable / disable / mask / restart arrive with M2 per Plan §7.3.

Public surface:

- pub trait Systemd { fn inventory(&self) -> Result<ServiceInventory, SystemdError>; }
- pub struct LiveSystemd with new() / with_binary() / binary().
- pub struct MockSystemd (test-mocks feature) with new() / with_inventory().
- pub fn parse_list_unit_files(&str) -> (BTreeSet<String>, BTreeSet<String>, BTreeSet<String>)
  returning (enabled, disabled, masked).
- pub fn parse_list_units(&str) -> BTreeSet<String> returning the
  loaded+active set.
- pub fn compose_inventory(unit_files, units) -> ServiceInventory.
- pub enum SystemdError — NotInPath, Io, InvocationFailed, NotUtf8.

Parser semantics:

- list-unit-files: enabled and enabled-runtime → enabled set;
  disabled → disabled; masked and masked-runtime → masked. static,
  alias, indirect, generated, transient skipped (not user-configurable
  enable values).
- list-units: filter LOAD == "loaded" && ACTIVE == "active" so the
  active set excludes not-found, error, masked, and inactive units.

LiveSystemd invokes:
- systemctl list-unit-files --no-pager --no-legend
- systemctl list-units --no-pager --no-legend --all --plain

Tests (10 passing):
- inventory: list_unit_files_distinguishes_enabled_disabled_masked,
  list_unit_files_skips_static_alias_indirect,
  list_units_filters_to_loaded_active, empty_outputs_yield_empty_inventory,
  compose_combines_both_streams, truncated_lines_are_skipped.
- live: systemctl_not_in_path_error_class,
  live_systemd_inventory_succeeds_when_systemctl_present (silent-skips
  if systemctl missing — CI runners have it).
- mock: empty_mock_yields_empty_inventory, with_inventory_round_trips.

Verification:
- cargo test -p pearlite-systemd  (10 passed; 0 failed)
- cargo clippy --workspace --all-targets -- -D warnings  (zero warnings)
- cargo fmt --all --check
- scripts/ci/check-spdx.sh
- pearlite-audit check .  (1 check, 0 violations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@UnbreakableMJ
UnbreakableMJ merged commit fc492cf into main Apr 27, 2026
3 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the feat/systemd-adapter branch April 27, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant