mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
Add directory actions
This commit is contained in:
parent
6cfcff39b6
commit
16069b8792
2 changed files with 128 additions and 6 deletions
|
|
@ -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
|
||||
|
|
|
|||
69
src/lib.rs
69
src/lib.rs
|
|
@ -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.);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue