From 48525d3122dc230a1cfc670c3154179a7ec9788f Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Mon, 19 Apr 2021 23:38:56 -0300 Subject: [PATCH] Implement pest parsing --- libips/src/actions/mod.rs | 251 +++++++++++++++++++++++++++++++++++++- libips/src/lib.rs | 2 +- 2 files changed, 248 insertions(+), 5 deletions(-) diff --git a/libips/src/actions/mod.rs b/libips/src/actions/mod.rs index 08a0f4e..960442d 100644 --- a/libips/src/actions/mod.rs +++ b/libips/src/actions/mod.rs @@ -7,7 +7,7 @@ use regex::{RegexSet, Regex}; use std::collections::{HashMap}; -use std::fs::File as OsFile; +use std::fs::{File as OsFile, read_to_string}; use std::io::BufRead; use std::io::BufReader; use crate::payload::Payload; @@ -17,6 +17,7 @@ use std::str::FromStr; use std::path::{Path}; use std::fmt; use crate::errors::Result; +use pest::Parser; pub trait FacetedAction { // Add a facet to the action if the facet is already present the function returns false. @@ -30,6 +31,7 @@ pub trait FacetedAction { pub struct Action { kind: ActionKind, payload: Payload, + payload_string: String, properties: Vec, facets: HashMap, } @@ -39,6 +41,7 @@ impl Action { Action{ kind, payload: Payload::default(), + payload_string: String::new(), properties: Vec::new(), facets: HashMap::new(), } @@ -66,6 +69,28 @@ pub struct Dir { pub facets: HashMap, } +impl From for Dir { + fn from(act: Action) -> Self { + let mut dir = Dir::default(); + for prop in act.properties { + match prop.key.as_str() { + "path" => dir.path = prop.value, + "owner" => dir.owner = prop.value, + "group" => dir.group = prop.value, + "mode" => dir.mode = prop.value, + "revert-tag" => dir.revert_tag = prop.value, + "salvage-from" => dir.salvage_from = prop.value, + _ => { + if is_facet(prop.key.clone()) { + dir.add_facet(Facet::from_key_value(prop.key, prop.value)); + } + } + } + } + dir + } +} + impl FacetedAction for Dir { fn add_facet(&mut self, facet: Facet) -> bool { return self.facets.insert(facet.name.clone(), facet.clone()) == None @@ -109,6 +134,51 @@ impl File { } } +impl From for File { + fn from(act: Action) -> Self { + let mut file = File::default(); + let mut p = act.payload.clone(); + if !act.payload_string.is_empty() { + if act.payload_string.contains("/") { + file.properties.push(Property{ + key: "original-path".to_string(), + value: act.payload_string + }); + } else { + p.primary_identifier = Digest::from_str(&act.payload_string).unwrap(); + } + } + for prop in act.properties { + match prop.key.as_str() { + "path" => file.path = prop.value, + "owner" => file.owner = prop.value, + "group" => file.group = prop.value, + "mode" => file.mode = prop.value, + "revert-tag" => file.revert_tag = prop.value, + "original_name" => file.original_name = prop.value, + "sysattr" => file.sys_attr = prop.value, + "overlay" => file.overlay = match string_to_bool(&prop.value) { + Ok(b) => b, + _ => false, + }, + "preserve" => file.preserve = match string_to_bool(&prop.value) { + Ok(b) => b, + _ => false, + }, + "chash" | "pkg.content-hash" => p.additional_identifiers.push(Digest::from_str(&prop.value).unwrap()), + _ => { + if is_facet(prop.key.clone()) { + file.add_facet(Facet::from_key_value(prop.key, prop.value)); + } else { + file.properties.push(prop.clone()); + } + } + } + } + file + } +} + impl FacetedAction for File { fn add_facet(&mut self, facet: Facet) -> bool { return self.facets.insert(facet.name.clone(), facet.clone()) == None @@ -136,6 +206,28 @@ pub struct Dependency { pub facets: HashMap, } +impl From for Dependency { + fn from(act: Action) -> Self { + let mut dep = Dependency::default(); + for prop in act.properties { + match prop.key.as_str() { + "fmri" => dep.fmri = prop.value, + "type" => dep.dependency_type = prop.value, + "predicate" => dep.predicate = prop.value, + "root-image" => dep.root_image = prop.value, + _ => { + if is_facet(prop.key.clone()) { + dep.add_facet(Facet::from_key_value(prop.key, prop.value)); + } else { + dep.optional.push(prop.clone()); + } + } + } + } + dep + } +} + impl FacetedAction for Dependency { fn add_facet(&mut self, facet: Facet) -> bool { return self.facets.insert(facet.name.clone(), facet.clone()) == None @@ -152,6 +244,15 @@ pub struct Facet { pub value: String, } +impl Facet { + fn from_key_value(key: String, value: String) -> Facet { + Facet{ + name: get_facet_key(key), + value, + } + } +} + #[derive(Debug, Default, PartialEq)] pub struct Attr { pub key: String, @@ -159,7 +260,26 @@ pub struct Attr { pub properties: HashMap, } -#[derive(Hash, Eq, PartialEq, Debug, Default)] +impl From for Attr { + fn from(act: Action) -> Self { + let mut attr = Attr::default(); + for prop in act.properties { + match prop.key.as_str() { + "name" => attr.key = prop.value, + "value" => attr.values.push(prop.value), + _ => { + attr.properties.insert(prop.key.clone(), Property{ + key: prop.key, + value: prop.value + }); + } + } + } + attr + } +} + +#[derive(Hash, Eq, PartialEq, Debug, Default, Clone)] pub struct Property { pub key: String, pub value: String, @@ -187,9 +307,101 @@ impl Manifest { self.files.push(f); } - pub fn parse_file(&mut self, f: String) -> Result<()> { + fn add_action(&mut self, act: Action) { + match act.kind { + ActionKind::Attr => { + self.attributes.push(act.into()); + } + ActionKind::Dir => { + self.directories.push(act.into()); + } + ActionKind::File => { + self.files.push(act.into()); + } + ActionKind::Dependency => { + self.dependencies.push(act.into()); + } + ActionKind::User => { - Ok(()) + } + ActionKind::Group => { + + } + ActionKind::Driver => { + + } + ActionKind::License => { + + } + ActionKind::Link => { + + } + ActionKind::Legacy => { + + } + ActionKind::Transform => { + + } + ActionKind::Unknown{action} => (), + } + } + + pub fn parse_file(f: String) -> Result { + let content = read_to_string(Path::new(&f))?; + Manifest::parse_string(content) + } + + pub fn parse_string(content: String) -> Result { + let mut m = Manifest::new(); + + let pairs = ManifestParser::parse(Rule::manifest, &content)?; + + for p in pairs { + match p.as_rule() { + Rule::manifest => { + for manifest in p.clone().into_inner() { + match manifest.as_rule() { + Rule::action => { + let mut act = Action::default(); + for action in manifest.clone().into_inner() { + match action.as_rule() { + Rule::action_name => { + act.kind = get_action_kind(action.as_str()); + } + Rule::payload => { + act.payload_string = action.as_str().clone().into(); + } + Rule::property => { + let mut property = Property::default(); + for prop in action.clone().into_inner() { + match prop.as_rule() { + Rule::property_name => { + property.key = prop.as_str().clone().into(); + } + Rule::property_value => { + property.value = prop.as_str().clone().into(); + } + _ => panic!("unexpected rule {:?} inside action expected property_name or property_value", prop.as_rule()) + } + } + act.properties.push(property); + } + Rule::EOI => (), + _ => panic!("unexpected rule {:?} inside action expected payload, property, action_name", action.as_rule()), + } + } + m.add_action(act); + } + Rule::EOI => (), + _ => panic!("unexpected rule {:?} inside manifest expected action", manifest.as_rule()), + } + } + } + _ => panic!("unexpected rule {:?} inside pair expected manifest", p.as_rule()), + } + } + + Ok(m) } } @@ -233,6 +445,37 @@ pub enum ManifestError { #[grammar = "actions/manifest.pest"] struct ManifestParser; +fn get_action_kind(act: &str) -> ActionKind { + return match act { + "set" => ActionKind::Attr, + "depend" => ActionKind::Dependency, + "dir" => ActionKind::Dir, + "file" => ActionKind::File, + "license" => ActionKind::License, + "hardlink" => ActionKind::Link, + "link" => ActionKind::Link, + "driver" => ActionKind::Driver, + "group" => ActionKind::Group, + "user" => ActionKind::User, + "legacy" => ActionKind::Legacy, + " ActionKind::Transform, + _ => ActionKind::Unknown{action: act.into()}, + } +} + +fn is_facet(s: String) -> bool { + s.starts_with("facet.") +} + +fn get_facet_key(facet_string: String) -> String { + match facet_string.find(".") { + Some(idx) => { + facet_string.clone().split_off(idx+1) + }, + None => facet_string.clone() + } +} + pub fn parse_manifest_file(filename: String) -> Result { let mut m = Manifest::new(); let f = OsFile::open(filename)?; diff --git a/libips/src/lib.rs b/libips/src/lib.rs index 5594317..cf22703 100644 --- a/libips/src/lib.rs +++ b/libips/src/lib.rs @@ -893,7 +893,7 @@ depend facet.version-lock.system/mozilla-nss=true fmri=system/mozilla-nss@3.51.1 }, ]; - let res = parse_manifest_string(manifest_string); + let res = Manifest::parse_string(manifest_string); assert!(res.is_ok(), "error during Manifest parsing: {:?}", res); let manifest = res.unwrap();