--- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,7 @@ "jrsonnet-evaluator", "jrsonnet-parser", "mimallocator", + "thiserror", ] [[package]] @@ -176,6 +177,7 @@ "serde", "serde_json", "structdump", + "thiserror", ] [[package]] @@ -429,6 +431,26 @@ ] [[package]] +name = "thiserror" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "unescape" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" --- a/cmds/jrsonnet/Cargo.toml +++ b/cmds/jrsonnet/Cargo.toml @@ -19,6 +19,7 @@ jrsonnet-cli = { path = "../../crates/jrsonnet-cli", version = "0.1.0" } # TODO: Fix mimalloc compile errors, and use them mimallocator = { version = "0.1.3", optional = true } +thiserror = "1.0.20" [dependencies.clap] git = "https://github.com/clap-rs/clap" --- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -1,7 +1,12 @@ use clap::Clap; -use jrsonnet_cli::{ConfigureState, GeneralOpts, InputOpts, ManifestOpts}; -use jrsonnet_evaluator::{error::Result, EvaluationState}; -use std::{path::PathBuf, rc::Rc}; +use jrsonnet_cli::{ConfigureState, GeneralOpts, InputOpts, ManifestOpts, OutputOpts}; +use jrsonnet_evaluator::{error::LocError, EvaluationState}; +use std::{ + fs::{create_dir_all, File}, + io::Write, + path::PathBuf, + rc::Rc, +}; #[cfg(feature = "mimalloc")] #[global_allocator] @@ -25,6 +30,8 @@ #[clap(flatten)] manifest: ManifestOpts, #[clap(flatten)] + output: OutputOpts, + #[clap(flatten)] debug: DebugOpts, } @@ -42,14 +49,32 @@ } } +#[derive(thiserror::Error, Debug)] +enum Error { + // Handled differently + #[error("evaluation error")] + Evaluation(jrsonnet_evaluator::error::LocError), + #[error("io error")] + Io(#[from] std::io::Error), +} +impl From for Error { + fn from(e: LocError) -> Self { + Self::Evaluation(e) + } +} + fn main_catch(opts: Opts) { let state = EvaluationState::default(); if let Err(e) = main_real(&state, opts) { - println!("{}", state.stringify_err(&e)); + if let Error::Evaluation(e) = e { + println!("{}", state.stringify_err(&e)); + } else { + println!("{}", e); + } } } -fn main_real(state: &EvaluationState, opts: Opts) -> Result<()> { +fn main_real(state: &EvaluationState, opts: Opts) -> Result<(), Error> { opts.general.configure(&state)?; opts.manifest.configure(&state)?; @@ -64,7 +89,34 @@ let val = state.with_tla(val)?; - println!("{}", state.manifest(val)?); + if let Some(multi) = opts.output.multi { + if opts.output.create_output_dirs { + let mut dir = multi.clone(); + dir.pop(); + create_dir_all(dir)?; + } + for (file, data) in state.manifest_multi(val)?.iter() { + let mut path = multi.clone(); + path.push(&file as &str); + if opts.output.create_output_dirs { + let mut dir = path.clone(); + dir.pop(); + create_dir_all(dir)?; + } + let mut file = File::create(path)?; + write!(file, "{}", data)?; + } + } else if let Some(path) = opts.output.output_file { + if opts.output.create_output_dirs { + let mut dir = path.clone(); + dir.pop(); + create_dir_all(dir)?; + } + let mut file = File::create(path)?; + write!(file, "{}", state.manifest(val)?)?; + } else { + println!("{}", state.manifest(val)?); + } Ok(()) }