Skip to content

Commit f4eeeaf

Browse files
committed
feat(install): quote package tokens, add remove/update/downgrade builders
- Add install/utils with shell_single_quote and strict name validation - Harden pacman/AUR/batch builders; add aur_install_body and CascadeMode verbs - Document Phase 4 in INSTALL_MODULE_PHASE; sync index and crate prep docs - Expand install_example tutorial; touch release v0.2.0 notes Made-with: Cursor
1 parent b3f7ecd commit f4eeeaf

7 files changed

Lines changed: 1356 additions & 388 deletions

File tree

dev/AUR_TOOLKIT_CRATE_PREPARATION.md

Lines changed: 352 additions & 331 deletions
Large diffs are not rendered by default.

dev/INDEX_MODULE_PHASE.md

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This document provides a detailed structured plan for implementing the Index Mod
1313
| **Estimated Effort** | 20-30 hours |
1414
| **Complexity** | Medium (system command execution, data persistence, async operations) |
1515
| **Dependencies** | `types` module, optional `aur` module for enrichment |
16-
| **Status** |Core complete - Tasks 3.1 through 3.4 complete; follow-ups pending |
16+
| **Status** |Complete - Tasks 3.1 through 3.5 complete (mirror management + `repos.conf` discovery + fetch parity hardening shipped); Task 3.6 (background updates) intentionally not ported |
1717

1818
## Overview
1919

@@ -260,12 +260,12 @@ This module is foundational and used by other modules (deps, install) for packag
260260
**Estimated Effort**: 2-3 hours
261261

262262
**Acceptance Criteria**:
263-
- [ ] Mirror fetching works
264-
- [ ] Windows-specific code is optional
265-
- [ ] Unit tests
266-
- [ ] Code passes quality checks
263+
- [x] Mirror fetching works (see `src/index/mirrors.rs::fetch_mirrors`)
264+
- [x] Windows-specific code is optional (module is platform-agnostic; consumers select via `index` feature)
265+
- [x] Unit tests (`parse_mirrors_from_json_extracts_rows`, `generate_mirrorlist_filters_to_active_https`)
266+
- [x] Code passes quality checks
267267

268-
**Note**: This may be low priority if Windows support is not needed initially.
268+
**Note**: Implementation shipped in current tree via `fetch_mirrors()` + `generate_mirrorlist()` using `reqwest`. Example available: `examples/index_mirrors_example.rs`.
269269

270270
---
271271

@@ -278,10 +278,10 @@ This module is foundational and used by other modules (deps, install) for packag
278278
**Estimated Effort**: 2-3 hours
279279

280280
**Acceptance Criteria**:
281-
- [ ] Extra repositories can be discovered from `repos.conf`
282-
- [ ] Index fetch includes discovered third-party repos (e.g., Chaotic-AUR)
283-
- [ ] Behavior degrades gracefully when config parsing fails
284-
- [ ] Unit tests cover parser + repo list derivation
281+
- [x] Extra repositories can be discovered from `repos.conf` (see `src/repos/config.rs::repos_conf_repo_names_for_index_sl`)
282+
- [x] Index fetch includes discovered third-party repos (e.g., Chaotic-AUR) via `merged_repos_for_index_fetch` in `src/index/fetch.rs`
283+
- [x] Behavior degrades gracefully when config parsing fails (baseline `core/extra/multilib` still fetched)
284+
- [x] Unit tests cover parser + repo list derivation (see `src/index/fetch.rs` tests using `ARCH_TOOLKIT_REPOS_CONF_PATH`)
285285

286286
---
287287

@@ -294,10 +294,10 @@ This module is foundational and used by other modules (deps, install) for packag
294294
**Estimated Effort**: 2-3 hours
295295

296296
**Acceptance Criteria**:
297-
- [ ] Repo/name dedup behavior matches intended Pacsea parity
298-
- [ ] Extra-repo `pacman -Sl` handling is resilient to partial failures
299-
- [ ] Fallback behavior remains explicit and test-covered
300-
- [ ] Unit tests cover parity-critical scenarios
297+
- [x] Repo/name dedup behavior matches intended Pacsea parity (lowercase dedup in `merged_repos_for_index_fetch`)
298+
- [x] Extra-repo `pacman -Sl` handling is resilient to partial failures (baseline strict, extras soft-fail)
299+
- [x] Fallback behavior remains explicit and test-covered (pacman-first with API fallback in `fetch_official_index_async`)
300+
- [x] Unit tests cover parity-critical scenarios
301301

