format.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. extern crate clap;
  2. extern crate rrecutils;
  3. extern crate rustache;
  4. use std::{fs,io};
  5. use std::convert::From;
  6. use std::string::FromUtf8Error;
  7. use rustache::Render;
  8. struct R {
  9. rec: rrecutils::Record
  10. }
  11. impl Render for R {
  12. fn render<W: io::Write>(
  13. &self,
  14. template: &str,
  15. writer: &mut W,
  16. ) -> Result<(), rustache::RustacheError>
  17. {
  18. use rustache::HashBuilder;
  19. let mut hb = HashBuilder::new();
  20. if let Some(ref t) = self.rec.rec_type {
  21. hb = hb.insert("%rec", t.clone());
  22. }
  23. for field in self.rec.fields.iter() {
  24. hb = hb.insert(&field.0, field.1.clone());
  25. }
  26. hb.render(template, writer)
  27. }
  28. }
  29. enum FormatErr {
  30. IOError(io::Error),
  31. Utf8Error(FromUtf8Error),
  32. Rustache(rustache::RustacheError),
  33. Generic(String),
  34. }
  35. impl From<io::Error> for FormatErr {
  36. fn from(err: io::Error) -> FormatErr {
  37. FormatErr::IOError(err)
  38. }
  39. }
  40. impl From<FromUtf8Error> for FormatErr {
  41. fn from(err: FromUtf8Error) -> FormatErr {
  42. FormatErr::Utf8Error(err)
  43. }
  44. }
  45. impl From<rustache::RustacheError> for FormatErr {
  46. fn from(err: rustache::RustacheError) -> FormatErr {
  47. FormatErr::Rustache(err)
  48. }
  49. }
  50. impl From<String> for FormatErr {
  51. fn from(err: String) -> FormatErr {
  52. FormatErr::Generic(err)
  53. }
  54. }
  55. fn run() -> Result<(), FormatErr> {
  56. let matches = clap::App::new("rr-format")
  57. .version("0.0")
  58. .author("Getty Ritter <rrecutils@infinitenegativeutility.com>")
  59. .about("Display the Rust AST for a Recutils file")
  60. .arg(clap::Arg::with_name("input")
  61. .short("i")
  62. .long("input")
  63. .value_name("FILE")
  64. .help("The input recfile (or - for stdin)"))
  65. .arg(clap::Arg::with_name("output")
  66. .short("o")
  67. .long("output")
  68. .value_name("FILE")
  69. .help("The desired output location (or - for stdout)"))
  70. .arg(clap::Arg::with_name("template")
  71. .short("t")
  72. .long("template")
  73. .value_name("FILE")
  74. .help("The template to use"))
  75. .arg(clap::Arg::with_name("joiner")
  76. .short("j")
  77. .long("joiner")
  78. .value_name("STRING")
  79. .help("The string used to separate each fragment"))
  80. .get_matches();
  81. let stdin = io::stdin();
  82. let input: Box<io::BufRead> =
  83. match matches.value_of("input").unwrap_or("-") {
  84. "-" => Box::new(stdin.lock()),
  85. path =>
  86. Box::new(io::BufReader::new(fs::File::open(path)?)),
  87. };
  88. let template: String = match matches.value_of("template") {
  89. Some(path) => {
  90. use io::Read;
  91. let mut buf = Vec::new();
  92. fs::File::open(path)?.read_to_end(&mut buf)?;
  93. String::from_utf8(buf)?
  94. },
  95. None => panic!("No template specified!"),
  96. };
  97. let recfile = rrecutils::Recfile::parse(input)?;
  98. let mut output: Box<io::Write> =
  99. match matches.value_of("output").unwrap_or("-") {
  100. "-" => Box::new(io::stdout()),
  101. path => Box::new(fs::File::open(path)?),
  102. };
  103. for r in recfile.records.into_iter() {
  104. R { rec: r }.render(&template, &mut output.as_mut())?;
  105. }
  106. Ok(())
  107. }
  108. fn main() {
  109. match run() {
  110. Ok(()) => (),
  111. Err(err) => panic!(err),
  112. }
  113. }