Add directory actions

This commit is contained in:
Till Wegmueller 2020-05-19 22:14:28 +02:00
parent 6cfcff39b6
commit 16069b8792
2 changed files with 128 additions and 6 deletions

View file

@ -3,7 +3,7 @@
// MPL was not distributed with this file, You can
// obtain one at https://mozilla.org/MPL/2.0/.
use regex::{Regex, Captures};
use regex::{RegexSet, Regex};
use std::collections::HashSet;
use std::error;
use std::fmt;
@ -18,6 +18,15 @@ pub struct Dir {
pub group: String,
pub owner: String,
pub mode: String, //TODO implement as bitmask
pub revert_tag: String,
pub salvage_from: String,
pub facets: HashSet<Facet>,
}
#[derive(Hash, Eq, PartialEq, Debug, Default)]
pub struct Facet {
pub name: String,
pub value: String,
}
#[derive(Debug, Default)]
@ -27,7 +36,7 @@ pub struct Attr {
pub properties: HashSet<Property>,
}
#[derive(Hash, Eq, PartialEq, Debug)]
#[derive(Hash, Eq, PartialEq, Debug, Default)]
pub struct Property {
pub key: String,
pub value: String,
@ -36,12 +45,14 @@ pub struct Property {
#[derive(Debug, Default)]
pub struct Manifest {
pub attributes: Vec<Attr>,
pub directories: Vec<Dir>,
}
impl Manifest {
pub fn new() -> Manifest {
return Manifest {
attributes: Vec::new(),
directories: Vec::new(),
};
}
}
@ -68,6 +79,12 @@ pub enum ManifestError {
line: usize,
action: String,
},
#[fail(display = "action string \"{}\" at line {} is invalid: {}", action, line, message)]
InvalidAction {
line: usize,
action: String,
message: String,
},
}
pub fn parse_manifest_file(filename: String) -> Result<Manifest, Error> {
@ -97,7 +114,7 @@ fn handle_manifest_line(manifest: &mut Manifest, line: &str, line_nr: usize) ->
manifest.attributes.push(parse_attr_action(String::from(line))?);
}
ActionKind::Dir => {
manifest.directories.push(parse_dir_action(String::from(line), line_nr)?);
}
ActionKind::File => {
@ -155,7 +172,47 @@ fn determine_action_kind(line: &str) -> ActionKind {
}
}
pub fn parse_attr_action(line: String) -> Result<Attr, Error> {
fn parse_dir_action(line: String, line_nr: usize) -> Result<Dir, Error> {
let mut act = Dir::default();
let regex = Regex::new(r#"(([^ ]+)=([^"][^ ]+[^"])|([^ ]+)=([^"][^ ]+[^"]))"#)?;
for cap in regex.captures_iter(line.trim_start()) {
match &cap[1] {
"path" => act.path = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
"owner" => act.owner = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
"group" => act.group = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
"mode" => act.mode = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
"revert-tag" => act.revert_tag = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
"salvage-from" => act.salvage_from = String::from(&cap[2]).replace(&['"', '\\'][..], ""),
_ => {
let key_val_string = String::from(&cap[1]).replace(&['"', '\\'][..], "");
if key_val_string.contains("facet.") {
let key = match key_val_string.find(".") {
Some(idx) => {
key_val_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 key_val_string.find("=") {
Some(idx) => {
key_val_string.clone().split_off(idx+1)
},
None => return Err(ManifestError::InvalidAction{action: line, line: line_nr, message: String::from("no value present for facet")})?
};
if !act.facets.insert(Facet{name: key, value: value}) {
return Err(ManifestError::InvalidAction{action: line, line: line_nr, message: String::from("double declaration of facet")})?
}
}
}
}
}
Ok(act)
}
fn parse_attr_action(line: String) -> Result<Attr, Error> {
// Do a full line match to see if we can fast path this.
// This also catches values with spaces, that have not been properly escaped.
// Note: values with spaces must be properly escaped or the rest here will fail. Strings with

View file

@ -10,12 +10,12 @@ mod actions;
#[cfg(test)]
mod tests {
use crate::actions::{Manifest, Property};
use crate::actions::{Manifest, Property, Dir};
use crate::actions::{parse_manifest_string, Attr};
use std::collections::HashSet;
#[test]
fn parse_manifest() {
fn parse_attributes() {
let manifest_string = String::from("set name=pkg.fmri value=pkg://openindiana.org/web/server/nginx@1.18.0,5.11-2020.0.1.0:20200421T195136Z
set name=com.oracle.info.name value=nginx value=test
set name=userland.info.git-remote value=git://github.com/OpenIndiana/oi-userland.git
@ -145,4 +145,69 @@ mod tests {
}
}
}
#[test]
fn parse_direcory_actions() {
let manifest_string = String::from("dir group=bin mode=0755 owner=root path=etc/nginx
dir group=bin mode=0755 owner=root path=usr/share/nginx
dir group=bin mode=0755 owner=root path=usr/share/nginx/html
dir group=bin mode=0755 owner=root path=\"var/nginx\"
dir group=bin mode=0755 owner=webservd path=var/nginx/logs");
let test_results = vec![
Dir{
group: String::from("bin"),
mode: String::from("0755"),
owner: String::from("root"),
path: String::from("etc/nginx"),
..Dir::default()
},Dir{
group: String::from("bin"),
mode: String::from("0755"),
owner: String::from("root"),
path: String::from("usr/share/nginx"),
..Dir::default()
},Dir{
group: String::from("bin"),
mode: String::from("0755"),
owner: String::from("root"),
path: String::from("usr/share/nginx/html"),
..Dir::default()
},Dir{
group: String::from("bin"),
mode: String::from("0755"),
owner: String::from("root"),
path: String::from("\"var/nginx\""),
..Dir::default()
},Dir{
group: String::from("bin"),
mode: String::from("0755"),
owner: String::from("root"),
path: String::from("var/nginx/logs"),
..Dir::default()
},
];
let mut manifest = Manifest::new();
match parse_manifest_string(manifest_string) {
Ok(m) => manifest = m,
Err(e) => {
println!("{}", e);
assert!(false, "caught error");
}
};
assert_eq!(manifest.directories.len(), test_results.len());
for (pos, attr) in manifest.directories.iter().enumerate() {
assert_eq!(attr.group, test_results[pos].group);
assert_eq!(attr.mode, test_results[pos].mode);
assert_eq!(attr.owner, test_results[pos].owner);
assert_eq!(attr.path, test_results[pos].path);
//for (vpos, val) in attr.facets.iter().enumerate() {
// assert_eq!(val, &test_results[pos].facets.);
//}
}
}
}