From 1feb056f19c362398d42fb441ae25c985aca7679 Mon Sep 17 00:00:00 2001 From: Lach Date: Sat, 22 Aug 2020 19:37:24 +0000 Subject: [PATCH] feat: yaml stream output --- --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -54,7 +54,7 @@ #[no_mangle] pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) { match v { - 1 => vm.set_manifest_format(ManifestFormat::None), + 1 => vm.set_manifest_format(ManifestFormat::String), 0 => vm.set_manifest_format(ManifestFormat::Json(4)), _ => panic!("incorrect output format"), } --- a/crates/jrsonnet-cli/src/manifest.rs +++ b/crates/jrsonnet-cli/src/manifest.rs @@ -5,7 +5,7 @@ pub enum ManifestFormatName { /// Expect string as output, and write them directly - None, + String, Json, Yaml, } @@ -14,7 +14,7 @@ type Err = &'static str; fn from_str(s: &str) -> std::result::Result { Ok(match s { - "none" => ManifestFormatName::None, + "string" => ManifestFormatName::String, "json" => ManifestFormatName::Json, "yaml" => ManifestFormatName::Yaml, _ => return Err("no such format"), @@ -27,14 +27,17 @@ // #[clap(group = clap::ArgGroup::new("output_format"), help_heading = "MANIFESTIFICATION OUTPUT")] pub struct ManifestOpts { /// Output format, wraps resulting value to corresponding std.manifest call. - /// If none - then jsonnet file is expected to return plain string value, otherwise + /// If string - then jsonnet file is expected to return plain string value, otherwise /// output will be serialized to specified format - #[clap(long, short = 'f', default_value = "json", possible_values = &["none", "json", "yaml"]/*, group = "output_format"*/)] + #[clap(long, short = 'f', default_value = "json", possible_values = &["string", "json", "yaml"]/*, group = "output_format"*/)] format: ManifestFormatName, /// Expect string as output, and write them directly. - /// Shortcut for --format=none, and can't be set with format together + /// Shortcut for --format=string, and can't be set with format together #[clap(long, short = 'S'/*, group = "output_format"*/)] string: bool, + /// Write output as YAML stream, can be used with --format json/yaml + #[clap(long, short = 'y')] + yaml_stream: bool, /// Numbed of spaces to pad output manifest with. /// 0 for hard tabs, -1 for single line output #[clap(long, default_value = "3")] @@ -43,10 +46,10 @@ impl ConfigureState for ManifestOpts { fn configure(&self, state: &EvaluationState) -> Result<()> { if self.string { - state.set_manifest_format(ManifestFormat::None); + state.set_manifest_format(ManifestFormat::String); } else { match self.format { - ManifestFormatName::None => state.set_manifest_format(ManifestFormat::None), + ManifestFormatName::String => state.set_manifest_format(ManifestFormat::String), ManifestFormatName::Json => { state.set_manifest_format(ManifestFormat::Json(self.line_padding)) } @@ -55,6 +58,11 @@ } } } + if self.yaml_stream { + state.set_manifest_format(ManifestFormat::YamlStream(Box::new( + state.manifest_format(), + ))) + } Ok(()) } } --- a/crates/jrsonnet-evaluator/src/error.rs +++ b/crates/jrsonnet-evaluator/src/error.rs @@ -58,6 +58,11 @@ DivisionByZero, StringManifestOutputIsNotAString, + StreamManifestOutputIsNotAArray, + MultiManifestOutputIsNotAObject, + + StreamManifestOutputCannotBeRecursed, + StreamManifestCannotNestString, ImportCallbackError(String), InvalidUnicodeCodepointGot(u32), --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -53,13 +53,6 @@ } } -#[derive(Clone)] -pub enum ManifestFormat { - Yaml(usize), - Json(usize), - None, -} - pub struct EvaluationSettings { /// Limits recursion by limiting stack frames pub max_stack: usize, @@ -321,16 +314,7 @@ } pub fn manifest(&self, val: Val) -> Result> { - self.run_in_state(|| { - Ok(match self.manifest_format() { - ManifestFormat::Yaml(padding) => val.into_yaml(padding)?, - ManifestFormat::Json(padding) => val.into_json(padding)?, - ManifestFormat::None => match val { - Val::Str(s) => s, - _ => throw!(StringManifestOutputIsNotAString), - }, - }) - }) + self.run_in_state(|| val.manifest(&self.manifest_format())) } /// If passed value is function - call with set TLA @@ -521,7 +505,7 @@ evaluator .evaluate_snippet_raw(Rc::new(PathBuf::from("raw.jsonnet")), $str.into()) .unwrap() - .into_json(0) + .to_json(0) .unwrap() .replace("\n", "") }) --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -131,6 +131,14 @@ } } +#[derive(Clone)] +pub enum ManifestFormat { + YamlStream(Box), + Yaml(usize), + Json(usize), + String, +} + #[derive(Debug, Clone)] pub enum Val { Bool(bool), @@ -221,10 +229,46 @@ }) } + + pub fn manifest(&self, ty: &ManifestFormat) -> Result> { + Ok(match ty { + ManifestFormat::YamlStream(format) => { + let arr = match self { + Val::Arr(a) => a, + _ => throw!(StreamManifestOutputIsNotAArray), + }; + let mut out = String::new(); + + match format as &ManifestFormat { + ManifestFormat::YamlStream(_) => throw!(StreamManifestOutputCannotBeRecursed), + ManifestFormat::String => throw!(StreamManifestCannotNestString), + _ => {} + }; + + if !arr.is_empty() { + for v in arr.iter() { + out.push_str("---\n"); + out.push_str(&v.manifest(format)?); + out.push_str("\n"); + } + out.push_str("..."); + } + + out.into() + } + ManifestFormat::Yaml(padding) => self.to_yaml(*padding)?, + ManifestFormat::Json(padding) => self.to_json(*padding)?, + ManifestFormat::String => match self { + Val::Str(s) => s.clone(), + _ => throw!(StringManifestOutputIsNotAString), + }, + }) + } + /// For manifestification - pub fn into_json(self, padding: usize) -> Result> { + pub fn to_json(&self, padding: usize) -> Result> { manifest_json_ex( - &self, + self, &ManifestJsonOptions { padding: &" ".repeat(padding), mtype: if padding == 0 { @@ -239,7 +283,7 @@ /// Calls std.manifestJson #[cfg(feature = "faster")] - pub fn into_std_json(self, padding: usize) -> Result> { + pub fn to_std_json(&self, padding: usize) -> Result> { manifest_json_ex( &self, &ManifestJsonOptions { @@ -252,11 +296,11 @@ /// Calls std.manifestJson #[cfg(not(feature = "faster"))] - pub fn into_std_json(self, padding: usize) -> Result> { + pub fn to_std_json(&self, padding: usize) -> Result> { with_state(|s| { let ctx = s .create_default_context()? - .with_var("__tmp__to_json__".into(), self)?; + .with_var("__tmp__to_json__".into(), self.clone())?; Ok(evaluate( ctx, &el!(Expr::Apply( @@ -274,11 +318,11 @@ .try_cast_str("to json")?) }) } - pub fn into_yaml(self, padding: usize) -> Result> { + pub fn to_yaml(&self, padding: usize) -> Result> { with_state(|s| { let ctx = s .create_default_context()? - .with_var("__tmp__to_json__".into(), self); + .with_var("__tmp__to_json__".into(), self.clone()); Ok(evaluate( ctx, &el!(Expr::Apply( -- gitstuff