302302
---
303303

@@ -520,10 +520,10 @@ The Index Module is complete when:
520520
- [ ] Example program works
521521
- [x] Code passes `cargo fmt`, `cargo clippy`, `cargo check` (for completed tasks)
522522
- [ ] README updated with index module documentation
523-
- [x] Module entry point created (Task 3.7 - partial, installed/explicit/query/fetch/persist modules complete)
524-
- [ ] Mirror management follow-up complete (Task 3.5.1 - optional)
525-
- [ ] `repos.conf` extra repo discovery follow-up complete (Task 3.5.2 - pending)
526-
- [ ] Fetch parity hardening follow-up complete (Task 3.5.3 - pending)
523+
- [x] Module entry point created (Task 3.7)
524+
- [x] Mirror management follow-up complete (Task 3.5.1)
525+
- [x] `repos.conf` extra repo discovery follow-up complete (Task 3.5.2)
526+
- [x] Fetch parity hardening follow-up complete (Task 3.5.3)
527527

528528
---
529529

@@ -535,25 +535,24 @@ The Index Module is complete when:
535535
| 3.2: Installed Queries | 4-6 | High | ✅ Complete |
536536
| 3.3: Official Queries | 7-9 | High | ✅ Complete |
537537
| 3.4: Persistence | 2-3 | High | ✅ Complete |
538-
| 3.5: Mirror Management | 2-3 | Medium (Optional) |
539-
| 3.5.2: `repos.conf` Extra Repo Discovery | 2-3 | Medium | ⏳ Pending |
540-
| 3.5.3: Fetch Parity Hardening | 2-3 | Medium | ⏳ Pending |
541-
| 3.6: Background Updates | 2-3 | Low (Optional) |
542-
| 3.7: Module Entry Point | 1-2 | High |Partial (installed/explicit/query/fetch/persist complete) |
543-
| 3.8: Testing & Docs | 7-10 | High |Partial (installed/explicit/query/fetch/persist complete) |
538+
| 3.5.1: Mirror Management | 2-3 | Medium | ✅ Complete |
539+
| 3.5.2: `repos.conf` Extra Repo Discovery | 2-3 | Medium | ✅ Complete |
540+
| 3.5.3: Fetch Parity Hardening | 2-3 | Medium | ✅ Complete |
541+
| 3.6: Background Updates | 2-3 | Low | ⏳ Not ported (optional, TUI runtime concern) |
542+
| 3.7: Module Entry Point | 1-2 | High |Complete |
543+
| 3.8: Testing & Docs | 7-10 | High |Complete |
544544
| **Total** | **31-45 hours** | |
545545

546-
**Recommended Approach**: Keep core tasks complete (3.1-3.4, 3.7-3.8) and prioritize follow-ups in order: 3.5.2, 3.5.3, then optional 3.5.1/3.6 as needed.
546+
**Recommended Approach**: Phase 3 index module is done. Task 3.6 (background updates) stays in consumer crates (Pacsea) as it depends on a host runtime/notification channel design.
547547

548548
---
549549

550550
## Next Steps
551551

552-
1. Maintain Task 3.4 as completed baseline in this document
553-
2. Implement Task 3.5.2 (`repos.conf`-driven extra repo discovery)
554-
3. Implement Task 3.5.3 (fetch parity hardening)
555-
4. Reassess Task 3.5.1 (mirror management) based on platform priorities
556-
5. Update this document after each follow-up is completed
552+
Phase 3 is complete. Remaining work moves to Phase 4 (install module) - see [INSTALL_MODULE_PHASE.md](./INSTALL_MODULE_PHASE.md).
553+
554+
Deferred (not blocking Phase 4):
555+
- Task 3.6 (background updates): kept in consumer crates; would require a channel/callback design that is not yet justified at the library boundary.
557556

558557
---
559558

