mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
chore(format): format code
This commit is contained in:
parent
e7dc9d5a4c
commit
4ab529f4c7
11 changed files with 210 additions and 107 deletions
|
|
@ -635,7 +635,10 @@ impl Resolver {
|
|||
// Helper: extract the package FMRI from a manifest's attributes
|
||||
fn manifest_fmri(manifest: &Manifest) -> Option<Fmri> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,15 @@
|
|||
// MPL was not distributed with this file, You can
|
||||
// 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::fmri::Fmri;
|
||||
use crate::repository::{
|
||||
FileBackend, NoopProgressReporter, ProgressInfo, ProgressReporter, ReadableRepository,
|
||||
RepositoryError, Result, WritableRepository,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
use tempfile::tempdir;
|
||||
use tracing::{info, debug};
|
||||
use tracing::{debug, info};
|
||||
|
||||
/// PackageReceiver handles downloading packages from a source 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> {
|
||||
/// Create a new PackageReceiver
|
||||
pub fn new(source: &'a mut S, dest: FileBackend) -> Self {
|
||||
Self { source, dest, progress: None }
|
||||
Self {
|
||||
source,
|
||||
dest,
|
||||
progress: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// * `fmris` - List of FMRIs to receive
|
||||
/// * `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 queue: Vec<Fmri> = fmris.to_vec();
|
||||
let mut updated_publishers = HashSet::new();
|
||||
|
|
@ -53,36 +65,55 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
while let Some(fmri) = queue.pop() {
|
||||
// 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 publisher = fmri.publisher.as_deref().or(default_publisher).ok_or_else(|| {
|
||||
RepositoryError::Other(format!("No publisher specified for package {}", fmri.name))
|
||||
})?;
|
||||
let publisher =
|
||||
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);
|
||||
|
||||
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
|
||||
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 {
|
||||
by_name.entry(pi.fmri.name.clone()).or_default().push(pi);
|
||||
}
|
||||
|
||||
let mut results = Vec::new();
|
||||
for (name, versions) in by_name {
|
||||
let newest = versions.into_iter().max_by(|a, b| {
|
||||
a.fmri.to_string().cmp(&b.fmri.to_string())
|
||||
});
|
||||
let newest = versions
|
||||
.into_iter()
|
||||
.max_by(|a, b| a.fmri.to_string().cmp(&b.fmri.to_string()));
|
||||
if let Some(pi) = newest {
|
||||
results.push(pi.fmri);
|
||||
} 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() {
|
||||
info!("Package {} not found in source for publisher {}", fmri.name, publisher);
|
||||
info!(
|
||||
"Package {} not found in source for publisher {}",
|
||||
fmri.name, publisher
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// 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 {
|
||||
let publisher_name = fmri_to_fetch.publisher.as_deref().or(default_publisher).ok_or_else(|| {
|
||||
RepositoryError::Other(format!("No publisher specified for package {}", fmri_to_fetch.name))
|
||||
})?.to_string();
|
||||
let publisher_name = fmri_to_fetch
|
||||
.publisher
|
||||
.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 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));
|
||||
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)?;
|
||||
updated_publishers.insert(publisher_name.clone());
|
||||
|
||||
|
|
@ -121,10 +163,10 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
if dep_fmri.publisher.is_none() {
|
||||
dep_fmri.publisher = Some(publisher_name.clone());
|
||||
}
|
||||
|
||||
|
||||
if !processed.contains(&dep_fmri) && queued.insert(dep_fmri.clone()) {
|
||||
total_packages += 1;
|
||||
queue.push(dep_fmri);
|
||||
total_packages += 1;
|
||||
queue.push(dep_fmri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +176,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
|
||||
for pub_name in updated_publishers {
|
||||
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);
|
||||
self.dest.rebuild(Some(&pub_name), false, false)?;
|
||||
}
|
||||
|
|
@ -147,10 +190,11 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
/// Receive a single package
|
||||
fn receive_one(&mut self, publisher: &str, fmri: &Fmri) -> Result<Manifest> {
|
||||
let progress = self.progress.unwrap_or(&NoopProgressReporter);
|
||||
|
||||
|
||||
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
|
||||
let dest_info = self.dest.get_info()?;
|
||||
if !dest_info.publishers.iter().any(|p| p.name == publisher) {
|
||||
|
|
@ -163,30 +207,41 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
txn.set_legacy_manifest(manifest_text);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
for (i, file) in payload_files.into_iter().enumerate() {
|
||||
if let Some(payload) = &file.payload {
|
||||
let files_done = (i + 1) as u64;
|
||||
let digest = &payload.primary_identifier.hash;
|
||||
|
||||
progress.update(&ProgressInfo::new(format!("Receiving payloads for {}", fmri.name))
|
||||
.with_total(total_files)
|
||||
.with_current(files_done)
|
||||
.with_context(format!("Payload: {}", digest)));
|
||||
|
||||
progress.update(
|
||||
&ProgressInfo::new(format!("Receiving payloads for {}", fmri.name))
|
||||
.with_total(total_files)
|
||||
.with_current(files_done)
|
||||
.with_context(format!("Payload: {}", digest)),
|
||||
);
|
||||
|
||||
let temp_file_path = temp_dir.path().join(digest);
|
||||
debug!("Fetching payload {} to {}", digest, temp_file_path.display());
|
||||
self.source.fetch_payload(publisher, digest, &temp_file_path)?;
|
||||
debug!(
|
||||
"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.update_manifest(manifest.clone());
|
||||
txn.commit()?;
|
||||
|
||||
|
||||
Ok(manifest)
|
||||
}
|
||||
}
|
||||
|
|
@ -194,8 +249,8 @@ impl<'a, S: ReadableRepository> PackageReceiver<'a, S> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::repository::{FileBackend, RepositoryVersion};
|
||||
use crate::actions::Attr;
|
||||
use crate::repository::{FileBackend, RepositoryVersion};
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
|
|
@ -206,7 +261,7 @@ mod tests {
|
|||
// Create source repo with one package
|
||||
let mut source_repo = FileBackend::create(source_dir.path(), RepositoryVersion::V4)?;
|
||||
source_repo.add_publisher("test")?;
|
||||
|
||||
|
||||
let fmri = Fmri::parse("pkg://test/pkgA@1.0").unwrap();
|
||||
let mut manifest = Manifest::new();
|
||||
manifest.attributes.push(Attr {
|
||||
|
|
@ -245,15 +300,18 @@ mod tests {
|
|||
// Create source repo
|
||||
let mut source_repo = FileBackend::create(source_dir.path(), RepositoryVersion::V4)?;
|
||||
source_repo.add_publisher("test")?;
|
||||
|
||||
|
||||
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
|
||||
let manifest_path = FileBackend::construct_manifest_path(source_dir.path(), "test", "pkgA", "1.0");
|
||||
std::fs::create_dir_all(manifest_path.parent().unwrap()).map_err(RepositoryError::IoError)?;
|
||||
let manifest_path =
|
||||
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)?;
|
||||
|
||||
|
||||
// Rebuild source repo to recognize the package
|
||||
source_repo.rebuild(Some("test"), false, false)?;
|
||||
|
||||
|
|
@ -264,9 +322,11 @@ mod tests {
|
|||
receiver.receive(Some("test"), &[Fmri::new("pkgA")], false)?;
|
||||
|
||||
// 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 content = std::fs::read_to_string(&dest_manifest_path).map_err(RepositoryError::IoError)?;
|
||||
|
||||
let dest_manifest_path =
|
||||
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!(!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();
|
||||
filename.push(".json");
|
||||
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)?;
|
||||
assert!(json_content.starts_with('{'), "JSON manifest should be JSON");
|
||||
assert!(
|
||||
json_content.starts_with('{'),
|
||||
"JSON manifest should be JSON"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1593,11 +1593,7 @@ impl ReadableRepository for FileBackend {
|
|||
)))
|
||||
}
|
||||
|
||||
fn fetch_manifest_text(
|
||||
&mut self,
|
||||
publisher: &str,
|
||||
fmri: &Fmri,
|
||||
) -> Result<String> {
|
||||
fn fetch_manifest_text(&mut self, publisher: &str, fmri: &Fmri) -> Result<String> {
|
||||
// Require a concrete version
|
||||
let version = fmri.version();
|
||||
if version.is_empty() {
|
||||
|
|
@ -1609,10 +1605,7 @@ impl ReadableRepository for FileBackend {
|
|||
let path = Self::construct_manifest_path(&self.path, publisher, fmri.stem(), &version);
|
||||
if path.exists() {
|
||||
return std::fs::read_to_string(&path)
|
||||
.map_err(|e| RepositoryError::FileReadError {
|
||||
path,
|
||||
source: e,
|
||||
});
|
||||
.map_err(|e| RepositoryError::FileReadError { path, source: e });
|
||||
}
|
||||
// Fallbacks: global pkg layout without publisher
|
||||
let encoded_stem = Self::url_encode(fmri.stem());
|
||||
|
|
|
|||
|
|
@ -385,11 +385,7 @@ pub trait ReadableRepository {
|
|||
) -> Result<crate::actions::Manifest>;
|
||||
|
||||
/// Fetch a package manifest as raw text by FMRI from the repository.
|
||||
fn fetch_manifest_text(
|
||||
&mut self,
|
||||
publisher: &str,
|
||||
fmri: &crate::fmri::Fmri,
|
||||
) -> Result<String>;
|
||||
fn fetch_manifest_text(&mut self, publisher: &str, fmri: &crate::fmri::Fmri) -> Result<String>;
|
||||
|
||||
/// Search for packages in the repository
|
||||
///
|
||||
|
|
|
|||
|
|
@ -64,7 +64,11 @@ impl WritableRepository for RestBackend {
|
|||
// This is a stub implementation
|
||||
// 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
|
||||
let config = RepositoryConfig {
|
||||
|
|
@ -323,7 +327,11 @@ impl WritableRepository for RestBackend {
|
|||
impl ReadableRepository for RestBackend {
|
||||
/// Open an existing repository
|
||||
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
|
||||
let client = Client::new();
|
||||
|
|
@ -444,14 +452,20 @@ impl ReadableRepository for RestBackend {
|
|||
return Ok(Vec::new());
|
||||
}
|
||||
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);
|
||||
for line in reader.lines() {
|
||||
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>
|
||||
// Example: pkg.fmri pkg:/system/rsyslog@8.2508.0,5.11-151056.0:20251023T180542Z set omnios/system/rsyslog
|
||||
|
|
@ -621,7 +635,7 @@ impl ReadableRepository for RestBackend {
|
|||
// Write atomically
|
||||
let tmp_path = dest.with_extension("tmp");
|
||||
let mut tmp_file = File::create(&tmp_path)?;
|
||||
|
||||
|
||||
std::io::copy(&mut resp, &mut tmp_file).map_err(|e| {
|
||||
RepositoryError::Other(format!("Failed to download payload: {}", e))
|
||||
})?;
|
||||
|
|
@ -681,11 +695,7 @@ impl ReadableRepository for RestBackend {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn fetch_manifest_text(
|
||||
&mut self,
|
||||
publisher: &str,
|
||||
fmri: &crate::fmri::Fmri,
|
||||
) -> Result<String> {
|
||||
fn fetch_manifest_text(&mut self, publisher: &str, fmri: &crate::fmri::Fmri) -> Result<String> {
|
||||
// Require versioned FMRI
|
||||
let version = fmri.version();
|
||||
if version.is_empty() {
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ async fn get_publisher_response(
|
|||
}],
|
||||
version: 1,
|
||||
};
|
||||
let json =
|
||||
serde_json::to_string_pretty(&p5i).map_err(|e| DepotError::Server(e.to_string()))?;
|
||||
let json = serde_json::to_string_pretty(&p5i)
|
||||
.map_err(|e| DepotError::Server(e.to_string()))?;
|
||||
Ok(([(header::CONTENT_TYPE, "application/vnd.pkg5.info")], json).into_response())
|
||||
} else {
|
||||
Err(DepotError::Repo(
|
||||
|
|
|
|||
|
|
@ -38,9 +38,15 @@ pub fn app_router(state: Arc<DepotRepo>) -> Router {
|
|||
)
|
||||
.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/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/1", get(publisher::get_default_publisher_v1))
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ async fn test_depot_server() {
|
|||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
assert_eq!(pub_json["version"], 1);
|
||||
assert_eq!(pub_json["publishers"][0]["name"], "test");
|
||||
|
||||
|
||||
// Test Default Publisher Route v1
|
||||
let def_pub_url = format!("{}/publisher/1", base_url);
|
||||
let resp = client.get(&def_pub_url).send().await.unwrap();
|
||||
|
|
@ -427,10 +427,10 @@ async fn test_multiple_publishers_default_route() {
|
|||
let temp_dir = TempDir::new().unwrap();
|
||||
let repo_path = temp_dir.path().join("repo_multi");
|
||||
let mut backend = FileBackend::create(&repo_path, RepositoryVersion::V4).unwrap();
|
||||
|
||||
|
||||
backend.add_publisher("pub1").unwrap();
|
||||
backend.add_publisher("pub2").unwrap();
|
||||
|
||||
|
||||
let config = Config {
|
||||
server: ServerConfig {
|
||||
bind: vec!["127.0.0.1:0".to_string()],
|
||||
|
|
@ -471,12 +471,15 @@ async fn test_multiple_publishers_default_route() {
|
|||
|
||||
let pub_json: serde_json::Value = resp.json().await.unwrap();
|
||||
let pubs = pub_json["publishers"].as_array().unwrap();
|
||||
|
||||
|
||||
// CURRENT BEHAVIOR: returns 1
|
||||
// DESIRED BEHAVIOR: returns 2
|
||||
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(&"pub2".to_string()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
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::recv::PackageReceiver;
|
||||
use libips::repository::{
|
||||
FileBackend, ProgressInfo, ProgressReporter, ReadableRepository, RestBackend,
|
||||
};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use std::path::PathBuf;
|
||||
use tracing::info;
|
||||
use tracing_subscriber::{EnvFilter, fmt};
|
||||
|
|
@ -56,7 +58,9 @@ fn main() -> Result<()> {
|
|||
// Open destination repository
|
||||
// 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))
|
||||
.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.into_diagnostic()?;
|
||||
|
|
@ -69,13 +73,17 @@ fn main() -> Result<()> {
|
|||
let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?;
|
||||
let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo);
|
||||
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 {
|
||||
let mut source_repo = FileBackend::open(&cli.source).into_diagnostic()?;
|
||||
let dest_repo = FileBackend::open(&cli.dest).into_diagnostic()?;
|
||||
let mut receiver = PackageReceiver::new(&mut source_repo, dest_repo);
|
||||
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.");
|
||||
|
|
|
|||
|
|
@ -131,7 +131,12 @@ fn main() -> Result<()> {
|
|||
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||
|
||||
// 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
|
||||
if let Some(err_path) = &cli.solver_error_file {
|
||||
|
|
@ -164,7 +169,9 @@ fn main() -> Result<()> {
|
|||
.query_catalog(Some(needle.as_str()))
|
||||
.map_err(|e| PkgTreeError(format!("Failed to query catalog: {}", e)))?
|
||||
} 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
|
||||
|
|
@ -765,7 +772,10 @@ fn query_catalog_cached_mut(
|
|||
return Ok(v.clone());
|
||||
}
|
||||
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));
|
||||
}
|
||||
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) {
|
||||
return Ok(m.clone());
|
||||
}
|
||||
let manifest_opt = image
|
||||
.get_manifest_from_catalog(fmri)
|
||||
.map_err(|e| PkgTreeError(format!("Failed to load manifest for {}: {}", fmri.to_string(), e)))?;
|
||||
let manifest_opt = image.get_manifest_from_catalog(fmri).map_err(|e| {
|
||||
PkgTreeError(format!(
|
||||
"Failed to load manifest for {}: {}",
|
||||
fmri.to_string(),
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let manifest = manifest_opt.unwrap_or_else(|| libips::actions::Manifest::new());
|
||||
ctx.manifest_cache.insert(key, manifest.clone());
|
||||
Ok(manifest)
|
||||
|
|
@ -1018,7 +1032,9 @@ fn run_dangling_scan(
|
|||
format: OutputFormat,
|
||||
) -> Result<()> {
|
||||
// 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,
|
||||
// honoring publisher filter
|
||||
|
|
@ -1188,7 +1204,12 @@ fn run_dangling_scan(
|
|||
|
||||
// ---------- Targeted analysis: parse pkg6 solver error text ----------
|
||||
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 "└─".
|
||||
let mut stack: Vec<String> = Vec::new();
|
||||
|
|
|
|||
|
|
@ -262,11 +262,7 @@ fn fmt() -> Result<()> {
|
|||
/// Run clippy
|
||||
fn clippy() -> Result<()> {
|
||||
Command::new("cargo")
|
||||
.args([
|
||||
"clippy",
|
||||
"--all-targets",
|
||||
"--all-features",
|
||||
])
|
||||
.args(["clippy", "--all-targets", "--all-features"])
|
||||
.status()
|
||||
.context("Failed to run clippy")?;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue