format.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. extern crate clap;
  2. extern crate rrecutils;
  3. extern crate rustache;
  4. #[macro_use]
  5. extern crate failure;
  6. use std::{fs, io};
  7. mod common;
  8. use rustache::Render;
  9. struct R {
  10. rec: rrecutils::Record,
  11. }
  12. impl Render for R {
  13. fn render<W: io::Write>(
  14. &self,
  15. template: &str,
  16. writer: &mut W,
  17. ) -> Result<(), rustache::RustacheError> {
  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. fn rr_format_args() -> clap::ArgMatches<'static> {
  30. clap::App::new("rr-format")
  31. .version(common::VERSION)
  32. .author(common::AUTHOR)
  33. .about("Display the Rust AST for a Recutils file")
  34. .arg(
  35. clap::Arg::with_name("input")
  36. .short("i")
  37. .long("input")
  38. .value_name("FILE")
  39. .help("The input recfile (or - for stdin)"),
  40. )
  41. .arg(
  42. clap::Arg::with_name("output")
  43. .short("o")
  44. .long("output")
  45. .value_name("FILE")
  46. .help("The desired output location (or - for stdout)"),
  47. )
  48. .arg(
  49. clap::Arg::with_name("mustache")
  50. .short("m")
  51. .long("mustache")
  52. .value_name("FILE")
  53. .help("The mustache template to use"),
  54. )
  55. .arg(
  56. clap::Arg::with_name("type")
  57. .short("t")
  58. .long("type")
  59. .value_name("TYPE")
  60. .takes_value(true)
  61. .help("The type of records to pass to the mustache file"),
  62. )
  63. .arg(
  64. clap::Arg::with_name("joiner")
  65. .short("j")
  66. .long("joiner")
  67. .value_name("STRING")
  68. .help("The string used to separate each fragment"),
  69. )
  70. .get_matches()
  71. }
  72. fn run() -> Result<(), failure::Error> {
  73. let matches = rr_format_args();
  74. let input = common::input_from_spec(matches.value_of("input"))?;
  75. let mut output = common::output_from_spec(matches.value_of("output"))?;
  76. let template: String = match matches.value_of("mustache") {
  77. Some(path) => {
  78. use io::Read;
  79. let mut buf = Vec::new();
  80. fs::File::open(path)?.read_to_end(&mut buf)?;
  81. String::from_utf8(buf)?
  82. }
  83. None => bail!("No template specified!"),
  84. };
  85. let mut recfile = rrecutils::Recfile::parse(input)?;
  86. if let Some(typ) = matches.value_of("type") {
  87. recfile.filter_by_type(typ);
  88. }
  89. let joiner = matches.value_of("joiner");
  90. let mut first = true;
  91. for r in recfile.records.into_iter() {
  92. if first {
  93. first = false;
  94. } else if let Some(j) = joiner {
  95. output.write(j.as_bytes())?;
  96. output.write(&['\n' as u8])?;
  97. }
  98. R { rec: r }
  99. .render(&template, &mut output.as_mut())
  100. .map_err(|e| format_err!("Rustache error: {:?}", e))?;
  101. }
  102. Ok(())
  103. }
  104. fn main() {
  105. match run() {
  106. Ok(()) => (),
  107. Err(e) => println!("{}", e),
  108. }
  109. }