]> git.proxmox.com Git - proxmox-backup.git/commitdiff
src/tools/nom.rs: move nom helpers into separate file
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 18 Jun 2020 10:41:13 +0000 (12:41 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 18 Jun 2020 10:41:13 +0000 (12:41 +0200)
src/tools.rs
src/tools/disks/zpool_list.rs
src/tools/disks/zpool_status.rs
src/tools/nom.rs [new file with mode: 0644]
src/tools/systemd/parse_time.rs

index 63222468b293717442e981f28650f9c088f2e24c..f6e80833ed07119019e75d2e02f8a668c9c40dcb 100644 (file)
@@ -33,6 +33,7 @@ pub mod ticket;
 pub mod timer;
 pub mod statistics;
 pub mod systemd;
+pub mod nom;
 
 mod wrapped_reader_stream;
 pub use wrapped_reader_stream::*;
index 44ce5883e73aa1620085b82aa78fc5b87bb137c0..d7c7c1fc0129bfdb9227c8493eedf801993449c3 100644 (file)
@@ -1,8 +1,11 @@
 use anyhow::{bail, Error};
 
+use crate::tools::nom::{
+    multispace0, multispace1, notspace1, IResult,
+};
+
 use nom::{
-    error::VerboseError,
-    bytes::complete::{take_while, take_while1, take_till, take_till1},
+    bytes::complete::{take_while1, take_till, take_till1},
     combinator::{map_res, all_consuming, recognize, opt},
     sequence::{preceded, tuple},
     character::complete::{digit1, char, line_ending},
@@ -26,22 +29,6 @@ pub struct ZFSPoolInfo {
     pub devices: Vec<String>,
 }
 
-type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
-
-/// Recognizes zero or more spaces and tabs (but not carage returns or line feeds)
-fn multispace0(i: &str)  -> IResult<&str, &str> {
-    take_while(|c| c == ' ' || c == '\t')(i)
-}
-
-/// Recognizes one or more spaces and tabs (but not carage returns or line feeds)
-fn multispace1(i: &str)  -> IResult<&str, &str> {
-    take_while1(|c| c == ' ' || c == '\t')(i)
-}
-
-/// Recognizes one or more non-whitespace-characters
-fn notspace1(i: &str)  -> IResult<&str, &str> {
-    take_while1(|c| !(c == ' ' || c == '\t' || c == '\n'))(i)
-}
 
 fn parse_optional_u64(i: &str) -> IResult<&str, Option<u64>> {
     if i.starts_with('-') {
index 729952286e79f73e1eac701e69714cdaa101ba89..44d04de04cdf480e45fd3284e491eea0a8046a14 100644 (file)
@@ -1,36 +1,19 @@
-use anyhow::{bail, Error};
+use anyhow::{Error};
 use serde_json::{json, Value};
 use ::serde::{Deserialize, Serialize};
 
+use crate::tools::nom::{
+    parse_complete, parse_failure, multispace0, multispace1, notspace1, parse_u64, IResult,
+};
+
 use nom::{
-    error::VerboseError,
     bytes::complete::{tag, take_while, take_while1},
-    combinator::{map_res, all_consuming, recognize, opt},
+    combinator::{opt},
     sequence::{preceded},
-    character::complete::{digit1, line_ending},
-    multi::{many0},
+    character::complete::{line_ending},
+    multi::{many0,many1},
 };
 
-type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
-
-/// Recognizes zero or more spaces and tabs (but not carage returns or line feeds)
-fn multispace0(i: &str) -> IResult<&str, &str> {
-    take_while(|c| c == ' ' || c == '\t')(i)
-}
-
-// Recognizes one or more spaces and tabs (but not carage returns or line feeds)
-fn multispace1(i: &str) -> IResult<&str, &str> {
-    take_while1(|c| c == ' ' || c == '\t')(i)
-}
-
-/// Recognizes one or more non-whitespace-characters
-fn notspace1(i: &str) -> IResult<&str, &str> {
-    take_while1(|c| !(c == ' ' || c == '\t' || c == '\n'))(i)
-}
-
-fn parse_u64(i: &str) -> IResult<&str, u64> {
-    map_res(recognize(digit1), str::parse)(i)
-}
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct ZFSPoolVDevState {
@@ -46,7 +29,12 @@ pub struct ZFSPoolVDevState {
 
 fn parse_zpool_status_vdev(i: &str) -> IResult<&str, ZFSPoolVDevState> {
 
-    let (i, indent) = multispace0(i)?;
+    let (n, indent) = multispace0(i)?;
+    if (indent.len() & 1) != 0 {
+        return Err(parse_failure(n, "wrong indent length"));
+    }
+    let i = n;
+
     let (i, vdev_name) =  notspace1(i)?;
     let (i, state) = preceded(multispace1, notspace1)(i)?;
     let (i, read) = preceded(multispace1, parse_u64)(i)?;
@@ -81,7 +69,7 @@ fn parse_zpool_status_tree(i: &str) -> IResult<&str, Vec<ZFSPoolVDevState>> {
     let (i, _) = line_ending(i)?;
 
     // parse vdev list
-    many0(parse_zpool_status_vdev)(i)
+    many1(parse_zpool_status_vdev)(i)
 }
 
 fn parse_zpool_status_field(i: &str) -> IResult<&str, (String, String)> {
@@ -127,29 +115,11 @@ fn parse_zpool_status_field(i: &str) -> IResult<&str, (String, String)> {
 }
 
 pub fn parse_zpool_status_config_tree(i: &str) -> Result<Vec<ZFSPoolVDevState>, Error> {
-    match all_consuming(parse_zpool_status_tree)(&i) {
-        Err(nom::Err::Error(err)) |
-        Err(nom::Err::Failure(err)) => {
-            bail!("unable to parse zfs status config tree - {}", nom::error::convert_error(&i, err));
-        }
-        Err(err) => {
-            bail!("unable to parse zfs status config tree: {}", err);
-        }
-        Ok((_, data)) => Ok(data),
-    }
+    parse_complete("zfs status config tree", i, parse_zpool_status_tree)
 }
 
 fn parse_zpool_status(i: &str) -> Result<Vec<(String, String)>, Error> {
-    match all_consuming(many0(parse_zpool_status_field))(i) {
-        Err(nom::Err::Error(err)) |
-        Err(nom::Err::Failure(err)) => {
-            bail!("unable to parse zfs status output - {}", nom::error::convert_error(i, err));
-        }
-        Err(err) => {
-            bail!("unable to parse zfs status output - {}", err);
-        }
-        Ok((_, data)) => Ok(data),
-    }
+    parse_complete("zfs status output", i, many0(parse_zpool_status_field))
 }
 
 pub fn vdev_list_to_tree(vdev_list: &[ZFSPoolVDevState]) -> Value {
@@ -265,7 +235,7 @@ config:
 
         NAME        STATE     READ WRITE CKSUM
         tank        DEGRADED     0     0     0
-          mirror-0  DEGRADED     0     0     0
+         mirror-0  DEGRADED     0     0     0
             c1t0d0  ONLINE       0     0     0
             c1t2d0  ONLINE       0     0     0
             c1t1d0  UNAVAIL      0     0     0  cannot open
diff --git a/src/tools/nom.rs b/src/tools/nom.rs
new file mode 100644 (file)
index 0000000..0b0fe81
--- /dev/null
@@ -0,0 +1,58 @@
+use anyhow::{bail, Error};
+
+use nom::{
+    error::{ParseError, VerboseError},
+    bytes::complete::{take_while, take_while1},
+    combinator::{map_res, all_consuming, recognize},
+    character::complete::{digit1},
+};
+
+pub type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
+
+pub fn parse_error<'a>(i: &'a str, context: &'static str) -> nom::Err<VerboseError<&'a str>> {
+    let err = VerboseError { errors: Vec::new() };
+    let err = VerboseError::add_context(i, context, err);
+    nom::Err::Error(err)
+}
+
+pub fn parse_failure<'a>(i: &'a str, context: &'static str) -> nom::Err<VerboseError<&'a str>> {
+    let err = VerboseError { errors: Vec::new() };
+    let err = VerboseError::add_context(i, context, err);
+    nom::Err::Failure(err)
+}
+
+/// Recognizes zero or more spaces and tabs (but not carage returns or line feeds)
+pub fn multispace0(i: &str)  -> IResult<&str, &str> {
+    take_while(|c| c == ' ' || c == '\t')(i)
+}
+
+/// Recognizes one or more spaces and tabs (but not carage returns or line feeds)
+pub fn multispace1(i: &str)  -> IResult<&str, &str> {
+    take_while1(|c| c == ' ' || c == '\t')(i)
+}
+
+/// Recognizes one or more non-whitespace-characters
+pub fn notspace1(i: &str)  -> IResult<&str, &str> {
+    take_while1(|c| !(c == ' ' || c == '\t' || c == '\n'))(i)
+}
+
+/// Parse a 64 bit unsigned integer
+pub fn parse_u64(i: &str) -> IResult<&str, u64> {
+    map_res(recognize(digit1), str::parse)(i)
+}
+
+pub fn parse_complete<'a, F, O>(what: &str, i: &'a str, parser: F) -> Result<O, Error>
+    where F: Fn(&'a str) -> IResult<&'a str, O>,
+{
+    match all_consuming(parser)(i) {
+        Err(nom::Err::Error(err)) |
+        Err(nom::Err::Failure(err)) => {
+            bail!("unable to parse {} - {}", what, nom::error::convert_error(i, err));
+        }
+        Err(err) => {
+            bail!("unable to parse {} - {}", what, err);
+        }
+        Ok((_, data)) => Ok(data),
+    }
+
+}
index 2cd8d38c1f2045aef17cb845b0bbbedf13da5424..00bcbfba0271309b33c6ba618ed48fe6dc83e2ef 100644 (file)
@@ -5,8 +5,12 @@ use lazy_static::lazy_static;
 
 use super::time::*;
 
+use crate::tools::nom::{
+    parse_complete, parse_u64, parse_error, IResult,
+};
+
 use nom::{
-    error::{context, ParseError, VerboseError},
+    error::{context},
     bytes::complete::{tag, take_while1},
     combinator::{map_res, all_consuming, opt, recognize},
     sequence::{pair, preceded, tuple},
@@ -14,14 +18,6 @@ use nom::{
     multi::separated_nonempty_list,
 };
 
-type IResult<I, O, E = VerboseError<I>> = Result<(I, O), nom::Err<E>>;
-
-fn parse_error<'a>(i: &'a str, context: &'static str) -> nom::Err<VerboseError<&'a str>> {
-    let err = VerboseError { errors: Vec::new() };
-    let err = VerboseError::add_context(i, context, err);
-    nom::Err::Error(err)
-}
-
 lazy_static! {
     pub static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = {
         let mut map = HashMap::new();
@@ -100,11 +96,7 @@ fn parse_time_comp(max: usize) -> impl Fn(&str) -> IResult<&str, u32> {
     }
 }
 
-fn parse_u64(i: &str) -> IResult<&str, u64> {
-    map_res(recognize(digit1), str::parse)(i)
-}
-
-fn parse_weekday(i: &str) -> IResult<&str, WeekDays, VerboseError<&str>> {
+fn parse_weekday(i: &str) -> IResult<&str, WeekDays> {
     let (i, text) = alpha1(i)?;
 
     match text.to_ascii_lowercase().as_str() {
@@ -192,20 +184,7 @@ fn parse_time_spec(i: &str) -> IResult<&str, (Vec<DateTimeValue>, Vec<DateTimeVa
 }
 
 pub fn parse_calendar_event(i: &str) -> Result<CalendarEvent, Error> {
-    match all_consuming(parse_calendar_event_incomplete)(i) {
-        Err(nom::Err::Error(VerboseError { errors })) |
-        Err(nom::Err::Failure(VerboseError { errors })) => {
-            if errors.is_empty() {
-                bail!("unable to parse calendar event");
-            } else {
-                bail!("unable to parse calendar event at '{}': {:?}", errors[0].0, errors[0].1);
-            }
-        }
-        Err(err) => {
-            bail!("unable to parse calendar event: {}", err);
-        }
-        Ok((_, ce)) => Ok(ce),
-    }
+    parse_complete("calendar event", i, parse_calendar_event_incomplete)
 }
 
 fn parse_calendar_event_incomplete(mut i: &str) -> IResult<&str, CalendarEvent> {