chore(format): format code

This commit is contained in:
Till Wegmueller 2026-01-25 23:17:49 +01:00
parent e7dc9d5a4c
commit 4ab529f4c7
No known key found for this signature in database
11 changed files with 210 additions and 107 deletions

View file

@ -635,7 +635,10 @@ impl Resolver {
// Helper: extract the package FMRI from a manifest's attributes // Helper: extract the package FMRI from a manifest's attributes
fn manifest_fmri(manifest: &Manifest) -> Option<Fmri> { fn manifest_fmri(manifest: &Manifest) -> Option<Fmri> {
for attr in &manifest.attributes { for attr in &manifest.attributes {
if attr.key == "pkg.fmri" && let Some(val) = attr.values.first() && let Ok(f) = Fmri::parse(val) { if attr.key == "pkg.fmri"
&& let Some(val) = attr.values.first()
&& let Ok(f) = Fmri::parse(val)
{
return Some(f); return Some(f);
} }
} }

View file

@ -3,12 +3,15 @@
// MPL was not distributed with this file, You can // MPL was not distributed with this file, You can
// obtain one at https://mozilla.org/MPL/2.0/. // obtain one at https://mozilla.org/MPL/2.0/.
use crate::repository::{ReadableRepository, FileBackend, RepositoryError, Result, WritableRepository, ProgressReporter, ProgressInfo, NoopProgressReporter};
use crate::fmri::Fmri;
use crate::actions::Manifest; use crate::actions::Manifest;
use crate::fmri::Fmri;
use crate::repository::{
FileBackend, NoopProgressReporter, ProgressInfo, ProgressReporter, ReadableRepository,
RepositoryError, Result, WritableRepository,
};
use std::collections::HashSet; use std::collections::HashSet;
use tempfile::tempdir; use tempfile::tempdir;
use tracing::{info, debug}; use tracing::{debug, info};
/// PackageReceiver handles downloading packages from a source repository /// PackageReceiver handles downloading packages from a source repository
/// and storing them in a destination repository. /// and storing them in a destination repository.
@ -21,7 +24,11 @@ pub struct PackageReceiver<'a, S: ReadableRepository> {
impl<'a, S: ReadableRepository> PackageReceiver<'a, S> { impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
/// Create a new PackageReceiver /// Create a new PackageReceiver
pub fn new(source: &'a mut S, dest: FileBackend) -> Self { pub fn new(source: &'a mut S, dest: FileBackend) -> Self {
Self { source, dest, progress: None } Self {
source,
dest,
progress: None,
}
} }
/// Set the progress reporter /// Set the progress reporter
@ -37,7 +44,12 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
/// * `default_publisher` - The default publisher name if not specified in FMRI /// * `default_publisher` - The default publisher name if not specified in FMRI
/// * `fmris` - List of FMRIs to receive /// * `fmris` - List of FMRIs to receive
/// * `recursive` - Whether to receive dependencies recursively /// * `recursive` - Whether to receive dependencies recursively
pub fn receive(&mut self, default_publisher: Option<&str>, fmris: &[Fmri], recursive: bool) -> Result<()> { pub fn receive(
&mut self,
default_publisher: Option<&str>,
fmris: &[Fmri],
recursive: bool,
) -> Result<()> {
let mut processed = HashSet::new(); let mut processed = HashSet::new();
let mut queue: Vec<Fmri> = fmris.to_vec(); let mut queue: Vec<Fmri> = fmris.to_vec();
let mut updated_publishers = HashSet::new(); let mut updated_publishers = HashSet::new();
@ -53,36 +65,55 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
while let Some(fmri) = queue.pop() { while let Some(fmri) = queue.pop() {
// If the FMRI doesn't have a version, we need to find the newest one // If the FMRI doesn't have a version, we need to find the newest one
let fmris_to_fetch = if fmri.version.is_none() { let fmris_to_fetch = if fmri.version.is_none() {
let publisher = fmri.publisher.as_deref().or(default_publisher).ok_or_else(|| { let publisher =
RepositoryError::Other(format!("No publisher specified for package {}", fmri.name)) fmri.publisher
.as_deref()
.or(default_publisher)
.ok_or_else(|| {
RepositoryError::Other(format!(
"No publisher specified for package {}",
fmri.name
))
})?; })?;
overall_progress = overall_progress.with_context(format!("Looking up newest version for {}", fmri.name)); overall_progress = overall_progress
.with_context(format!("Looking up newest version for {}", fmri.name));
progress.update(&overall_progress); progress.update(&overall_progress);
debug!("No version specified for {}, looking up newest", fmri.name); debug!("No version specified for {}, looking up newest", fmri.name);
let pkgs = self.source.list_packages(Some(publisher), Some(&fmri.name))?; let pkgs = self
.source
.list_packages(Some(publisher), Some(&fmri.name))?;
// Group by package name to find the newest version for each // Group by package name to find the newest version for each
let mut by_name: std::collections::HashMap<String, Vec<crate::repository::PackageInfo>> = std::collections::HashMap::new(); let mut by_name: std::collections::HashMap<
String,
Vec<crate::repository::PackageInfo>,
> = std::collections::HashMap::new();
for pi in pkgs { for pi in pkgs {
by_name.entry(pi.fmri.name.clone()).or_default().push(pi); by_name.entry(pi.fmri.name.clone()).or_default().push(pi);
} }
let mut results = Vec::new(); let mut results = Vec::new();
for (name, versions) in by_name { for (name, versions) in by_name {
let newest = versions.into_iter().max_by(|a, b| { let newest = versions
a.fmri.to_string().cmp(&b.fmri.to_string()) .into_iter()
}); .max_by(|a, b| a.fmri.to_string().cmp(&b.fmri.to_string()));
if let Some(pi) = newest { if let Some(pi) = newest {
results.push(pi.fmri); results.push(pi.fmri);
} else { } else {
info!("Package {} not found in source for publisher {}", name, publisher); info!(
"Package {} not found in source for publisher {}",
name, publisher
);
} }
} }
if results.is_empty() { if results.is_empty() {
info!("Package {} not found in source for publisher {}", fmri.name, publisher); info!(
"Package {} not found in source for publisher {}",
fmri.name, publisher
);
continue; continue;
} }
// Update total_packages: remove the wildcard FMRI we just popped, and add actual results // Update total_packages: remove the wildcard FMRI we just popped, and add actual results
@ -93,9 +124,17 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
}; };
for fmri_to_fetch in fmris_to_fetch { for fmri_to_fetch in fmris_to_fetch {
let publisher_name = fmri_to_fetch.publisher.as_deref().or(default_publisher).ok_or_else(|| { let publisher_name = fmri_to_fetch
RepositoryError::Other(format!("No publisher specified for package {}", fmri_to_fetch.name)) .publisher
})?.to_string(); .as_deref()
.or(default_publisher)
.ok_or_else(|| {
RepositoryError::Other(format!(
"No publisher specified for package {}",
fmri_to_fetch.name
))
})?
.to_string();
if !processed.insert(fmri_to_fetch.clone()) { if !processed.insert(fmri_to_fetch.clone()) {
// If we already processed it (possibly as a dependency), don't count it again // If we already processed it (possibly as a dependency), don't count it again
@ -110,7 +149,10 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
.with_context(format!("Receiving {}", fmri_to_fetch)); .with_context(format!("Receiving {}", fmri_to_fetch));
progress.update(&overall_progress); progress.update(&overall_progress);
info!("Receiving package {} from publisher {}", fmri_to_fetch, publisher_name); info!(
"Receiving package {} from publisher {}",
fmri_to_fetch, publisher_name
);
let manifest = self.receive_one(&publisher_name, &fmri_to_fetch)?; let manifest = self.receive_one(&publisher_name, &fmri_to_fetch)?;
updated_publishers.insert(publisher_name.clone()); updated_publishers.insert(publisher_name.clone());
@ -134,7 +176,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
for pub_name in updated_publishers { for pub_name in updated_publishers {
info!("Rebuilding metadata for publisher {}", pub_name); info!("Rebuilding metadata for publisher {}", pub_name);
overall_progress = overall_progress.with_context(format!("Rebuilding metadata for {}", pub_name)); overall_progress =
overall_progress.with_context(format!("Rebuilding metadata for {}", pub_name));
progress.update(&overall_progress); progress.update(&overall_progress);
self.dest.rebuild(Some(&pub_name), false, false)?; self.dest.rebuild(Some(&pub_name), false, false)?;
} }
@ -149,7 +192,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
let progress = self.progress.unwrap_or(&NoopProgressReporter); let progress = self.progress.unwrap_or(&NoopProgressReporter);
let manifest_text = self.source.fetch_manifest_text(publisher, fmri)?; let manifest_text = self.source.fetch_manifest_text(publisher, fmri)?;
let manifest = Manifest::parse_string(manifest_text.clone()).map_err(RepositoryError::from)?; let manifest =
Manifest::parse_string(manifest_text.clone()).map_err(RepositoryError::from)?;
// Ensure publisher exists in destination // Ensure publisher exists in destination
let dest_info = self.dest.get_info()?; let dest_info = self.dest.get_info()?;
@ -164,7 +208,11 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
let temp_dir = tempdir().map_err(RepositoryError::IoError)?; let temp_dir = tempdir().map_err(RepositoryError::IoError)?;
let payload_files: Vec<_> = manifest.files.iter().filter(|f| f.payload.is_some()).collect(); let payload_files: Vec<_> = manifest
.files
.iter()
.filter(|f| f.payload.is_some())
.collect();
let total_files = payload_files.len() as u64; let total_files = payload_files.len() as u64;
for (i, file) in payload_files.into_iter().enumerate() { for (i, file) in payload_files.into_iter().enumerate() {
@ -172,14 +220,21 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
let files_done = (i + 1) as u64; let files_done = (i + 1) as u64;
let digest = &payload.primary_identifier.hash; let digest = &payload.primary_identifier.hash;
progress.update(&ProgressInfo::new(format!("Receiving payloads for {}", fmri.name)) progress.update(
&ProgressInfo::new(format!("Receiving payloads for {}", fmri.name))
.with_total(total_files) .with_total(total_files)
.with_current(files_done) .with_current(files_done)
.with_context(format!("Payload: {}", digest))); .with_context(format!("Payload: {}", digest)),
);
let temp_file_path = temp_dir.path().join(digest); let temp_file_path = temp_dir.path().join(digest);
debug!("Fetching payload {} to {}", digest, temp_file_path.display()); debug!(
self.source.fetch_payload(publisher, digest, &temp_file_path)?; "Fetching payload {} to {}",
digest,
temp_file_path.display()
);
self.source
.fetch_payload(publisher, digest, &temp_file_path)?;
txn.add_file(file.clone(), &temp_file_path)?; txn.add_file(file.clone(), &temp_file_path)?;
} }
} }
@ -194,8 +249,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::repository::{FileBackend, RepositoryVersion};
use crate::actions::Attr; use crate::actions::Attr;
use crate::repository::{FileBackend, RepositoryVersion};
use tempfile::tempdir; use tempfile::tempdir;
#[test] #[test]
@ -247,11 +302,14 @@ mod tests {
source_repo.add_publisher("test")?; source_repo.add_publisher("test")?;
let _fmri = Fmri::parse("pkg://test/pkgA@1.0").unwrap(); let _fmri = Fmri::parse("pkg://test/pkgA@1.0").unwrap();
let manifest_content = "set name=pkg.fmri value=pkg://test/pkgA@1.0\nset name=pkg.summary value=test\n"; let manifest_content =
"set name=pkg.fmri value=pkg://test/pkgA@1.0\nset name=pkg.summary value=test\n";
// Manually write the manifest in IPS format to the source repo // Manually write the manifest in IPS format to the source repo
let manifest_path = FileBackend::construct_manifest_path(source_dir.path(), "test", "pkgA", "1.0"); let manifest_path =
std::fs::create_dir_all(manifest_path.parent().unwrap()).map_err(RepositoryError::IoError)?; FileBackend::construct_manifest_path(source_dir.path(), "test", "pkgA", "1.0");
std::fs::create_dir_all(manifest_path.parent().unwrap())
.map_err(RepositoryError::IoError)?;
std::fs::write(&manifest_path, manifest_content).map_err(RepositoryError::IoError)?; std::fs::write(&manifest_path, manifest_content).map_err(RepositoryError::IoError)?;
// Rebuild source repo to recognize the package // Rebuild source repo to recognize the package
@ -264,8 +322,10 @@ mod tests {
receiver.receive(Some("test"), &[Fmri::new("pkgA")], false)?; receiver.receive(Some("test"), &[Fmri::new("pkgA")], false)?;
// Verify dest repo has the package and the manifest is in IPS format // Verify dest repo has the package and the manifest is in IPS format
let dest_manifest_path = FileBackend::construct_manifest_path(dest_dir.path(), "test", "pkgA", "1.0"); let dest_manifest_path =
let content = std::fs::read_to_string(&dest_manifest_path).map_err(RepositoryError::IoError)?; FileBackend::construct_manifest_path(dest_dir.path(), "test", "pkgA", "1.0");
let content =
std::fs::read_to_string(&dest_manifest_path).map_err(RepositoryError::IoError)?;
assert_eq!(content, manifest_content); assert_eq!(content, manifest_content);
assert!(!content.starts_with('{'), "Manifest should not be JSON"); assert!(!content.starts_with('{'), "Manifest should not be JSON");
@ -275,9 +335,16 @@ mod tests {
let mut filename = json_path.file_name().unwrap().to_os_string(); let mut filename = json_path.file_name().unwrap().to_os_string();
filename.push(".json"); filename.push(".json");
json_path.set_file_name(filename); json_path.set_file_name(filename);
assert!(json_path.exists(), "JSON manifest should exist at {}", json_path.display()); assert!(
json_path.exists(),
"JSON manifest should exist at {}",
json_path.display()
);
let json_content = std::fs::read_to_string(&json_path).map_err(RepositoryError::IoError)?; let json_content = std::fs::read_to_string(&json_path).map_err(RepositoryError::IoError)?;
assert!(json_content.starts_with('{'), "JSON manifest should be JSON"); assert!(
json_content.starts_with('{'),
"JSON manifest should be JSON"
);
Ok(()) Ok(())
} }

View file

@ -1593,11 +1593,7 @@ impl ReadableRepository for FileBackend {
))) )))
} }
fn fetch_manifest_text( fn fetch_manifest_text(&mut self, publisher: &str, fmri: &Fmri) -> Result<String> {
&mut self,
publisher: &str,
fmri: &Fmri,
) -> Result<String> {
// Require a concrete version // Require a concrete version
let version = fmri.version(); let version = fmri.version();
if version.is_empty() { if version.is_empty() {
@ -1609,10 +1605,7 @@ impl ReadableRepository for FileBackend {
let path = Self::construct_manifest_path(&self.path, publisher, fmri.stem(), &version); let path = Self::construct_manifest_path(&self.path, publisher, fmri.stem(), &version);
if path.exists() { if path.exists() {
return std::fs::read_to_string(&path) return std::fs::read_to_string(&path)
.map_err(|e| RepositoryError::FileReadError { .map_err(|e| RepositoryError::FileReadError { path, source: e });
path,
source: e,
});
} }
// Fallbacks: global pkg layout without publisher // Fallbacks: global pkg layout without publisher
let encoded_stem = Self::url_encode(fmri.stem()); let encoded_stem = Self::url_encode(fmri.stem());

View file

@ -385,11 +385,7 @@ pub trait ReadableRepository {
) -> Result<crate::actions::Manifest>; ) -> Result<crate::actions::Manifest>;
/// Fetch a package manifest as raw text by FMRI from the repository. /// Fetch a package manifest as raw text by FMRI from the repository.
fn fetch_manifest_text( fn fetch_manifest_text(&mut self, publisher: &str, fmri: &crate::fmri::Fmri) -> Result<String>;
&mut self,
publisher: &str,
fmri: &crate::fmri::Fmri,
) -> Result<String>;
/// Search for packages in the repository /// Search for packages in the repository
/// ///

View file

@ -64,7 +64,11 @@ impl WritableRepository for RestBackend {
// This is a stub implementation // This is a stub implementation
// In a real implementation, we would make a REST API call to create the repository // In a real implementation, we would make a REST API call to create the repository
let uri_str = uri.as_ref().to_string_lossy().trim_end_matches('/').to_string(); let uri_str = uri
.as_ref()
.to_string_lossy()
.trim_end_matches('/')
.to_string();
// Create the repository configuration // Create the repository configuration
let config = RepositoryConfig { let config = RepositoryConfig {
@ -323,7 +327,11 @@ impl WritableRepository for RestBackend {
impl ReadableRepository for RestBackend { impl ReadableRepository for RestBackend {
/// Open an existing repository /// Open an existing repository
fn open<P: AsRef<Path>>(uri: P) -> Result<Self> { fn open<P: AsRef<Path>>(uri: P) -> Result<Self> {
let uri_str = uri.as_ref().to_string_lossy().trim_end_matches('/').to_string(); let uri_str = uri
.as_ref()
.to_string_lossy()
.trim_end_matches('/')
.to_string();
// Create an HTTP client // Create an HTTP client
let client = Client::new(); let client = Client::new();
@ -444,14 +452,20 @@ impl ReadableRepository for RestBackend {
return Ok(Vec::new()); return Ok(Vec::new());
} }
Err(e) => { Err(e) => {
return Err(RepositoryError::Other(format!("Search API error: {} for {}", e, url))); return Err(RepositoryError::Other(format!(
"Search API error: {} for {}",
e, url
)));
} }
}; };
let reader = BufReader::new(resp); let reader = BufReader::new(resp);
for line in reader.lines() { for line in reader.lines() {
let line = line.map_err(|e| { let line = line.map_err(|e| {
RepositoryError::Other(format!("Failed to read search response line: {}", e)) RepositoryError::Other(format!(
"Failed to read search response line: {}",
e
))
})?; })?;
// Line format: <attr> <fmri> <value_type> <value> // Line format: <attr> <fmri> <value_type> <value>
// Example: pkg.fmri pkg:/system/rsyslog@8.2508.0,5.11-151056.0:20251023T180542Z set omnios/system/rsyslog // Example: pkg.fmri pkg:/system/rsyslog@8.2508.0,5.11-151056.0:20251023T180542Z set omnios/system/rsyslog
@ -681,11 +695,7 @@ impl ReadableRepository for RestBackend {
todo!() todo!()
} }
fn fetch_manifest_text( fn fetch_manifest_text(&mut self, publisher: &str, fmri: &crate::fmri::Fmri) -> Result<String> {
&mut self,
publisher: &str,
fmri: &crate::fmri::Fmri,
) -> Result<String> {
// Require versioned FMRI // Require versioned FMRI
let version = fmri.version(); let version = fmri.version();
if version.is_empty() { if version.is_empty() {

View file

@ -69,8 +69,8 @@ async fn get_publisher_response(
}], }],
version: 1, version: 1,
}; };
let json = let json = serde_json::to_string_pretty(&p5i)
serde_json::to_string_pretty(&p5i).map_err(|e| DepotError::Server(e.to_string()))?; .map_err(|e| DepotError::Server(e.to_string()))?;
Ok(([(header::CONTENT_TYPE, "application/vnd.pkg5.info")], json).into_response()) Ok(([(header::CONTENT_TYPE, "application/vnd.pkg5.info")], json).into_response())
} else { } else {
Err(DepotError::Repo( Err(DepotError::Repo(

View file

@ -38,9 +38,15 @@ pub fn app_router(state: Arc<DepotRepo>) -> Router {
) )
.route("/{publisher}/info/0/{fmri}", get(info::get_info)) .route("/{publisher}/info/0/{fmri}", get(info::get_info))
.route("/{publisher}/publisher/0", get(publisher::get_publisher_v0)) .route("/{publisher}/publisher/0", get(publisher::get_publisher_v0))
.route("/{publisher}/publisher/0/", get(publisher::get_publisher_v0)) .route(
"/{publisher}/publisher/0/",
get(publisher::get_publisher_v0),
)
.route("/{publisher}/publisher/1", get(publisher::get_publisher_v1)) .route("/{publisher}/publisher/1", get(publisher::get_publisher_v1))
.route("/{publisher}/publisher/1/", get(publisher::get_publisher_v1)) .route(
"/{publisher}/publisher/1/",
get(publisher::get_publisher_v1),
)
.route("/publisher/0", get(publisher::get_default_publisher_v0)) .route("/publisher/0", get(publisher::get_default_publisher_v0))
.route("/publisher/0/", get(publisher::get_default_publisher_v0)) .route("/publisher/0/", get(publisher::get_default_publisher_v0))
.route("/publisher/1", get(publisher::get_default_publisher_v1)) .route("/publisher/1", get(publisher::get_default_publisher_v1))

View file

@ -476,7 +476,10 @@ async fn test_multiple_publishers_default_route() {
// DESIRED BEHAVIOR: returns 2 // DESIRED BEHAVIOR: returns 2
assert_eq!(pubs.len(), 2, "Should return all publishers"); assert_eq!(pubs.len(), 2, "Should return all publishers");
let names: Vec<String> = pubs.iter().map(|p| p["name"].as_str().unwrap().to_string()).collect(); let names: Vec<String> = pubs
.iter()
.map(|p| p["name"].as_str().unwrap().to_string())
.collect();
assert!(names.contains(&"pub1".to_string())); assert!(names.contains(&"pub1".to_string()));
assert!(names.contains(&"pub2".to_string())); assert!(names.contains(&"pub2".to_string()));
} }

View file

@ -1,8 +1,10 @@
use clap::Parser; use clap::Parser;
use miette::{IntoDiagnostic, Result};
use libips::repository::{FileBackend, RestBackend, ReadableRepository, ProgressReporter, ProgressInfo};
use libips::recv::PackageReceiver;
use libips::fmri::Fmri; use libips::fmri::Fmri;
use libips::recv::PackageReceiver;
use libips::repository::{
FileBackend, ProgressInfo, ProgressReporter, ReadableRepository, RestBackend,
};
use miette::{IntoDiagnostic, Result};
use std::path::PathBuf; use std::path::PathBuf;
use tracing::info; use tracing::info;
use tracing_subscriber::{EnvFilter, fmt}; use tracing_subscriber::{EnvFilter, fmt};
@ -56,7 +58,9 @@ fn main() -> Result<()> {
// Open destination repository // Open destination repository
// We'll open it inside each branch to avoid borrow checker issues with moves // We'll open it inside each branch to avoid borrow checker issues with moves
let fmris: Vec<Fmri> = cli.packages.iter() let fmris: Vec<Fmri> = cli
.packages
.iter()
.map(|s| Fmri::parse(s)) .map(|s| Fmri::parse(s))
.collect::<std::result::Result<Vec<_>, _>>() .collect::<std::result::Result<Vec<_>, _>>()
.into_diagnostic()?; .into_diagnostic()?;
@ -69,13 +73,17 @@ fn main() -> Result<()> {
let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?; let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?;
let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo); let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo);
receiver = receiver.with_progress(&progress); receiver = receiver.with_progress(&progress);
receiver.receive(cli.publisher.as_deref(), &fmris, cli.recursive).into_diagnostic()?; receiver
.receive(cli.publisher.as_deref(), &fmris, cli.recursive)
.into_diagnostic()?;
} else { } else {
let mut source_repo = FileBackend::open(&cli.source).into_diagnostic()?; let mut source_repo = FileBackend::open(&cli.source).into_diagnostic()?;
let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?; let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?;
let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo); let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo);
receiver = receiver.with_progress(&progress); receiver = receiver.with_progress(&progress);
receiver.receive(cli.publisher.as_deref(), &fmris, cli.recursive).into_diagnostic()?; receiver
.receive(cli.publisher.as_deref(), &fmris, cli.recursive)
.into_diagnostic()?;
} }
info!("Package receive complete."); info!("Package receive complete.");

View file

@ -131,7 +131,12 @@ fn main() -> Result<()> {
tracing_subscriber::fmt().with_env_filter(env_filter).init(); tracing_subscriber::fmt().with_env_filter(env_filter).init();
// Load image // Load image
let image = Image::load(&cli.image_path).map_err(|e| PkgTreeError(format!("Failed to load image at {:?}: {}", cli.image_path, e)))?; let image = Image::load(&cli.image_path).map_err(|e| {
PkgTreeError(format!(
"Failed to load image at {:?}: {}",
cli.image_path, e
))
})?;
// Targeted analysis of solver error file has top priority if provided // Targeted analysis of solver error file has top priority if provided
if let Some(err_path) = &cli.solver_error_file { if let Some(err_path) = &cli.solver_error_file {
@ -164,7 +169,9 @@ fn main() -> Result<()> {
.query_catalog(Some(needle.as_str())) .query_catalog(Some(needle.as_str()))
.map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))? .map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))?
} else { } else {
image.query_catalog(None).map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))? image
.query_catalog(None)
.map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))?
}; };
// Filter by publisher if specified // Filter by publisher if specified
@ -765,7 +772,10 @@ fn query_catalog_cached_mut(
return Ok(v.clone()); return Ok(v.clone());
} }
let mut out = Vec::new(); let mut out = Vec::new();
for p in image.query_catalog(Some(stem)).map_err(|e| PkgTreeError(format!("Failed to query catalog for {}: {}", stem, e)))? { for p in image
.query_catalog(Some(stem))
.map_err(|e| PkgTreeError(format!("Failed to query catalog for {}: {}", stem, e)))?
{
out.push((p.publisher, p.fmri)); out.push((p.publisher, p.fmri));
} }
ctx.catalog_cache.insert(stem.to_string(), out.clone()); ctx.catalog_cache.insert(stem.to_string(), out.clone());
@ -781,9 +791,13 @@ fn get_manifest_cached(
if let Some(m) = ctx.manifest_cache.get(&key) { if let Some(m) = ctx.manifest_cache.get(&key) {
return Ok(m.clone()); return Ok(m.clone());
} }
let manifest_opt = image let manifest_opt = image.get_manifest_from_catalog(fmri).map_err(|e| {
.get_manifest_from_catalog(fmri) PkgTreeError(format!(
.map_err(|e| PkgTreeError(format!("Failed to load manifest for {}: {}", fmri.to_string(), e)))?; "Failed to load manifest for {}: {}",
fmri.to_string(),
e
))
})?;
let manifest = manifest_opt.unwrap_or_else(|| libips::actions::Manifest::new()); let manifest = manifest_opt.unwrap_or_else(|| libips::actions::Manifest::new());
ctx.manifest_cache.insert(key, manifest.clone()); ctx.manifest_cache.insert(key, manifest.clone());
Ok(manifest) Ok(manifest)
@ -1018,7 +1032,9 @@ fn run_dangling_scan(
format: OutputFormat, format: OutputFormat,
) -> Result<()> { ) -> Result<()> {
// Query full catalog once // Query full catalog once
let mut pkgs = image.query_catalog(None).map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))?; let mut pkgs = image
.query_catalog(None)
.map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))?;
// Build set of available non-obsolete stems AND an index of available (release, branch) pairs per stem, // Build set of available non-obsolete stems AND an index of available (release, branch) pairs per stem,
// honoring publisher filter // honoring publisher filter
@ -1188,7 +1204,12 @@ fn run_dangling_scan(
// ---------- Targeted analysis: parse pkg6 solver error text ---------- // ---------- Targeted analysis: parse pkg6 solver error text ----------
fn analyze_solver_error(image: &Image, publisher: Option<&str>, err_path: &PathBuf) -> Result<()> { fn analyze_solver_error(image: &Image, publisher: Option<&str>, err_path: &PathBuf) -> Result<()> {
let text = std::fs::read_to_string(err_path).map_err(|e| PkgTreeError(format!("Failed to read solver error file {:?}: {}", err_path, e)))?; let text = std::fs::read_to_string(err_path).map_err(|e| {
PkgTreeError(format!(
"Failed to read solver error file {:?}: {}",
err_path, e
))
})?;
// Build a stack based on indentation before the tree bullet "└─". // Build a stack based on indentation before the tree bullet "└─".
let mut stack: Vec<String> = Vec::new(); let mut stack: Vec<String> = Vec::new();

View file

@ -262,11 +262,7 @@ fn fmt() -> Result<()> {
/// Run clippy /// Run clippy
fn clippy() -> Result<()> { fn clippy() -> Result<()> {
Command::new("cargo") Command::new("cargo")
.args([ .args(["clippy", "--all-targets", "--all-features"])
"clippy",
"--all-targets",
"--all-features",
])
.status() .status()
.context("Failed to run clippy")?; .context("Failed to run clippy")?;