This commit is contained in:
2026-03-20 10:47:58 +01:00
parent f791799105
commit d0c590c185
5 changed files with 81 additions and 9 deletions

View File

@@ -2,6 +2,40 @@
--- ---
## V35 2026-03-20 21:00:00
**Harden dpack repo loading and fix search command failure**
### Changes:
- Fixed `src/dpack/src/main.rs`:
- Search, Remove, Upgrade, and CheckUpdates commands now gracefully handle
repo loading failures — logs a warning to stderr and continues to next repo
instead of aborting the entire command via `?` operator
- This prevents a single broken/unreadable repo or package file from making
the search command return no results
- Fixed `src/dpack/src/resolver/mod.rs`:
- `load_repo()` now gracefully handles unreadable directory entries
(broken symlinks, permission errors) — logs warning and skips instead of
propagating error via `?`
- `file_type()` errors fall back to `path.is_dir()` (follows symlinks) instead
of aborting the entire repo scan
- Improved `tests/run-tests.sh`:
- dpack.cli.search test now captures both stdout and stderr (was suppressing
stderr with `2>/dev/null` which hid error messages)
- On failure, includes first 5 lines of output in the failure message for debugging
### Plan deviation/changes:
- None
### What is missing/needs polish:
- The build/install orchestrator (`build/mod.rs`) still uses `?` for load_repo — this
is intentional since installs need complete dependency information
- Root cause of the original search failure (which repo/file triggered the error)
is not yet identified — the improved error handling and diagnostics will reveal
this on the next test run
---
## V34 2026-03-20 17:30:00 ## V34 2026-03-20 17:30:00
**Fix critical gaps: locale-gen, 32-bit multilib, network auto-detect, polkit** **Fix critical gaps: locale-gen, 32-bit multilib, network auto-detect, polkit**

View File

@@ -128,7 +128,13 @@ fn run(cli: Cli) -> Result<()> {
// Load repos for reverse-dep checking // Load repos for reverse-dep checking
let mut all_repo_packages = std::collections::HashMap::new(); let mut all_repo_packages = std::collections::HashMap::new();
for repo in &config.repos { for repo in &config.repos {
let repo_pkgs = resolver::DependencyGraph::load_repo(&repo.path)?; let repo_pkgs = match resolver::DependencyGraph::load_repo(&repo.path) {
Ok(pkgs) => pkgs,
Err(e) => {
eprintln!("Warning: failed to load repo '{}': {}", repo.name, e);
continue;
}
};
all_repo_packages.extend(repo_pkgs); all_repo_packages.extend(repo_pkgs);
} }
@@ -191,7 +197,13 @@ fn run(cli: Cli) -> Result<()> {
// Load all repos to compare available vs installed versions // Load all repos to compare available vs installed versions
let mut all_repo_packages = std::collections::HashMap::new(); let mut all_repo_packages = std::collections::HashMap::new();
for repo in &config.repos { for repo in &config.repos {
let repo_pkgs = resolver::DependencyGraph::load_repo(&repo.path)?; let repo_pkgs = match resolver::DependencyGraph::load_repo(&repo.path) {
Ok(pkgs) => pkgs,
Err(e) => {
eprintln!("Warning: failed to load repo '{}': {}", repo.name, e);
continue;
}
};
all_repo_packages.extend(repo_pkgs); all_repo_packages.extend(repo_pkgs);
} }
@@ -254,7 +266,13 @@ fn run(cli: Cli) -> Result<()> {
Commands::Search { query } => { Commands::Search { query } => {
// Search through all repos for matching package names/descriptions // Search through all repos for matching package names/descriptions
for repo in &config.repos { for repo in &config.repos {
let packages = resolver::DependencyGraph::load_repo(&repo.path)?; let packages = match resolver::DependencyGraph::load_repo(&repo.path) {
Ok(pkgs) => pkgs,
Err(e) => {
eprintln!("Warning: failed to load repo '{}': {}", repo.name, e);
continue;
}
};
for (name, pkg) in &packages { for (name, pkg) in &packages {
if name.contains(&query) || pkg.package.description.to_lowercase().contains(&query.to_lowercase()) { if name.contains(&query) || pkg.package.description.to_lowercase().contains(&query.to_lowercase()) {
println!( println!(
@@ -398,7 +416,13 @@ fn run(cli: Cli) -> Result<()> {
// Load all repos // Load all repos
let mut all_repo_packages = std::collections::HashMap::new(); let mut all_repo_packages = std::collections::HashMap::new();
for repo in &config.repos { for repo in &config.repos {
let repo_pkgs = resolver::DependencyGraph::load_repo(&repo.path)?; let repo_pkgs = match resolver::DependencyGraph::load_repo(&repo.path) {
Ok(pkgs) => pkgs,
Err(e) => {
eprintln!("Warning: failed to load repo '{}': {}", repo.name, e);
continue;
}
};
all_repo_packages.extend(repo_pkgs); all_repo_packages.extend(repo_pkgs);
} }

View File

@@ -84,8 +84,21 @@ impl DependencyGraph {
for entry in std::fs::read_dir(repo_dir) for entry in std::fs::read_dir(repo_dir)
.with_context(|| format!("Failed to read repo: {}", repo_dir.display()))? .with_context(|| format!("Failed to read repo: {}", repo_dir.display()))?
{ {
let entry = entry?; let entry = match entry {
if !entry.file_type()?.is_dir() { Ok(e) => e,
Err(e) => {
log::warn!("Skipping unreadable entry in {}: {}", repo_dir.display(), e);
continue;
}
};
let is_dir = match entry.file_type() {
Ok(ft) => ft.is_dir(),
Err(_) => {
// Fallback: try metadata (follows symlinks)
entry.path().is_dir()
}
};
if !is_dir {
continue; continue;
} }

View File

@@ -280,10 +280,11 @@ DCONF
record_test "dpack.cli.check" "fail" "Exit code $?" record_test "dpack.cli.check" "fail" "Exit code $?"
fi fi
if $DPACK_CMD search zlib 2>/dev/null | grep -q "zlib"; then SEARCH_OUT=$($DPACK_CMD search zlib 2>&1)
if echo "$SEARCH_OUT" | grep -q "zlib"; then
record_test "dpack.cli.search" "pass" record_test "dpack.cli.search" "pass"
else else
record_test "dpack.cli.search" "fail" "zlib not found in search" record_test "dpack.cli.search" "fail" "zlib not found in search. Output: $(echo "$SEARCH_OUT" | head -5)"
fi fi
if $DPACK_CMD info zlib 2>/dev/null | grep -qi "compression\|zlib"; then if $DPACK_CMD info zlib 2>/dev/null | grep -qi "compression\|zlib"; then