Browse Source

a few changes

Getty Ritter 2 years ago
parent
commit
f0739d189b
6 changed files with 188 additions and 192 deletions
  1. 6 15
      src/contlines.rs
  2. 37 53
      src/lib.rs
  3. 21 10
      src/tools/common.rs
  4. 46 45
      src/tools/format.rs
  5. 52 48
      src/tools/select.rs
  6. 26 21
      src/tools/tojson.rs

+ 6 - 15
src/contlines.rs

@@ -2,11 +2,11 @@ use std::io;
 
 /// An iterator that abstracts over continuation characters on
 /// subsequent lines
-pub struct ContinuationLines<R: Iterator<Item=io::Result<String>>> {
+pub struct ContinuationLines<R: Iterator<Item = io::Result<String>>> {
     underlying: R,
 }
 
-impl<R: Iterator<Item=io::Result<String>>> ContinuationLines<R> {
+impl<R: Iterator<Item = io::Result<String>>> ContinuationLines<R> {
     fn join_next(&mut self, mut past: String) -> Option<io::Result<String>> {
         let next = self.underlying.next();
         match next {
@@ -30,7 +30,7 @@ impl<R: Iterator<Item=io::Result<String>>> ContinuationLines<R> {
     }
 }
 
-impl<R: Iterator<Item=io::Result<String>>> Iterator for ContinuationLines<R> {
+impl<R: Iterator<Item = io::Result<String>>> Iterator for ContinuationLines<R> {
     type Item = io::Result<String>;
 
     fn next(&mut self) -> Option<io::Result<String>> {
@@ -48,7 +48,6 @@ impl<R: Iterator<Item=io::Result<String>>> Iterator for ContinuationLines<R> {
             }
         }
     }
-
 }
 
 #[cfg(test)]
@@ -59,8 +58,7 @@ mod tests {
     fn test_contlines(input: &[u8], expected: Vec<&str>) {
         // build a ContinuationLines iterator from our input buffer,
         // and unwrap all the IO exceptions we would get
-        let mut i = ContinuationLines::new(Cursor::new(input).lines())
-            .map(Result::unwrap);
+        let mut i = ContinuationLines::new(Cursor::new(input).lines()).map(Result::unwrap);
         // walk the expected values and make sure those are the ones
         // we're getting
         for e in expected.into_iter() {
@@ -82,18 +80,11 @@ mod tests {
 
     #[test]
     fn three_joined_lines() {
-        test_contlines(
-            b"foo\\\nbar\\\nbaz\n",
-            vec!["foobarbaz"],
-        );
+        test_contlines(b"foo\\\nbar\\\nbaz\n", vec!["foobarbaz"]);
     }
 
     #[test]
     fn mixed_joins() {
-        test_contlines(
-            b"foo\nbar\\\nbaz\nquux\n",
-            vec!["foo", "barbaz", "quux"],
-        );
+        test_contlines(b"foo\nbar\\\nbaz\nquux\n", vec!["foo", "barbaz", "quux"]);
     }
-
 }

+ 37 - 53
src/lib.rs

@@ -1,15 +1,14 @@
-#[macro_use] extern crate failure;
+#[macro_use]
+extern crate failure;
 
 pub mod contlines;
 
 use contlines::ContinuationLines;
 
-
 struct ParsingContext {
     current_record_type: Option<String>,
 }
 
-
 #[derive(Eq, PartialEq, Debug)]
 pub struct Record {
     pub rec_type: Option<String>,
@@ -18,7 +17,8 @@ pub struct Record {
 
 impl Record {
     pub fn write<W>(&self, w: &mut W) -> std::io::Result<()>
-        where W: std::io::Write
+    where
+        W: std::io::Write,
     {
         for &(ref name, ref value) in self.fields.iter() {
             write!(w, "{}: {}\n", name, value)?;
@@ -32,7 +32,6 @@ impl Record {
     }
 }
 
-
 #[derive(Eq, PartialEq, Debug)]
 pub struct Recfile {
     pub records: Vec<Record>,
@@ -40,7 +39,8 @@ pub struct Recfile {
 
 impl Recfile {
     pub fn write<W>(&self, w: &mut W) -> std::io::Result<()>
-        where W: std::io::Write
+    where
+        W: std::io::Write,
     {
         for r in self.records.iter() {
             r.write(w)?;
@@ -60,25 +60,19 @@ impl Recfile {
 #[derive(Debug, Fail)]
 pub enum RecError {
     #[fail(display = "Error parsing records: {}", message)]
-    GenericError {
-        message: String,
-    },
+    GenericError { message: String },
 
     #[fail(display = "Found cont line in nonsensical place: {}", ln)]
-    BadContLine {
-        ln: String,
-    },
+    BadContLine { ln: String },
 
     #[fail(display = "Invalid line: {}", ln)]
-    InvalidLine {
-        ln: String,
-    },
+    InvalidLine { ln: String },
 }
 
-
 impl Recfile {
     pub fn parse<I>(i: I) -> Result<Recfile, RecError>
-        where I: std::io::BufRead
+    where
+        I: std::io::BufRead,
     {
         let mut iter = ContinuationLines::new(i.lines());
         let mut current = Record {
@@ -91,7 +85,7 @@ impl Recfile {
         };
 
         while let Some(Ok(ln)) = iter.next() {
-            let ln = ln.trim_left_matches(' ');
+            let ln = ln.trim_start_matches(' ');
 
             if ln.starts_with('#') {
                 // skip comment lines
@@ -106,22 +100,21 @@ impl Recfile {
             } else if ln.starts_with('+') {
                 if let Some(val) = current.fields.last_mut() {
                     val.1.push_str("\n");
-                    val.1.push_str(
-                        if ln[1..].starts_with(' ') {
-                            &ln[2..]
-                        } else {
-                            &ln[1..]
-                        });
+                    val.1.push_str(if ln[1..].starts_with(' ') {
+                        &ln[2..]
+                    } else {
+                        &ln[1..]
+                    });
                 } else {
-                    return Err(RecError::BadContLine{ ln: ln.to_owned() });
+                    return Err(RecError::BadContLine { ln: ln.to_owned() });
                 }
             } else if let Some(pos) = ln.find(':') {
                 let (key, val) = ln.split_at(pos);
-                current.fields.push((
-                    key.to_owned(),
-                    val[1..].trim_left().to_owned()));
+                current
+                    .fields
+                    .push((key.to_owned(), val[1..].trim_start().to_owned()));
                 if key == "%rec" {
-                    ctx.current_record_type = Some(val[1..].trim_left().to_owned());
+                    ctx.current_record_type = Some(val[1..].trim_start().to_owned());
                 }
             } else {
                 return Err(RecError::InvalidLine { ln: ln.to_owned() });
@@ -134,23 +127,24 @@ impl Recfile {
 
         Ok(Recfile { records: buf })
     }
-
 }
 
 #[cfg(test)]
 mod tests {
-    use ::{Recfile,Record};
+    use {Recfile, Record};
 
     fn test_parse(input: &[u8], expected: Vec<Vec<(&str, &str)>>) {
         let file = Recfile {
-            records: expected.iter().map( |v| {
-                Record {
+            records: expected
+                .iter()
+                .map(|v| Record {
                     rec_type: None,
-                    fields: v.iter().map( |&(k, v)| {
-                        (k.to_owned(), v.to_owned())
-                    }).collect(),
-                }
-            }).collect(),
+                    fields: v
+                        .iter()
+                        .map(|&(k, v)| (k.to_owned(), v.to_owned()))
+                        .collect(),
+                })
+                .collect(),
         };
         assert_eq!(Recfile::parse(input), Ok(file));
     }
@@ -167,17 +161,14 @@ mod tests {
 
     #[test]
     fn one_section() {
-        test_parse(b"hello: yes\n", vec![ vec![ ("hello", "yes") ] ]);
+        test_parse(b"hello: yes\n", vec![vec![("hello", "yes")]]);
     }
 
     #[test]
     fn two_sections() {
         test_parse(
             b"hello: yes\n\ngoodbye: no\n",
-            vec![
-                vec![ ("hello", "yes") ],
-                vec![ ("goodbye", "no") ],
-            ],
+            vec![vec![("hello", "yes")], vec![("goodbye", "no")]],
         );
     }
 
@@ -185,9 +176,7 @@ mod tests {
     fn continuation_with_space() {
         test_parse(
             b"hello: yes\n+ but also no\n",
-            vec![
-                vec![ ("hello", "yes\nbut also no") ],
-            ],
+            vec![vec![("hello", "yes\nbut also no")]],
         );
     }
 
@@ -195,9 +184,7 @@ mod tests {
     fn continuation_without_space() {
         test_parse(
             b"hello: yes\n+but also no\n",
-            vec![
-                vec![ ("hello", "yes\nbut also no") ],
-            ],
+            vec![vec![("hello", "yes\nbut also no")]],
         );
     }
 
@@ -205,10 +192,7 @@ mod tests {
     fn continuation_with_two_spaces() {
         test_parse(
             b"hello: yes\n+  but also no\n",
-            vec![
-                vec![ ("hello", "yes\n but also no") ],
-            ],
+            vec![vec![("hello", "yes\n but also no")]],
         );
     }
-
 }

+ 21 - 10
src/tools/common.rs

@@ -1,18 +1,22 @@
 #![allow(dead_code)]
 
-use std::{fs,io};
+use std::{fs, io};
 
 /// This can be changed to modify all the tool metadata all at once
 pub const VERSION: &'static str = "0.0";
-pub const AUTHOR: &'static str =
-    "Getty Ritter <rrecutils@infinitenegativeutility.com>";
+pub const AUTHOR: &'static str = "Getty Ritter <rrecutils@infinitenegativeutility.com>";
+
+// pub fn with_input_file<R>(spec: Option<&str>, f: impl FnOnce(&dyn io::Write) -> R) -> io::Result<R> {
+//     match spec.unwrap_or("-") {
+//         "-" => f(&io::BufReader::new(io::stdout())),
+//         path => f(&io::BufReader::new(fs::File::open(path)?)),
+//     }
+// }
 
 /// If this doesn't name a path, or if the path is `"-"`, then return
 /// a buffered reader from stdin; otherwise, attempt to open the file
 /// named by the path and return a buffered reader around it
-pub fn input_from_spec<'a>(
-    spec: Option<&'a str>
-) -> io::Result<io::BufReader<Box<io::Read>>> {
+pub fn input_from_spec<'a>(spec: Option<&'a str>) -> io::Result<io::BufReader<Box<dyn io::Read>>> {
     match spec.unwrap_or("-") {
         "-" => Ok(io::BufReader::new(Box::new(io::stdin()))),
         path => {
@@ -22,13 +26,20 @@ pub fn input_from_spec<'a>(
     }
 }
 
+pub fn with_output_file<R>(
+    spec: Option<&str>,
+    f: impl FnOnce(&mut dyn io::Write) -> R,
+) -> io::Result<R> {
+    Ok(match spec.unwrap_or("-") {
+        "-" => f(&mut io::stdout()),
+        path => f(&mut fs::File::open(path)?),
+    })
+}
+
 /// If this doesn't name a path, or if the path is `"-"`, then return
 /// a buffered writer to stdout; otherwise, attempt to open the file
 /// named by the path and return a writer around it
-pub fn output_from_spec<'a>(
-    spec: Option<&'a str>
-) -> io::Result<Box<io::Write>>
-{
+pub fn output_from_spec<'a>(spec: Option<&'a str>) -> io::Result<Box<dyn io::Write>> {
     match spec.unwrap_or("-") {
         "-" => Ok(Box::new(io::stdout())),
         path => Ok(Box::new(fs::File::open(path)?)),

+ 46 - 45
src/tools/format.rs

@@ -1,16 +1,17 @@
 extern crate clap;
 extern crate rrecutils;
 extern crate rustache;
-#[macro_use] extern crate failure;
+#[macro_use]
+extern crate failure;
 
-use std::{fs,io};
+use std::{fs, io};
 
 mod common;
 
 use rustache::Render;
 
 struct R {
-    rec: rrecutils::Record
+    rec: rrecutils::Record,
 }
 
 impl Render for R {
@@ -18,8 +19,7 @@ impl Render for R {
         &self,
         template: &str,
         writer: &mut W,
-    ) -> Result<(), rustache::RustacheError>
-    {
+    ) -> Result<(), rustache::RustacheError> {
         use rustache::HashBuilder;
         let mut hb = HashBuilder::new();
         if let Some(ref t) = self.rec.rec_type {
@@ -32,54 +32,55 @@ impl Render for R {
     }
 }
 
-
 fn rr_format_args() -> clap::ArgMatches<'static> {
     clap::App::new("rr-format")
         .version(common::VERSION)
         .author(common::AUTHOR)
         .about("Display the Rust AST for a Recutils file")
-
-        .arg(clap::Arg::with_name("input")
-             .short("i")
-             .long("input")
-             .value_name("FILE")
-             .help("The input recfile (or - for stdin)"))
-
-        .arg(clap::Arg::with_name("output")
-             .short("o")
-             .long("output")
-             .value_name("FILE")
-             .help("The desired output location (or - for stdout)"))
-
-        .arg(clap::Arg::with_name("mustache")
-             .short("m")
-             .long("mustache")
-             .value_name("FILE")
-             .help("The mustache template to use"))
-
-        .arg(clap::Arg::with_name("type")
-             .short("t")
-             .long("type")
-             .value_name("TYPE")
-             .takes_value(true)
-             .help("The type of records to pass to the mustache file"))
-
-        .arg(clap::Arg::with_name("joiner")
-             .short("j")
-             .long("joiner")
-             .value_name("STRING")
-             .help("The string used to separate each fragment"))
-
+        .arg(
+            clap::Arg::with_name("input")
+                .short("i")
+                .long("input")
+                .value_name("FILE")
+                .help("The input recfile (or - for stdin)"),
+        )
+        .arg(
+            clap::Arg::with_name("output")
+                .short("o")
+                .long("output")
+                .value_name("FILE")
+                .help("The desired output location (or - for stdout)"),
+        )
+        .arg(
+            clap::Arg::with_name("mustache")
+                .short("m")
+                .long("mustache")
+                .value_name("FILE")
+                .help("The mustache template to use"),
+        )
+        .arg(
+            clap::Arg::with_name("type")
+                .short("t")
+                .long("type")
+                .value_name("TYPE")
+                .takes_value(true)
+                .help("The type of records to pass to the mustache file"),
+        )
+        .arg(
+            clap::Arg::with_name("joiner")
+                .short("j")
+                .long("joiner")
+                .value_name("STRING")
+                .help("The string used to separate each fragment"),
+        )
         .get_matches()
 }
 
 fn run() -> Result<(), failure::Error> {
     let matches = rr_format_args();
 
-    let input = common::input_from_spec(
-        matches.value_of("input"))?;
-    let mut output = common::output_from_spec(
-        matches.value_of("output"))?;
+    let input = common::input_from_spec(matches.value_of("input"))?;
+    let mut output = common::output_from_spec(matches.value_of("output"))?;
 
     let template: String = match matches.value_of("mustache") {
         Some(path) => {
@@ -87,7 +88,7 @@ fn run() -> Result<(), failure::Error> {
             let mut buf = Vec::new();
             fs::File::open(path)?.read_to_end(&mut buf)?;
             String::from_utf8(buf)?
-        },
+        }
         None => bail!("No template specified!"),
     };
 
@@ -97,7 +98,6 @@ fn run() -> Result<(), failure::Error> {
         recfile.filter_by_type(typ);
     }
 
-
     let joiner = matches.value_of("joiner");
 
     let mut first = true;
@@ -108,7 +108,8 @@ fn run() -> Result<(), failure::Error> {
             output.write(j.as_bytes())?;
             output.write(&['\n' as u8])?;
         }
-        R { rec: r }.render(&template, &mut output.as_mut())
+        R { rec: r }
+            .render(&template, &mut output.as_mut())
             .map_err(|e| format_err!("Rustache error: {:?}", e))?;
     }
 

+ 52 - 48
src/tools/select.rs

@@ -1,6 +1,6 @@
 extern crate clap;
-extern crate rrecutils;
 extern crate failure;
+extern crate rrecutils;
 
 mod common;
 
@@ -11,59 +11,63 @@ fn rr_select_args() -> clap::ArgMatches<'static> {
         .version(common::VERSION)
         .author(common::AUTHOR)
         .about("Print records from a recfile")
-
-        .arg(clap::Arg::with_name("input")
-             .short("i")
-             .long("input")
-             .value_name("FILE")
-             .help("The input recfile (or - for stdin)"))
-
-        .arg(clap::Arg::with_name("output")
-             .short("o")
-             .long("output")
-             .value_name("FILE")
-             .help("The desired output location (or - for stdout)"))
-
-        .arg(clap::Arg::with_name("type")
-             .long("type")
-             .short("t")
-             .required(false)
-             .takes_value(true))
-
-        .arg(clap::Arg::with_name("include-descriptors")
-             .long("include-descriptors")
-             .short("d")
-             .required(false)
-             .takes_value(false))
-
-        .arg(clap::Arg::with_name("collapse")
-             .long("collapse")
-             .short("C")
-             .required(false)
-             .takes_value(false))
-
-        .arg(clap::Arg::with_name("sort")
-             .long("sort")
-             .short("S")
-             .required(false)
-             .takes_value(true))
-
-        .arg(clap::Arg::with_name("group-by")
-             .long("group-by")
-             .short("G")
-             .required(false)
-             .takes_value(true))
-
+        .arg(
+            clap::Arg::with_name("input")
+                .short("i")
+                .long("input")
+                .value_name("FILE")
+                .help("The input recfile (or - for stdin)"),
+        )
+        .arg(
+            clap::Arg::with_name("output")
+                .short("o")
+                .long("output")
+                .value_name("FILE")
+                .help("The desired output location (or - for stdout)"),
+        )
+        .arg(
+            clap::Arg::with_name("type")
+                .long("type")
+                .short("t")
+                .required(false)
+                .takes_value(true),
+        )
+        .arg(
+            clap::Arg::with_name("include-descriptors")
+                .long("include-descriptors")
+                .short("d")
+                .required(false)
+                .takes_value(false),
+        )
+        .arg(
+            clap::Arg::with_name("collapse")
+                .long("collapse")
+                .short("C")
+                .required(false)
+                .takes_value(false),
+        )
+        .arg(
+            clap::Arg::with_name("sort")
+                .long("sort")
+                .short("S")
+                .required(false)
+                .takes_value(true),
+        )
+        .arg(
+            clap::Arg::with_name("group-by")
+                .long("group-by")
+                .short("G")
+                .required(false)
+                .takes_value(true),
+        )
         .get_matches()
 }
 
 fn run() -> Result<(), Error> {
     let matches = rr_select_args();
 
-    let input = common::input_from_spec(
-        matches.value_of("input"))?;
-    let mut output = common::output_from_spec(
-        matches.value_of("output"))?;
+    let input = common::input_from_spec(matches.value_of("input"))?;
+    let mut output = common::output_from_spec(matches.value_of("output"))?;
 
     let mut records = rrecutils::Recfile::parse(input)?;
 

+ 26 - 21
src/tools/tojson.rs

@@ -5,9 +5,10 @@ extern crate serde_json;
 mod common;
 
 use std::fmt;
+use std::io::Write;
 
-use serde_json::Value;
 use serde_json::map::Map;
+use serde_json::Value;
 
 fn record_to_json(rec: &rrecutils::Record) -> Value {
     let mut m = Map::new();
@@ -34,33 +35,38 @@ fn main() {
         .version(common::VERSION)
         .author(common::AUTHOR)
         .about("Display the Rust AST for a Recutils file")
-        .arg(clap::Arg::with_name("pretty")
-             .short("p")
-             .long("pretty")
-             .help("Pretty-print the resulting JSON"))
-        .arg(clap::Arg::with_name("input")
-             .short("i")
-             .long("input")
-             .value_name("FILE")
-             .help("The input recfile (or - for stdin)"))
-        .arg(clap::Arg::with_name("output")
-             .short("o")
-             .long("output")
-             .value_name("FILE")
-             .help("The desired output location (or - for stdout)"))
+        .arg(
+            clap::Arg::with_name("pretty")
+                .short("p")
+                .long("pretty")
+                .help("Pretty-print the resulting JSON"),
+        )
+        .arg(
+            clap::Arg::with_name("input")
+                .short("i")
+                .long("input")
+                .value_name("FILE")
+                .help("The input recfile (or - for stdin)"),
+        )
+        .arg(
+            clap::Arg::with_name("output")
+                .short("o")
+                .long("output")
+                .value_name("FILE")
+                .help("The desired output location (or - for stdout)"),
+        )
         .get_matches();
 
-    let input = unwrap_err(common::input_from_spec(
-        matches.value_of("input")));
-    let mut output = unwrap_err(common::output_from_spec(
-        matches.value_of("output")));
+    let input = unwrap_err(common::input_from_spec(matches.value_of("input")));
+    let mut output = unwrap_err(common::output_from_spec(matches.value_of("output")));
 
     let json = Value::Array(
         unwrap_err(rrecutils::Recfile::parse(input))
             .records
             .iter()
             .map(|x| record_to_json(x))
-            .collect());
+            .collect(),
+    );
 
     let serialized = if matches.is_present("pretty") {
         unwrap_err(serde_json::to_string_pretty(&json))
@@ -69,5 +75,4 @@ fn main() {
     };
 
     unwrap_err(writeln!(output, "{}", serialized));
-
 }