Skip to content

Commit

Permalink
Adds pest2ion command (#44)
Browse files Browse the repository at this point in the history
Adds a basic CLI driver over the `pest-ion` crate.  This driver supports
setting the input file (defaulting to STDIN), an output file (defaulting
to STDOUT), and flags around the Ion data format.

An explicit TODO is to figure out a good way to test this probably using
integration tests and spawning the command. (See #42)

Resolves #36.
  • Loading branch information
almann committed Jun 11, 2021
1 parent 0ca2de1 commit 5da7928
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
9 changes: 9 additions & 0 deletions pest-ion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,14 @@ pest = "~2.1.3"
pest_meta = "~2.1.3"
ion-rs = "~0.6.0"

# for pest2ion binary--not sure if this can be modeled separately
clap = "~2.33.3"
anyhow = "~1.0.40"

[dev-dependencies]
rstest = "~0.10.0"

[[bin]]
name = "pest2ion"
test = false
bench = false
82 changes: 82 additions & 0 deletions pest-ion/src/bin/pest2ion/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright Amazon.com, Inc. or its affiliates.

use anyhow::Result;
use clap::{crate_authors, crate_description, crate_version, App, Arg, ArgGroup};
use ion_rs::value::writer::{ElementWriter, Format, TextKind};
use pest_ion::{from_read, TryPestToElement};
use std::fs::File;
use std::io::{stdin, stdout, Write};
use std::path::Path;

fn main() -> Result<()> {
let matches = App::new("Pest to Ion Converter")
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
.arg(
Arg::with_name("INPUT_FILE")
.help("The input file to parse (defaults to STDIN)")
.index(1),
)
.arg(
Arg::with_name("OUTPUT_FILE")
.long("output")
.short("o")
.takes_value(true)
.help("Writes output to the given file (defaults to STDOUT)"),
)
.arg(
Arg::with_name("text")
.long("text")
.short("t")
.help("Generate Ion text (default)"),
)
.arg(
Arg::with_name("binary")
.long("binary")
.short("b")
.help("Generate Ion binary"),
)
.arg(
Arg::with_name("pretty")
.long("pretty")
.short("p")
.help("Generate Ion pretty printed text"),
)
.group(ArgGroup::with_name("format").args(&["text", "binary", "pretty"]))
.get_matches();

let elem = if let Some(file_name) = matches.value_of("INPUT_FILE") {
Path::new(file_name).try_pest_to_element()?
} else {
// no file argument means read from stdin
from_read(stdin()).try_pest_to_element()?
};

// currently Ion element requires a fixed buffer to serialize to, let's choose something
// relatively big until this limitation is lifted
const BUFFER_SIZE: usize = 32 * 1024 * 1024;
let mut out_buf = vec![0u8; BUFFER_SIZE];

let format = if matches.is_present("binary") {
Format::Binary
} else if matches.is_present("pretty") {
Format::Text(TextKind::Pretty)
} else {
Format::Text(TextKind::Compact)
};

let mut writer = format.element_writer_for_slice(&mut out_buf)?;
writer.write(&elem)?;
let out_slice = writer.finish()?;

// TODO make output (file) configurable
let mut out: Box<dyn Write> = if let Some(out_file_name) = matches.value_of("OUTPUT_FILE") {
Box::new(File::create(out_file_name)?)
} else {
Box::new(stdout())
};
out.write_all(&out_slice)?;

Ok(())
}

0 comments on commit 5da7928

Please sign in to comment.