dev/INSTALL_MODULE_PHASE.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# Install Module - Phase 4 Implementation Plan
2+
3+
This document tracks the scope, progress, and explicit non-goals of the Install Module (`feature = "install"`) in `arch-toolkit`. This is Phase 4 of the extraction plan from Pacsea.
4+
5+
---
6+
7+
## Executive Summary
8+
9+
| Aspect | Details |
10+
|--------|---------|
11+
| **Module** | `install` (feature = "install") |
12+
| **Source** | `Pacsea/src/install/` (command-string helpers only) + `Pacsea/src/logic/privilege.rs` (already represented in `arch-toolkit` as `src/system/privilege.rs`) |
13+
| **Estimated Effort** | 8-12 hours |
14+
| **Complexity** | Low-medium (pure string algebra + strict shell-quoting discipline) |
15+
| **Dependencies** | `error`, `system::privilege` |
16+
| **Status** | ✅ Complete - Priorities 1-4 shipped, example and phase doc in place |
17+
18+
Phase 4 is intentionally scoped to **framework-agnostic, pure-Rust command string builders** for `pacman`/AUR-helper operations. Password pipes, PTY spawning, TUI wiring, and filesystem scans stay in Pacsea.
19+
20+
---
21+
22+
## Scope
23+
24+
### In scope (ported / aligned)
25+
26+
- Shell-quoting helpers (`shell_single_quote`, `is_safe_package_name`, `validate_package_names`, `quote_and_join_package_names`) - [src/install/utils.rs](../src/install/utils.rs)
27+
- Install command builders hardened to quote every interpolated package name:
28+
- `build_pacman_install_command` (official `-S` installs)
29+
- `build_aur_install_command` (helper installs with an explicit `AurHelper`)
30+
- `build_batch_install_command` (mixed official + AUR planning with overlap preflight)
31+
- Stateless helpers for constructing AUR planning fragments:
32+
- `aur_install_helper_flags` (constant flag selection)
33+
- `aur_install_body` (paru-preferred / yay-fallback shell snippet)
34+
- `detect_aur_helper` (PATH-based preference)
35+
- `aur_pkgnames_also_in_official_catalog` (overlap detection)
36+
- Remove / downgrade / update command builders wired through [`system::privilege`](../src/system/privilege.rs):
37+
- `CascadeMode` (mirrors Pacsea's `-R` / `-Rs` / `-Rns` modes)
38+
- `build_remove_command(tool, names, cascade, dry_run)`
39+
- `build_downgrade_command(tool, names, dry_run)` (guards against missing `downgrade` helper)
40+
- `build_update_command(commands, dry_run)` (chain with `&&`, dry-run echoes each step)
41+
42+
### Out of scope (remains in Pacsea)
43+
44+
- `Pacsea/src/install/executor.rs` — PTY spawning, password pipes, `sudo -S` integration, hold-tail loop, credential warm-up.
45+
- `Pacsea/src/install/scan/` and `Pacsea/src/install/patterns.rs` — scanner + env wiring; better fit a future Sandbox phase or a dedicated `scan` feature.
46+
- `Pacsea/src/install/logging.rs`, terminal spawn helpers, UX-specific dry-run failure simulation (`PACSEA_TEST_SIMULATE_PACMAN_FAILURE`).
47+
- Consumers that need password pipes should compose them themselves using `crate::system::privilege::build_privilege_command` plus their own redacted logging strategy. The library deliberately does not construct password pipe commands to keep its security surface small.
48+
49+
---
50+
51+
## Priorities and progress
52+
53+
### Priority 1 — Security parity on existing APIs ✅
54+
55+
- [x] Added `shell_single_quote`, `is_safe_package_name`, and `validate_package_names` to `src/install/utils.rs` (mirrors Pacsea's pattern).
56+
- [x] Re-exported the quoting helpers from the `install` module root.
57+
- [x] Updated `build_pacman_install_command`, `build_aur_install_command`, and the batch builder to single-quote **every** package token before interpolation.
58+
- [x] Regression tests cover metacharacters (`;`, `$(...)`, embedded single quotes) and dry-run wrapping.
59+
60+
### Priority 2 — Align helpers with Pacsea's pure install layer ✅
61+
62+
- [x] Ported `aur_install_body(flags, quoted_names)` so consumers can compose `paru || yay` fallback snippets without running `detect_aur_helper` at planning time.
63+
- [x] Kept the existing `aur_install_helper_flags(reinstall)` constant function for shared flag strings.
64+
65+
### Priority 3 — Remove / update / downgrade command strings ✅
66+
67+
- [x] Added `CascadeMode` (`Basic` / `Cascade` / `CascadeWithConfigs`) matching Pacsea.
68+
- [x] `build_remove_command(tool, names, cascade, dry_run)` uses `system::privilege::build_privilege_command`.
69+
- [x] `build_downgrade_command(tool, names, dry_run)` emits the defensive `if (command -v downgrade) || pacman -Qi downgrade; then ... else echo ...; fi` shell guard.
70+
- [x] `build_update_command(commands, dry_run)` chains pre-built steps with ` && ` and wraps each step in `echo DRY RUN: '...'` on dry-run.
71+
- [x] Unit tests cover empty inputs, both privilege tools, cascade variants, dry-run wrapping, and guard logic.
72+
73+
### Priority 4 — Process / documentation ✅
74+
75+
- [x] Update [AUR_TOOLKIT_CRATE_PREPARATION.md](./AUR_TOOLKIT_CRATE_PREPARATION.md) Phase 4 bullet to reflect in-progress state.
76+
- [x] Reconcile [INDEX_MODULE_PHASE.md](./INDEX_MODULE_PHASE.md) with the current `src/index` + `src/repos` tree (Task 3.5.x are implemented).
77+
- [x] Author this `INSTALL_MODULE_PHASE.md`.
78+
- [x] Expand `examples/install_example.rs` to tutorial-style parity with `pkgbuild_example` / `deps_types_example` (see Examples below).
79+
80+
---
81+
82+
## Public API surface (current)
83+
84+
```text
85+
arch_toolkit::install
86+
├── utils::shell_single_quote
87+
├── utils::is_safe_package_name
88+
├── utils::validate_package_names
89+
├── utils::quote_and_join_package_names
90+
├── InstallSource { Official, Aur }
91+
├── InstallTarget { name, source }
92+
├── AurHelper { Paru, Yay } + binary_name()
93+
├── aur_install_helper_flags(reinstall)
94+
├── aur_install_body(flags, quoted_names)
95+
├── detect_aur_helper()
96+
├── build_pacman_install_command(packages, reinstall, dry_run)
97+
├── build_aur_install_command(helper, packages, reinstall, dry_run)
98+
├── build_batch_install_command(targets, official_has_reinstall, aur_has_reinstall, official_catalog, dry_run) -> Result
99+
├── aur_pkgnames_also_in_official_catalog(targets, catalog) -> Vec<String>
100+
├── CascadeMode { Basic, Cascade, CascadeWithConfigs } + flag()
101+
├── build_remove_command(tool, names, cascade, dry_run)
102+
├── build_downgrade_command(tool, names, dry_run)
103+
└── build_update_command(commands, dry_run)
104+
```
105+
106+
All package tokens interpolated into shell command strings are passed through `shell_single_quote`. Callers who need strict allowlist enforcement should invoke `validate_package_names` before building commands.
107+
108+
---
109+
110+
## Acceptance criteria
111+
112+
- [x] Every builder that interpolates package tokens quotes them individually.
113+
- [x] Unit tests exist for each builder, including empty-list and dry-run paths.
114+
- [x] Regression tests prove shell metacharacters are neutralised.
115+
- [x] Remove / update / downgrade builders delegate privilege-tool selection to `crate::system::privilege`.
116+
- [x] No new environment-variable test-overrides ship in release builds.
117+
- [x] `cargo test --all-features -- --test-threads=1` passes.
118+
- [x] `cargo clippy --all-targets --all-features -- -D warnings` is clean.
119+
- [x] `examples/install_example.rs` walks through each public API in sectioned output (parity with Phase 2/3 examples).
120+
121+
---
122+
123+
## Examples parity (pending)
124+
125+
Bring `examples/install_example.rs` up to the same tutorial style as [`examples/pkgbuild_example.rs`](../examples/pkgbuild_example.rs) and [`examples/deps_types_example.rs`](../examples/deps_types_example.rs):
126+
127+
- Sectioned stdout walkthrough ("# 1. Shell quoting", "# 2. Validation", "# 3. Pacman install", "# 4. AUR install", "# 5. Mixed batch", "# 6. Remove / downgrade / update").
128+
- Scenarios to demonstrate: empty lists, `reinstall = true/false`, `dry_run = true/false`, mixed official + AUR batch, overlap error path, quoting of awkward-but-valid edge cases.
129+
- Include `cargo run --example install_example --features install` in the file header doc comment.
130+
131+
---
132+
133+
## Verification
134+
135+
Run from the repository root (per [AGENTS.md](../AGENTS.md)):
136+
137+
```bash
138+
cargo fmt --all
139+
cargo clippy --all-targets --all-features -- -D warnings
140+
cargo check
141+
cargo test --all-features -- --test-threads=1
142+
```
143+
144+
---
145+
146+
## References
147+
148+
- [AUR_TOOLKIT_CRATE_PREPARATION.md](./AUR_TOOLKIT_CRATE_PREPARATION.md) — overall extraction plan.
149+
- [DEPENDENCIES_MODULE_PHASE.md](./DEPENDENCIES_MODULE_PHASE.md) — Phase 2 reference for doc structure.
150+
- [INDEX_MODULE_PHASE.md](./INDEX_MODULE_PHASE.md) — Phase 3 reference.
151+
- Pacsea source: `src/install/` — source code for command-string helpers.
152+
- Pacsea source: `src/logic/privilege.rs` — already represented here as `src/system/privilege.rs`.

docs/RELEASE_v0.2.0.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,45 @@ This release completes the dependency management module with full resolution, qu
99
### ✨ New Features
1010

1111
**Dependency Resolution**
12+
1213
- Resolve dependencies for official, AUR, and local packages
1314
- Configurable resolution (include optional, make, check dependencies)
1415
- Batch dependency fetching for efficient queries
1516
- Conflict detection and status determination
1617
- Support for PKGBUILD cache callbacks
1718

1819
**Reverse Dependency Analysis**
20+
1921
- Find all packages that depend on packages being removed
2022
- Distinguish direct vs transitive dependents
2123
- Generate conflict status with detailed reasons
2224
- Helper functions for quick dependency checks
2325

2426
**Version Comparison**
27+
2528
- Pacman-compatible version comparison algorithm
2629
- Version requirement satisfaction checking
2730
- Major version bump detection
2831
- Extract major version components
2932

3033
**Package Querying**
34+
3135
- Query installed packages
3236
- Query upgradable packages
3337
- Get installed and available package versions
3438
- Check if packages are installed or provided
3539
- Graceful degradation when pacman is unavailable
3640

3741
**Source Determination**
42+
3843
- Determine package source (official, AUR, local)
3944
- Identify core repository packages
4045
- Detect critical system packages
4146

4247
### 📚 Examples
4348

4449
Seven comprehensive example files demonstrate all new functionality:
50+
4551
- `examples/deps_example.rs` - Complete dependency module overview
4652
- `examples/parse_example.rs` - Dependency specification parsing
4753
- `examples/query_example.rs` - Package querying examples
@@ -160,6 +166,7 @@ arch-toolkit = { version = "0.2.0", features = ["deps", "aur"] }
160166
No breaking changes! This is a backward-compatible release. All existing code will continue to work.
161167

162168
**New capabilities:**
169+
163170
- Use `DependencyResolver` to resolve dependencies for packages
164171
- Use `ReverseDependencyAnalyzer` to analyze reverse dependencies
165172
- Use version comparison functions for package version checks
@@ -179,5 +186,4 @@ Found a bug or have a feature request? Open an issue on [GitHub](https://github.
179186

180187
---
181188

182-
**Full Changelog**: See [CHANGELOG.md](../CHANGELOG.md) for detailed technical changes.
183-
189+
**Full Changelog**: See [CHANGELOG.md](../CHANGELOG.md) for detailed technical changes.

0 commit comments

Comments
 (0)