mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-11 05:40:41 +00:00
Add default derive
Add Fast path parsing which catches the case of unescaped values with spaces.
This commit is contained in:
parent
f33df3d0ab
commit
441a47d384
2 changed files with 77 additions and 5 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
// MPL was not distributed with this file, You can
|
// MPL was not distributed with this file, You can
|
||||||
// obtain one at https://mozilla.org/MPL/2.0/.
|
// obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::{Regex, Captures};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
@ -11,6 +11,7 @@ use std::fs::File;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct Dir {
|
pub struct Dir {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub group: String,
|
pub group: String,
|
||||||
|
|
@ -18,6 +19,7 @@ pub struct Dir {
|
||||||
pub mode: String, //TODO implement as bitmask
|
pub mode: String, //TODO implement as bitmask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct Attr {
|
pub struct Attr {
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub values: Vec<String>,
|
pub values: Vec<String>,
|
||||||
|
|
@ -30,6 +32,7 @@ pub struct Property {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
pub struct Manifest {
|
pub struct Manifest {
|
||||||
pub attributes: Vec<Attr>,
|
pub attributes: Vec<Attr>,
|
||||||
}
|
}
|
||||||
|
|
@ -130,6 +133,49 @@ fn is_attr_action(line: &String) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_attr_action(line: String) -> Result<Attr, ManifestError> {
|
pub fn parse_attr_action(line: String) -> Result<Attr, ManifestError> {
|
||||||
|
// 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
|
||||||
|
// unescaped spaces are never valid but sadly present in the wild.
|
||||||
|
// Fast path will fail if a value has multiple values or a '=' sign in the values
|
||||||
|
let full_line_regex = match Regex::new(r"^set name=([^ ]+) value=(.+)$") {
|
||||||
|
Ok(re) => re,
|
||||||
|
Err(e) => return Err(ManifestError::Regex(e)),
|
||||||
|
};
|
||||||
|
|
||||||
|
if full_line_regex.is_match(line.trim_start()) {
|
||||||
|
match full_line_regex.captures(line.trim_start()) {
|
||||||
|
Some(captures) => {
|
||||||
|
let mut fast_path_fail = false;
|
||||||
|
let mut val = String::from(&captures[2]);
|
||||||
|
|
||||||
|
if val.contains("=") {
|
||||||
|
fast_path_fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.contains("value=") {
|
||||||
|
fast_path_fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.contains("name=") {
|
||||||
|
fast_path_fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = val.replace(&['"', '\\'][..], "");
|
||||||
|
|
||||||
|
if !fast_path_fail{
|
||||||
|
return Ok(Attr{
|
||||||
|
key: String::from(&captures[1]),
|
||||||
|
values: vec![val],
|
||||||
|
..Attr::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Todo move regex initialisation out of for loop into static area
|
//Todo move regex initialisation out of for loop into static area
|
||||||
let name_regex = match Regex::new(r"name=([^ ]+) value=") {
|
let name_regex = match Regex::new(r"name=([^ ]+) value=") {
|
||||||
Ok(re) => re,
|
Ok(re) => re,
|
||||||
|
|
|
||||||
34
src/lib.rs
34
src/lib.rs
|
|
@ -8,7 +8,7 @@ mod actions;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::actions::Manifest;
|
use crate::actions::{Manifest, Property};
|
||||||
use crate::actions::{parse_manifest_string, Attr};
|
use crate::actions::{parse_manifest_string, Attr};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,15 @@ mod tests {
|
||||||
set name=info.source-url value=http://nginx.org/download/nginx-1.18.0.tar.gz
|
set name=info.source-url value=http://nginx.org/download/nginx-1.18.0.tar.gz
|
||||||
set name=org.opensolaris.consolidation value=userland
|
set name=org.opensolaris.consolidation value=userland
|
||||||
set name=com.oracle.info.version value=1.18.0
|
set name=com.oracle.info.version value=1.18.0
|
||||||
set name=variant.arch value=i386");
|
set name=pkg.summary value=\\\"provided mouse accessibility enhancements\\\"
|
||||||
|
set name=info.upstream value=X.Org Foundation
|
||||||
|
set name=pkg.description value=Latvian language support's extra files
|
||||||
|
set name=variant.arch value=i386 optional=testing optionalWithString=\"test ing\"");
|
||||||
|
|
||||||
|
let mut optional_hash = HashSet::new();
|
||||||
|
optional_hash.insert(Property{key: String::from("optional"), value:String::from("testing")});
|
||||||
|
optional_hash.insert(Property{key: String::from("optionalWithString"), value:String::from("test ing")});
|
||||||
|
|
||||||
let test_results = vec![
|
let test_results = vec![
|
||||||
Attr{
|
Attr{
|
||||||
key: String::from("pkg.fmri"),
|
key: String::from("pkg.fmri"),
|
||||||
|
|
@ -82,10 +90,25 @@ mod tests {
|
||||||
values: vec![String::from("1.18.0")],
|
values: vec![String::from("1.18.0")],
|
||||||
properties: HashSet::new(),
|
properties: HashSet::new(),
|
||||||
},
|
},
|
||||||
|
Attr{
|
||||||
|
key: String::from("pkg.summary"),
|
||||||
|
values: vec![String::from("provided mouse accessibility enhancements")],
|
||||||
|
properties: HashSet::new(),
|
||||||
|
},
|
||||||
|
Attr{
|
||||||
|
key: String::from("info.upstream"),
|
||||||
|
values: vec![String::from("X.Org Foundation")],
|
||||||
|
properties: HashSet::new(),
|
||||||
|
},
|
||||||
|
Attr{
|
||||||
|
key: String::from("pkg.description"),
|
||||||
|
values: vec![String::from("Latvian language support's extra files")],
|
||||||
|
properties: HashSet::new(),
|
||||||
|
},
|
||||||
Attr{
|
Attr{
|
||||||
key: String::from("variant.arch"),
|
key: String::from("variant.arch"),
|
||||||
values: vec![String::from("i386")],
|
values: vec![String::from("i386")],
|
||||||
properties: HashSet::new(),
|
properties: optional_hash,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -94,9 +117,12 @@ mod tests {
|
||||||
Ok(m) => manifest = m,
|
Ok(m) => manifest = m,
|
||||||
Err(_) => assert!(false, "caught error"),
|
Err(_) => assert!(false, "caught error"),
|
||||||
};
|
};
|
||||||
assert_eq!(manifest.attributes.len(), 12);
|
|
||||||
|
assert_eq!(manifest.attributes.len(), 15);
|
||||||
|
|
||||||
for (pos, attr) in manifest.attributes.iter().enumerate() {
|
for (pos, attr) in manifest.attributes.iter().enumerate() {
|
||||||
assert_eq!(attr.key, test_results[pos].key);
|
assert_eq!(attr.key, test_results[pos].key);
|
||||||
|
|
||||||
for (vpos, val) in attr.values.iter().enumerate() {
|
for (vpos, val) in attr.values.iter().enumerate() {
|
||||||
assert_eq!(val, &test_results[pos].values[vpos]);
|
assert_eq!(val, &test_results[pos].values[vpos]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue