From b57d63cebf4f78c6946c44723569aca7b60f024e Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Sun, 17 May 2020 01:17:19 +0200 Subject: [PATCH] Intial set function Parsing --- .gitignore | 86 +++++++++++++++++++++++++++++ .idea/.gitignore | 8 +++ .idea/libips.iml | 12 ++++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ Cargo.toml | 10 ++++ src/actions/mod.rs | 135 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 47 ++++++++++++++++ 9 files changed, 318 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/libips.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 Cargo.toml create mode 100644 src/actions/mod.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e34821e --- /dev/null +++ b/.gitignore @@ -0,0 +1,86 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Rust template +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/libips.iml b/.idea/libips.iml new file mode 100644 index 0000000..758ceaa --- /dev/null +++ b/.idea/libips.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c73cd4f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1ac634a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "libips" +version = "0.1.0" +authors = ["Till Wegmueller "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1.3.7" \ No newline at end of file diff --git a/src/actions/mod.rs b/src/actions/mod.rs new file mode 100644 index 0000000..353ea0f --- /dev/null +++ b/src/actions/mod.rs @@ -0,0 +1,135 @@ +use std::fs::File; +use std::io::BufRead; +use std::io::BufReader; +use std::error; +use std::fmt; +use regex::Regex; +use regex::RegexSet; + +pub struct Attr { + pub Key: String, + pub Values: Vec, +} + +pub struct Manifest { + pub Attributes: Vec, +} + +impl Manifest { + pub fn new() -> Manifest { + return Manifest{ + Attributes: Vec::new(), + }; + } +} + +#[derive(Debug)] +pub enum ManifestError { + EmptyVec, + // We will defer to the parse error implementation for their error. + // Supplying extra info requires adding more data to the type. + Read(std::io::Error), + Regex(regex::Error), +} + +impl fmt::Display for ManifestError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ManifestError::EmptyVec => + write!(f, "please use a vector with at least one element"), + // This is a wrapper, so defer to the underlying types' implementation of `fmt`. + ManifestError::Read(ref e) => e.fmt(f), + ManifestError::Regex(ref e) => e.fmt(f), + } + } +} + +impl error::Error for ManifestError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + ManifestError::EmptyVec => None, + // The cause is the underlying implementation error type. Is implicitly + // cast to the trait object `&error::Error`. This works because the + // underlying type already implements the `Error` trait. + ManifestError::Read(ref e) => Some(e), + ManifestError::Regex(ref e) => Some(e), + } + } +} + +pub fn ParseManifestFile(filename: String) -> Result { + let mut manifest = Manifest::new(); + let f = match File::open(filename) { + Ok(file) => file, + Err(e) => return Err(ManifestError::Read(e)), + }; + let file = BufReader::new(&f); + for lineRead in file.lines() { + let line = match lineRead { + Ok(l) => l, + Err(e) => return Err(ManifestError::Read(e)), + }; + if isAttrLine(&line) { + match ParseAttrLine(line) { + Ok(attr) => manifest.Attributes.push(attr), + Err(e) => return Err(e) + } + } + } + return Ok(manifest); +} + +pub fn ParseManifestString(manifest: String) -> Result { + let mut m = Manifest::new(); + for line in manifest.lines() { + if isAttrLine(&String::from(line)) { + let attr = match ParseAttrLine(String::from(line)) { + Ok(attr) => m.Attributes.push(attr), + Err(e) => return Err(e) + }; + } + } + return Ok(m) +} + +fn isAttrLine(line: &String) -> bool { + if line.trim().starts_with("set ") { + return true; + } + return false; +} + +pub fn ParseAttrLine(line: String) -> Result { + let name_regex = match Regex::new(r"name=([^ ]+) value=") { + Ok(re) => re, + Err(e) => return Err(ManifestError::Regex(e)) + }; + let mut name = String::new(); + for cap in name_regex.captures_iter(line.trim_start()) { + name = String::from(&cap[1]); + } + + let mut values = Vec::new(); + let value_no_space_regex = match Regex::new(r#"value="(.+)""#) { + Ok(re) => re, + Err(e) => return Err(ManifestError::Regex(e)), + }; + + let value_space_regex = match Regex::new(r#"value=([^"][^ ]+[^"])"#) { + Ok(re) => re, + Err(e) => return Err(ManifestError::Regex(e)), + }; + + for cap in value_no_space_regex.captures_iter(line.trim_start()) { + values.push(String::from(&cap[1])); + } + + for cap in value_space_regex.captures_iter(line.trim_start()) { + values.push(String::from(&cap[1])); + } + + Ok(Attr{ + Key: name, + Values: values, + }) +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3b40424 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,47 @@ +mod actions; + +#[cfg(test)] +mod tests { + + use crate::actions::ParseManifestString; + use crate::actions::Manifest; + use crate::actions::ManifestError; + use std::error; + use std::fmt; + + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } + + #[test] + fn parse_manifest() { + 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 + set name=userland.info.git-branch value=HEAD + set name=userland.info.git-rev value=1665491ba61bd494bf73e2916cd2250f3024260e + set name=pkg.summary value=\"Nginx Webserver\" + set name=info.classification value=\"org.opensolaris.category.2008:Web Services/Application and Web Servers\" + set name=info.upstream-url value=http://nginx.net/ + 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=com.oracle.info.version value=1.18.0 + set name=variant.arch value=i386"); + let mut manifest = Manifest::new(); + match ParseManifestString(manifest_string){ + Ok(m) => manifest = m, + Err(_) => assert!(false, "caught error") + }; + for attr in manifest.Attributes { + println!("Name: {}", attr.Key); + for val in attr.Values { + println!("Value: {}", val) + } + println!(); + } + //assert_eq!(manifest.Attributes.len(), 12); + } + +} +