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",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"regex",
|
"regex",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
|
|
@ -1348,9 +1349,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.17"
|
version = "1.0.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ pest_derive = "2.1.0"
|
||||||
strum = { version = "0.24.1", features = ["derive"] }
|
strum = { version = "0.24.1", features = ["derive"] }
|
||||||
serde = { version = "1.0.207", features = ["derive"] }
|
serde = { version = "1.0.207", features = ["derive"] }
|
||||||
serde_json = "1.0.124"
|
serde_json = "1.0.124"
|
||||||
diff-struct = "0.5.3"
|
|
||||||
flate2 = "1.0.28"
|
flate2 = "1.0.28"
|
||||||
lz4 = "1.24.0"
|
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
|
// Source https://docs.oracle.com/cd/E23824_01/html/E21796/pkg-5.html
|
||||||
|
|
||||||
use crate::digest::Digest;
|
use crate::digest::Digest;
|
||||||
|
use crate::fmri::Fmri;
|
||||||
use crate::payload::{Payload, PayloadError};
|
use crate::payload::{Payload, PayloadError};
|
||||||
use pest::Parser;
|
use pest::Parser;
|
||||||
use pest_derive::Parser;
|
use pest_derive::Parser;
|
||||||
|
|
@ -267,9 +268,9 @@ pub enum FileError {
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
))]
|
))]
|
||||||
pub struct Dependency {
|
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 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 root_image: String, //TODO make boolean
|
||||||
pub optional: Vec<Property>,
|
pub optional: Vec<Property>,
|
||||||
pub facets: HashMap<String, Facet>,
|
pub facets: HashMap<String, Facet>,
|
||||||
|
|
@ -288,9 +289,25 @@ impl From<Action> for Dependency {
|
||||||
}
|
}
|
||||||
for prop in props {
|
for prop in props {
|
||||||
match prop.key.as_str() {
|
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,
|
"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,
|
"root-image" => dep.root_image = prop.value,
|
||||||
_ => {
|
_ => {
|
||||||
if is_facet(prop.key.clone()) {
|
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)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
pub mod digest;
|
pub mod digest;
|
||||||
|
pub mod fmri;
|
||||||
pub mod payload;
|
pub mod payload;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod repository;
|
pub mod repository;
|
||||||
|
|
@ -16,6 +17,7 @@ mod tests {
|
||||||
use crate::actions::Attr;
|
use crate::actions::Attr;
|
||||||
use crate::actions::{Dependency, Dir, Facet, File, Link, Manifest, Property};
|
use crate::actions::{Dependency, Dir, Facet, File, Link, Manifest, Property};
|
||||||
use crate::digest::{Digest, DigestAlgorithm, DigestSource};
|
use crate::digest::{Digest, DigestAlgorithm, DigestSource};
|
||||||
|
use crate::fmri::Fmri;
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
use std::collections::HashMap;
|
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![
|
let test_results = vec![
|
||||||
Dependency {
|
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_type: "require".to_string(),
|
||||||
..Dependency::default()
|
..Dependency::default()
|
||||||
},
|
},
|
||||||
Dependency {
|
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_type: "incorporate".to_string(),
|
||||||
..Dependency::default()
|
..Dependency::default()
|
||||||
},
|
},
|
||||||
Dependency {
|
Dependency {
|
||||||
fmri: "pkg:/system/data/hardware-registry@2020.2.22,5.11-2020.0.1.19951"
|
fmri: Some(Fmri::parse("pkg:/system/data/hardware-registry@2020.2.22,5.11-2020.0.1.19951").unwrap()),
|
||||||
.to_string(),
|
|
||||||
dependency_type: "incorporate".to_string(),
|
dependency_type: "incorporate".to_string(),
|
||||||
facets: hashmap! {
|
facets: hashmap! {
|
||||||
"version-lock.system/data/hardware-registry".to_string() => Facet{
|
"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::default()
|
||||||
},
|
},
|
||||||
Dependency {
|
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(),
|
dependency_type: "incorporate".to_string(),
|
||||||
facets: hashmap! {
|
facets: hashmap! {
|
||||||
"version-lock.xvm".to_string() => Facet{
|
"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::default()
|
||||||
},
|
},
|
||||||
Dependency {
|
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(),
|
dependency_type: "incorporate".to_string(),
|
||||||
facets: hashmap! {
|
facets: hashmap! {
|
||||||
"version-lock.system/mozilla-nss".to_string() => Facet{
|
"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());
|
assert_eq!(manifest.dependencies.len(), test_results.len());
|
||||||
for (pos, dependency) in manifest.dependencies.iter().enumerate() {
|
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!(
|
assert_eq!(
|
||||||
dependency.dependency_type,
|
dependency.dependency_type,
|
||||||
test_results[pos].dependency_type
|
test_results[pos].dependency_type
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ use regex::Regex;
|
||||||
|
|
||||||
use crate::actions::{Manifest, File as FileAction};
|
use crate::actions::{Manifest, File as FileAction};
|
||||||
use crate::digest::Digest;
|
use crate::digest::Digest;
|
||||||
|
use crate::fmri::Fmri;
|
||||||
use crate::payload::{Payload, PayloadCompressionAlgorithm};
|
use crate::payload::{Payload, PayloadCompressionAlgorithm};
|
||||||
|
|
||||||
use super::{Repository, RepositoryConfig, RepositoryVersion, REPOSITORY_CONFIG_FILENAME, PublisherInfo, RepositoryInfo, PackageInfo};
|
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() {
|
if attr.key == "pkg.fmri" && !attr.values.is_empty() {
|
||||||
let fmri = &attr.values[0];
|
let fmri = &attr.values[0];
|
||||||
|
|
||||||
// Parse the FMRI to extract package name and version
|
// Parse the FMRI using our Fmri type
|
||||||
// Format: pkg://publisher/package_name@version
|
match Fmri::parse(fmri) {
|
||||||
if let Some(pkg_part) = fmri.strip_prefix("pkg://") {
|
Ok(parsed_fmri) => {
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
// Filter by pattern if specified
|
// Filter by pattern if specified
|
||||||
if let Some(pat) = pattern {
|
if let Some(pat) = pattern {
|
||||||
// Try to compile the pattern as a regex
|
// Try to compile the pattern as a regex
|
||||||
match Regex::new(pat) {
|
match Regex::new(pat) {
|
||||||
Ok(regex) => {
|
Ok(regex) => {
|
||||||
// Use regex matching
|
// Use regex matching
|
||||||
if !regex.is_match(pkg_name) {
|
if !regex.is_match(&parsed_fmri.name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Log the error but fall back to simple string contains
|
// Log the error but fall back to simple string contains
|
||||||
eprintln!("Error compiling regex pattern '{}': {}", pat, err);
|
eprintln!("Error compiling regex pattern '{}': {}", pat, err);
|
||||||
if !pkg_name.contains(pat) {
|
if !parsed_fmri.name.contains(pat) {
|
||||||
continue;
|
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
|
// Create a PackageInfo struct and add it to the list
|
||||||
packages.push(PackageInfo {
|
packages.push(PackageInfo {
|
||||||
name: pkg_name.to_string(),
|
fmri: fmri_with_publisher,
|
||||||
version: version.to_string(),
|
|
||||||
publisher: pub_name.clone(),
|
|
||||||
});
|
});
|
||||||
|
} 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
|
// Found the package info, no need to check other attributes
|
||||||
break;
|
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();
|
let mut contents = Vec::new();
|
||||||
|
|
||||||
for pkg_info in packages {
|
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)
|
// Example content data (package, path, type)
|
||||||
let example_contents = vec![
|
let example_contents = vec![
|
||||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/bin/example".to_string(), "file".to_string()),
|
(pkg_id.clone(), "/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/share/doc/example".to_string(), "dir".to_string()),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Filter by action type if specified
|
// Filter by action type if specified
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,8 @@ pub struct RepositoryInfo {
|
||||||
/// Information about a package in a repository
|
/// Information about a package in a repository
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct PackageInfo {
|
pub struct PackageInfo {
|
||||||
/// Name of the package
|
/// FMRI (Fault Management Resource Identifier) of the package
|
||||||
pub name: String,
|
pub fmri: crate::fmri::Fmri,
|
||||||
/// Version of the package
|
|
||||||
pub version: String,
|
|
||||||
/// Publisher of the package
|
|
||||||
pub publisher: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repository version
|
/// Repository version
|
||||||
|
|
|
||||||
|
|
@ -211,10 +211,17 @@ impl Repository for RestBackend {
|
||||||
for pkg_info in packages {
|
for pkg_info in packages {
|
||||||
// In a real implementation, we would get this information from the REST API
|
// 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)
|
// Example content data (package, path, type)
|
||||||
let example_contents = vec![
|
let example_contents = vec![
|
||||||
(format!("{}@{}", pkg_info.name, pkg_info.version), "/usr/bin/example".to_string(), "file".to_string()),
|
(pkg_id.clone(), "/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/share/doc/example".to_string(), "dir".to_string()),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Filter by action type if specified
|
// Filter by action type if specified
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,18 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
// Print packages
|
// Print packages
|
||||||
for pkg_info in 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(())
|
Ok(())
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue