From d2a414fb4a633e4d86ca6f426df2a8bc675981b9 Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Thu, 6 Aug 2020 00:06:18 +0200 Subject: [PATCH] Implement dependency action --- Cargo.toml | 3 +- src/actions/mod.rs | 74 +++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e6d94d5..06d4314 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,5 @@ keywords = ["packaging", "illumos"] [dependencies] regex = "1.3.7" -failure = "0.1.8" \ No newline at end of file +failure = "0.1.8" +maplit = "0.1.6" \ No newline at end of file diff --git a/src/actions/mod.rs b/src/actions/mod.rs index ae3ffb2..f867530 100644 --- a/src/actions/mod.rs +++ b/src/actions/mod.rs @@ -3,6 +3,8 @@ // MPL was not distributed with this file, You can // obtain one at https://mozilla.org/MPL/2.0/. +// Source https://docs.oracle.com/cd/E23824_01/html/E21796/pkg-5.html + use regex::{RegexSet, Regex}; use std::collections::HashSet; use std::fs::File as OsFile; @@ -98,6 +100,27 @@ impl FacetedAction for File { } } +//TODO implement multiple FMRI for require-any +#[derive(Debug, Default)] +pub struct Dependency { + pub fmri: String, //TODO make FMRI + pub dependency_type: String, //TODO make enum + pub predicate: String, //TODO make FMRI + pub root_image: String, //TODO make boolean + pub optional: Vec, + pub facets: HashSet, +} + +impl FacetedAction for Dependency { + fn add_facet(&mut self, facet: Facet) -> bool { + return self.facets.insert(facet) + } + + fn remove_facet(&mut self, facet: Facet) -> bool { + return self.facets.remove(&facet) + } +} + #[derive(Hash, Eq, PartialEq, Debug, Default)] pub struct Facet { pub name: String, @@ -122,6 +145,7 @@ pub struct Manifest { pub attributes: Vec, pub directories: Vec, pub files: Vec, + pub dependencies: Vec, } impl Manifest { @@ -130,6 +154,7 @@ impl Manifest { attributes: Vec::new(), directories: Vec::new(), files: Vec::new(), + dependencies: Vec::new(), }; } } @@ -202,7 +227,7 @@ fn handle_manifest_line(manifest: &mut Manifest, line: &str, line_nr: usize) -> manifest.files.push(parse_file_action(String::from(line), line_nr)?); } ActionKind::Dependency => { - + manifest.dependencies.push(parse_depend_action(String::from(line),line_nr)?); } ActionKind::User => { @@ -230,21 +255,23 @@ fn handle_manifest_line(manifest: &mut Manifest, line: &str, line_nr: usize) -> } fn add_facet_to_action(action: &mut T, facet_string: String, line: String, line_nr: usize) -> Result<(), ManifestError> { - let facet_key = match facet_string.find(".") { + let mut facet_key = match facet_string.find(".") { Some(idx) => { facet_string.clone().split_off(idx+1) }, None => return Err(ManifestError::InvalidAction{action: line, line: line_nr, message: String::from("separation dot not found but string contains facet.")})? }; - let value = match facet_string.find("=") { + let value = match facet_key.find("=") { Some(idx) => { - facet_string.clone().split_off(idx+1) + facet_key.split_off(idx+1) }, None => return Err(ManifestError::InvalidAction{action: line, line: line_nr, message: String::from("no value present for facet")})? }; - if !action.add_facet(Facet{name: facet_key, value}) { + facet_key.truncate(facet_key.len() - 1); + + if !action.add_facet(Facet{name: clean_string_value(facet_key.as_str()), value: clean_string_value(value.as_str())}) { return Err(ManifestError::InvalidAction{action: line, line: line_nr, message: String::from("double declaration of facet")})? } @@ -290,6 +317,43 @@ fn string_to_bool(orig: &str) -> Result { } } +fn parse_depend_action(line: String, line_nr: usize) -> Result { + let mut act = Dependency::default(); + let regex_set = RegexSet::new(&[ + r#"([^ ]+)=([^"][^ ]+[^"])"#, + r#"([^ ]+)="(.+)"# + ])?; + + for (pat, _) in regex_set.matches(line.trim_start()).into_iter().map(|match_idx| (®ex_set.patterns()[match_idx], match_idx)) { + let regex = Regex::new(&pat)?; + for cap in regex.captures_iter(line.clone().trim_start()) { + let full_cap_idx = 0; + let key_cap_idx = 1; + let val_cap_idx = 2; + + match &cap[key_cap_idx] { + "fmri" => act.fmri = clean_string_value(&cap[val_cap_idx]), + "type" => act.dependency_type = clean_string_value(&cap[val_cap_idx]), + "predicate" => act.predicate = clean_string_value(&cap[val_cap_idx]), + "root-image" => act.root_image = clean_string_value(&cap[val_cap_idx]), + _ => { + let key_val_string = String::from(&cap[full_cap_idx]); + if key_val_string.contains("facet.") { + match add_facet_to_action(&mut act, key_val_string, line.clone(), line_nr) { + Ok(_) => continue, + Err(e) => return Err(e)?, + } + } else { + act.optional.push(Property{key: clean_string_value(&cap[key_cap_idx]), value: clean_string_value(&cap[val_cap_idx])}); + } + } + } + } + } + + Ok(act) +} + fn parse_file_action(line: String, line_nr: usize) -> Result { let mut act = File::default(); let regex_set = RegexSet::new(&[ diff --git a/src/lib.rs b/src/lib.rs index ee85d84..eeef24a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,16 +8,18 @@ mod digest; mod payload; #[macro_use] extern crate failure; +#[macro_use] extern crate maplit; #[cfg(test)] mod tests { - use crate::actions::{Manifest, Property, Dir, File}; + use crate::actions::{Manifest, Property, Dir, File, Dependency, Facet}; use crate::actions::{parse_manifest_string, Attr}; use std::collections::HashSet; use crate::payload::Payload; use crate::digest::{Digest, DigestAlgorithm, DigestSource}; use std::str::FromStr; + use failure::_core::ptr::hash; #[test] fn parse_attributes() { @@ -828,4 +830,80 @@ file 6d5f820bb1d67594c7b757c79ef6f9242df49e98 chash=3ab17dde089f1eac7abd37d8efd7 } } } + + #[test] + fn parse_dependency_actions() { + let manifest_string = String::from("depend fmri=pkg:/system/library@0.5.11-2020.0.1.19563 type=require +depend fmri=pkg:/system/file-system/nfs@0.5.11,5.11-2020.0.1.19951 type=incorporate +depend facet.version-lock.system/data/hardware-registry=true fmri=pkg:/system/data/hardware-registry@2020.2.22,5.11-2020.0.1.19951 type=incorporate +depend facet.version-lock.xvm=true fmri=xvm@0.5.11-2015.0.2.0 type=incorporate +depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1-2020.0.1.0 type=incorporate"); + + let test_results = vec![ + Dependency{ + fmri: "pkg:/system/library@0.5.11-2020.0.1.19563".to_string(), + 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(), + 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(), + dependency_type: "incorporate".to_string(), + facets: hashset!{ + Facet{ + name: "version-lock.system/data/hardware-registry".to_string(), + value: "true".to_string(), + } + }, + ..Dependency::default() + }, + Dependency{ + fmri: "xvm@0.5.11-2015.0.2.0".to_string(), + dependency_type: "incorporate".to_string(), + facets: hashset!{ + Facet{ + name: "version-lock.xvm".to_string(), + value: "true".to_string(), + } + }, + ..Dependency::default() + }, + Dependency{ + fmri: "system/mozilla-nss@3.51.1-2020.0.1.0".to_string(), + dependency_type: "incorporate".to_string(), + facets: hashset!{ + Facet{ + name: "version-lock.system/mozilla-nss".to_string(), + value: "true".to_string(), + } + }, + ..Dependency::default() + }, + ]; + + let mut manifest = Manifest::new(); + let res = parse_manifest_string(manifest_string); + assert!(res.is_ok(), "error during Manifest parsing: {:?}", res); + let manifest = res.unwrap(); + + assert_eq!(manifest.dependencies.len(), test_results.len()); + for (pos, dependency) in manifest.dependencies.iter().enumerate() { + assert_eq!(dependency.fmri, test_results[pos].fmri); + assert_eq!(dependency.dependency_type, test_results[pos].dependency_type); + for (vpos, facet) in dependency.facets.iter().enumerate() { + let fres = test_results[pos].facets.get(facet); + assert!(fres.is_some(), "error no facet with name: {:?} found", facet.name); + let f = fres.unwrap(); + assert_eq!(facet.name, f.name); + assert_eq!(facet.value, f.value); + } + } + + } } + +