mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
Implement pest parsing
This commit is contained in:
parent
d557773763
commit
48525d3122
2 changed files with 248 additions and 5 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use regex::{RegexSet, Regex};
|
use regex::{RegexSet, Regex};
|
||||||
use std::collections::{HashMap};
|
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::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
|
|
@ -17,6 +17,7 @@ use std::str::FromStr;
|
||||||
use std::path::{Path};
|
use std::path::{Path};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use crate::errors::Result;
|
use crate::errors::Result;
|
||||||
|
use pest::Parser;
|
||||||
|
|
||||||
pub trait FacetedAction {
|
pub trait FacetedAction {
|
||||||
// Add a facet to the action if the facet is already present the function returns false.
|
// 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 {
|
pub struct Action {
|
||||||
kind: ActionKind,
|
kind: ActionKind,
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
|
payload_string: String,
|
||||||
properties: Vec<Property>,
|
properties: Vec<Property>,
|
||||||
facets: HashMap<String, Facet>,
|
facets: HashMap<String, Facet>,
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +41,7 @@ impl Action {
|
||||||
Action{
|
Action{
|
||||||
kind,
|
kind,
|
||||||
payload: Payload::default(),
|
payload: Payload::default(),
|
||||||
|
payload_string: String::new(),
|
||||||
properties: Vec::new(),
|
properties: Vec::new(),
|
||||||
facets: HashMap::new(),
|
facets: HashMap::new(),
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +69,28 @@ pub struct Dir {
|
||||||
pub facets: HashMap<String, Facet>,
|
pub facets: HashMap<String, Facet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Action> 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 {
|
impl FacetedAction for Dir {
|
||||||
fn add_facet(&mut self, facet: Facet) -> bool {
|
fn add_facet(&mut self, facet: Facet) -> bool {
|
||||||
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
||||||
|
|
@ -109,6 +134,51 @@ impl File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Action> 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 {
|
impl FacetedAction for File {
|
||||||
fn add_facet(&mut self, facet: Facet) -> bool {
|
fn add_facet(&mut self, facet: Facet) -> bool {
|
||||||
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
||||||
|
|
@ -136,6 +206,28 @@ pub struct Dependency {
|
||||||
pub facets: HashMap<String, Facet>,
|
pub facets: HashMap<String, Facet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Action> 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 {
|
impl FacetedAction for Dependency {
|
||||||
fn add_facet(&mut self, facet: Facet) -> bool {
|
fn add_facet(&mut self, facet: Facet) -> bool {
|
||||||
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
return self.facets.insert(facet.name.clone(), facet.clone()) == None
|
||||||
|
|
@ -152,6 +244,15 @@ pub struct Facet {
|
||||||
pub value: String,
|
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)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
pub struct Attr {
|
pub struct Attr {
|
||||||
pub key: String,
|
pub key: String,
|
||||||
|
|
@ -159,7 +260,26 @@ pub struct Attr {
|
||||||
pub properties: HashMap<String, Property>,
|
pub properties: HashMap<String, Property>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, Eq, PartialEq, Debug, Default)]
|
impl From<Action> 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 struct Property {
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
|
@ -187,9 +307,101 @@ impl Manifest {
|
||||||
self.files.push(f);
|
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<Manifest> {
|
||||||
|
let content = read_to_string(Path::new(&f))?;
|
||||||
|
Manifest::parse_string(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_string(content: String) -> Result<Manifest> {
|
||||||
|
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"]
|
#[grammar = "actions/manifest.pest"]
|
||||||
struct ManifestParser;
|
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,
|
||||||
|
"<transform" => 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<Manifest> {
|
pub fn parse_manifest_file(filename: String) -> Result<Manifest> {
|
||||||
let mut m = Manifest::new();
|
let mut m = Manifest::new();
|
||||||
let f = OsFile::open(filename)?;
|
let f = OsFile::open(filename)?;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
assert!(res.is_ok(), "error during Manifest parsing: {:?}", res);
|
||||||
let manifest = res.unwrap();
|
let manifest = res.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue