mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
Refactor package FMRI handling by introducing Fmri struct, update dependencies, and adjust repository and action modules for structured FMRI data processing
Signed-off-by: Till Wegmueller <toasterson@gmail.com>
This commit is contained in:
parent
2e69b277ed
commit
5d987ca0cb
9 changed files with 1101 additions and 49 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -722,6 +722,7 @@ dependencies = [
|
|||
"pest",
|
||||
"pest_derive",
|
||||
"regex",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
|
|
@ -1348,9 +1349,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.17"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pest_derive = "2.1.0"
|
|||
strum = { version = "0.24.1", features = ["derive"] }
|
||||
serde = { version = "1.0.207", features = ["derive"] }
|
||||
serde_json = "1.0.124"
|
||||
diff-struct = "0.5.3"
|
||||
flate2 = "1.0.28"
|
||||
lz4 = "1.24.0"
|
||||
semver = { version = "1.0.20", features = ["serde"] }
|
||||
diff-struct = "0.5.3"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
// Source https://docs.oracle.com/cd/E23824_01/html/E21796/pkg-5.html
|
||||
|
||||
use crate::digest::Digest;
|
||||
use crate::fmri::Fmri;
|
||||
use crate::payload::{Payload, PayloadError};
|
||||
use pest::Parser;
|
||||
use pest_derive::Parser;
|
||||
|
|
@ -267,9 +268,9 @@ pub enum FileError {
|
|||
#[derive(Debug, PartialEq)]
|
||||
))]
|
||||
pub struct Dependency {
|
||||
pub fmri: String, //TODO make FMRI
|
||||
pub fmri: Option<Fmri>, // FMRI of the dependency
|
||||
pub dependency_type: String, //TODO make enum
|
||||
pub predicate: String, //TODO make FMRI
|
||||
pub predicate: Option<Fmri>, // FMRI for conditional dependencies
|
||||
pub root_image: String, //TODO make boolean
|
||||
pub optional: Vec<Property>,
|
||||
pub facets: HashMap<String, Facet>,
|
||||
|
|
@ -288,9 +289,25 @@ impl From<Action> for Dependency {
|
|||
}
|
||||
for prop in props {
|
||||
match prop.key.as_str() {
|
||||
"fmri" => dep.fmri = prop.value,
|
||||
"fmri" => {
|
||||
match Fmri::parse(&prop.value) {
|
||||
Ok(fmri) => dep.fmri = Some(fmri),
|
||||
Err(err) => {
|
||||
eprintln!("Error parsing FMRI '{}': {}", prop.value, err);
|
||||
dep.fmri = None;
|
||||
}
|
||||
}
|
||||
},
|
||||
"type" => dep.dependency_type = prop.value,
|
||||
"predicate" => dep.predicate = prop.value,
|
||||
"predicate" => {
|
||||
match Fmri::parse(&prop.value) {
|
||||
Ok(fmri) => dep.predicate = Some(fmri),
|
||||
Err(err) => {
|
||||
eprintln!("Error parsing predicate FMRI '{}': {}", prop.value, err);
|
||||
dep.predicate = None;
|
||||
}
|
||||
}
|
||||
},
|
||||
"root-image" => dep.root_image = prop.value,
|
||||
_ => {
|
||||
if is_facet(prop.key.clone()) {
|
||||
|
|
|
|||
1001
libips/src/fmri.rs
Normal file
1001
libips/src/fmri.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -6,6 +6,7 @@
|
|||
#[allow(clippy::result_large_err)]
|
||||
pub mod actions;
|
||||
pub mod digest;
|
||||
pub mod fmri;
|
||||
pub mod payload;
|
||||
pub mod image;
|
||||
pub mod repository;
|
||||
|
|
@ -16,6 +17,7 @@ mod tests {
|
|||
use crate::actions::Attr;
|
||||
use crate::actions::{Dependency, Dir, Facet, File, Link, Manifest, Property};
|
||||
use crate::digest::{Digest, DigestAlgorithm, DigestSource};
|
||||
use crate::fmri::Fmri;
|
||||
use crate::payload::Payload;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
|
@ -980,18 +982,17 @@ depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1
|
|||
|
||||
let test_results = vec![
|
||||
Dependency {
|
||||
fmri: "pkg:/system/library@0.5.11-2020.0.1.19563".to_string(),
|
||||
fmri: Some(Fmri::parse("pkg:/system/library@0.5.11-2020.0.1.19563").unwrap()),
|
||||
dependency_type: "require".to_string(),
|
||||
..Dependency::default()
|
||||
},
|
||||
Dependency {
|
||||
fmri: "pkg:/system/file-system/nfs@0.5.11,5.11-2020.0.1.19951".to_string(),
|
||||
fmri: Some(Fmri::parse("pkg:/system/file-system/nfs@0.5.11,5.11-2020.0.1.19951").unwrap()),
|
||||
dependency_type: "incorporate".to_string(),
|
||||
..Dependency::default()
|
||||
},
|
||||
Dependency {
|
||||
fmri: "pkg:/system/data/hardware-registry@2020.2.22,5.11-2020.0.1.19951"
|
||||
.to_string(),
|
||||
fmri: Some(Fmri::parse("pkg:/system/data/hardware-registry@2020.2.22,5.11-2020.0.1.19951").unwrap()),
|
||||
dependency_type: "incorporate".to_string(),
|
||||
facets: hashmap! {
|
||||
"version-lock.system/data/hardware-registry".to_string() => Facet{
|
||||
|
|
@ -1002,7 +1003,7 @@ depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1
|
|||
..Dependency::default()
|
||||
},
|
||||
Dependency {
|
||||
fmri: "xvm@0.5.11-2015.0.2.0".to_string(),
|
||||
fmri: Some(Fmri::parse("xvm@0.5.11-2015.0.2.0").unwrap()),
|
||||
dependency_type: "incorporate".to_string(),
|
||||
facets: hashmap! {
|
||||
"version-lock.xvm".to_string() => Facet{
|
||||
|
|
@ -1013,7 +1014,7 @@ depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1
|
|||
..Dependency::default()
|
||||
},
|
||||
Dependency {
|
||||
fmri: "system/mozilla-nss@3.51.1-2020.0.1.0".to_string(),
|
||||
fmri: Some(Fmri::parse("system/mozilla-nss@3.51.1-2020.0.1.0").unwrap()),
|
||||
dependency_type: "incorporate".to_string(),
|
||||
facets: hashmap! {
|
||||
"version-lock.system/mozilla-nss".to_string() => Facet{
|
||||
|
|
@ -1031,7 +1032,13 @@ depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1
|
|||
|
||||
assert_eq!(manifest.dependencies.len(), test_results.len());
|
||||
for (pos, dependency) in manifest.dependencies.iter().enumerate() {
|
||||
assert_eq!(dependency.fmri, test_results[pos].fmri);
|
||||
// Compare the string representation of the FMRIs
|
||||
if let (Some(dep_fmri), Some(test_fmri)) = (&dependency.fmri, &test_results[pos].fmri) {
|
||||
assert_eq!(dep_fmri.to_string(), test_fmri.to_string());
|
||||
} else {
|
||||
assert_eq!(dependency.fmri.is_none(), test_results[pos].fmri.is_none());
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
dependency.dependency_type,
|
||||
test_results[pos].dependency_type
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use regex::Regex;
|
|||
|
||||
use crate::actions::{Manifest, File as FileAction};
|
||||
use crate::digest::Digest;
|
||||
use crate::fmri::Fmri;
|
||||
use crate::payload::{Payload, PayloadCompressionAlgorithm};
|
||||
|
||||
use super::{Repository, RepositoryConfig, RepositoryVersion, REPOSITORY_CONFIG_FILENAME, PublisherInfo, RepositoryInfo, PackageInfo};
|
||||
|
|
@ -520,51 +521,51 @@ impl Repository for FileBackend {
|
|||
if attr.key == "pkg.fmri" && !attr.values.is_empty() {
|
||||
let fmri = &attr.values[0];
|
||||
|
||||
// Parse the FMRI to extract package name and version
|
||||
// Format: pkg://publisher/package_name@version
|
||||
if let Some(pkg_part) = fmri.strip_prefix("pkg://") {
|
||||
if let Some(at_pos) = pkg_part.find('@') {
|
||||
let pkg_with_pub = &pkg_part[0..at_pos];
|
||||
let version = &pkg_part[at_pos+1..];
|
||||
|
||||
// Extract package name (may include publisher)
|
||||
let pkg_name = if let Some(slash_pos) = pkg_with_pub.find('/') {
|
||||
// Skip publisher part if present
|
||||
let pub_end = slash_pos + 1;
|
||||
&pkg_with_pub[pub_end..]
|
||||
} else {
|
||||
pkg_with_pub
|
||||
};
|
||||
|
||||
// Parse the FMRI using our Fmri type
|
||||
match Fmri::parse(fmri) {
|
||||
Ok(parsed_fmri) => {
|
||||
// Filter by pattern if specified
|
||||
if let Some(pat) = pattern {
|
||||
// Try to compile the pattern as a regex
|
||||
match Regex::new(pat) {
|
||||
Ok(regex) => {
|
||||
// Use regex matching
|
||||
if !regex.is_match(pkg_name) {
|
||||
if !regex.is_match(&parsed_fmri.name) {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
// Log the error but fall back to simple string contains
|
||||
eprintln!("Error compiling regex pattern '{}': {}", pat, err);
|
||||
if !pkg_name.contains(pat) {
|
||||
if !parsed_fmri.name.contains(pat) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the publisher is not set in the FMRI, use the current publisher
|
||||
if parsed_fmri.publisher.is_none() {
|
||||
let mut fmri_with_publisher = parsed_fmri.clone();
|
||||
fmri_with_publisher.publisher = Some(pub_name.clone());
|
||||
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
name: pkg_name.to_string(),
|
||||
version: version.to_string(),
|
||||
publisher: pub_name.clone(),
|
||||
fmri: fmri_with_publisher,
|
||||
});
|
||||
} else {
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
fmri: parsed_fmri.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// Found the package info, no need to check other attributes
|
||||
break;
|
||||
},
|
||||
Err(err) => {
|
||||
// Log the error but continue processing
|
||||
eprintln!("Error parsing FMRI '{}': {}", fmri, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -597,10 +598,17 @@ impl Repository for FileBackend {
|
|||
let mut contents = Vec::new();
|
||||
|
||||
for pkg_info in packages {
|
||||
// Format the package identifier using the FMRI
|
||||
let pkg_id = if let Some(version) = &pkg_info.fmri.version {
|
||||
format!("{}@{}", pkg_info.fmri.name, version)
|
||||
} else {
|
||||
pkg_info.fmri.name.clone()
|
||||
};
|
||||
|
||||
// Example content data (package, path, type)
|
||||
let example_contents = vec![
|
||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/bin/example".to_string(), "file".to_string()),
|
||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/share/doc/example".to_string(), "dir".to_string()),
|
||||
(pkg_id.clone(), "/usr/bin/example".to_string(), "file".to_string()),
|
||||
(pkg_id.clone(), "/usr/share/doc/example".to_string(), "dir".to_string()),
|
||||
];
|
||||
|
||||
// Filter by action type if specified
|
||||
|
|
|
|||
|
|
@ -39,12 +39,8 @@ pub struct RepositoryInfo {
|
|||
/// Information about a package in a repository
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PackageInfo {
|
||||
/// Name of the package
|
||||
pub name: String,
|
||||
/// Version of the package
|
||||
pub version: String,
|
||||
/// Publisher of the package
|
||||
pub publisher: String,
|
||||
/// FMRI (Fault Management Resource Identifier) of the package
|
||||
pub fmri: crate::fmri::Fmri,
|
||||
}
|
||||
|
||||
/// Repository version
|
||||
|
|
|
|||
|
|
@ -211,10 +211,17 @@ impl Repository for RestBackend {
|
|||
for pkg_info in packages {
|
||||
// In a real implementation, we would get this information from the REST API
|
||||
|
||||
// Format the package identifier using the FMRI
|
||||
let pkg_id = if let Some(version) = &pkg_info.fmri.version {
|
||||
format!("{}@{}", pkg_info.fmri.name, version)
|
||||
} else {
|
||||
pkg_info.fmri.name.clone()
|
||||
};
|
||||
|
||||
// Example content data (package, path, type)
|
||||
let example_contents = vec![
|
||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/bin/example".to_string(), "file".to_string()),
|
||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/share/doc/example".to_string(), "dir".to_string()),
|
||||
(pkg_id.clone(), "/usr/bin/example".to_string(), "file".to_string()),
|
||||
(pkg_id.clone(), "/usr/share/doc/example".to_string(), "dir".to_string()),
|
||||
];
|
||||
|
||||
// Filter by action type if specified
|
||||
|
|
|
|||
|
|
@ -378,7 +378,18 @@ fn main() -> Result<()> {
|
|||
|
||||
// Print packages
|
||||
for pkg_info in packages {
|
||||
println!("{:<30} {:<15} {:<10}", pkg_info.name, pkg_info.version, pkg_info.publisher);
|
||||
// Format version and publisher, handling optional fields
|
||||
let version_str = match &pkg_info.fmri.version {
|
||||
Some(version) => version.to_string(),
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
let publisher_str = match &pkg_info.fmri.publisher {
|
||||
Some(publisher) => publisher.clone(),
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
println!("{:<30} {:<15} {:<10}", pkg_info.fmri.name, version_str, publisher_str);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue