--- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -5,7 +5,7 @@ use clap::{CommandFactory, Parser}; use clap_complete::Shell; -use jrsonnet_cli::{ConfigureState, GeneralOpts, ManifestOpts, OutputOpts, TraceOpts}; +use jrsonnet_cli::{ManifestOpts, OutputOpts, TraceOpts, MiscOpts, TlaOpts, StdOpts, GcOpts}; use jrsonnet_evaluator::{ apply_tla, error::{Error as JrError, ErrorKind}, @@ -60,7 +60,13 @@ #[clap(flatten)] input: InputOpts, #[clap(flatten)] - general: GeneralOpts, + misc: MiscOpts, + #[clap(flatten)] + tla: TlaOpts, + #[clap(flatten)] + std: StdOpts, + #[clap(flatten)] + gc: GcOpts, #[clap(flatten)] trace: TraceOpts, @@ -129,8 +135,7 @@ let s = State::default(); let trace = opts .trace - .configure(&s) - .expect("this configurator doesn't fail"); + .trace_format(); if let Err(e) = main_real(&s, opts) { if let Error::Evaluation(e) = e { let mut out = String::new(); @@ -145,8 +150,17 @@ } fn main_real(s: &State, opts: Opts) -> Result<(), Error> { - let (tla, _gc_guard) = opts.general.configure(s)?; - let manifest_format = opts.manifest.configure(s)?; + let _gc_leak_guard= opts.gc.leak_on_exit(); + let _gc_print_stats = opts.gc.stats_printer(); + let _stack_depth_override = opts.misc.stack_size_override(); + + let import_resolver = opts.misc.import_resolver(); + s.set_import_resolver(import_resolver); + + let std = opts.std.context_initializer(s)?; + if let Some(std) = std { + s.set_context_initializer(std); + } let input = opts.input.input.ok_or(Error::MissingInputArgument)?; let val = if opts.input.exec { @@ -160,8 +174,10 @@ s.import(&input)? }; + let tla = opts.tla.tla_opts()?; let val = apply_tla(s.clone(), &tla, val)?; + let manifest_format = opts.manifest.manifest_format(); if let Some(multi) = opts.output.multi { if opts.output.create_output_dirs { let mut dir = multi.clone(); --- a/crates/jrsonnet-cli/src/lib.rs +++ b/crates/jrsonnet-cli/src/lib.rs @@ -6,19 +6,13 @@ use std::{env, marker::PhantomData, path::PathBuf}; use clap::Parser; -use jrsonnet_evaluator::{error::Result, stack::set_stack_depth_limit, FileImportResolver, State}; +use jrsonnet_evaluator::{error::Result, stack::{set_stack_depth_limit, StackDepthLimitOverrideGuard, limit_stack_depth}, FileImportResolver, State, ImportResolver}; use jrsonnet_gcmodule::with_thread_object_space; pub use manifest::*; pub use stdlib::*; pub use tla::*; pub use trace::*; - -pub trait ConfigureState { - type Guards; - fn configure(&self, s: &State) -> Result; -} - #[derive(Parser)] #[clap(next_help_heading = "INPUT")] pub struct InputOpts { @@ -45,50 +39,18 @@ #[clap(long, short = 'J')] jpath: Vec, } -impl ConfigureState for MiscOpts { - type Guards = (); - fn configure(&self, s: &State) -> Result { +impl MiscOpts { + pub fn import_resolver(&self) -> FileImportResolver { let mut library_paths = self.jpath.clone(); library_paths.reverse(); if let Some(path) = env::var_os("JSONNET_PATH") { library_paths.extend(env::split_paths(path.as_os_str())); } - s.set_import_resolver(FileImportResolver::new(library_paths)); - - set_stack_depth_limit(self.max_stack); - Ok(()) + FileImportResolver::new(library_paths) } -} - -/// General configuration of jsonnet -#[derive(Parser)] -#[clap(name = "jrsonnet", version, author)] -pub struct GeneralOpts { - #[clap(flatten)] - misc: MiscOpts, - - #[clap(flatten)] - tla: TlaOpts, - #[clap(flatten)] - std: StdOpts, - - #[clap(flatten)] - gc: GcOpts, -} - -impl ConfigureState for GeneralOpts { - type Guards = ( - ::Guards, - ::Guards, - ); - fn configure(&self, s: &State) -> Result { - // Configure trace first, because tla-code/ext-code can throw - self.misc.configure(s)?; - let tla_guards = self.tla.configure(s)?; - self.std.configure(s)?; - let gc_guards = self.gc.configure(s)?; - Ok((tla_guards, gc_guards)) + pub fn stack_size_override(&self) -> StackDepthLimitOverrideGuard { + limit_stack_depth(self.max_stack) } } @@ -107,18 +69,14 @@ #[clap(long)] gc_collect_before_printing_stats: bool, } -impl ConfigureState for GcOpts { - type Guards = (Option, Option); - - fn configure(&self, _s: &State) -> Result { - // Constructed structs have side-effects in Drop impl - #[allow(clippy::unnecessary_lazy_evaluations)] - Ok(( - self.gc_print_stats.then(|| GcStatsPrinter { - collect_before_printing_stats: self.gc_collect_before_printing_stats, - }), - (!self.gc_collect_on_exit).then(|| LeakSpace(PhantomData)), - )) +impl GcOpts { + pub fn stats_printer(&self) -> Option { + self.gc_print_stats.then(|| GcStatsPrinter { + collect_before_printing_stats: self.gc_collect_before_printing_stats, + }) + } + pub fn leak_on_exit(&self) -> Option { + (!self.gc_collect_on_exit).then(|| LeakSpace(PhantomData)) } } --- a/crates/jrsonnet-cli/src/manifest.rs +++ b/crates/jrsonnet-cli/src/manifest.rs @@ -8,8 +8,6 @@ }; use jrsonnet_stdlib::{TomlFormat, YamlFormat}; -use crate::ConfigureState; - #[derive(Clone, ValueEnum)] pub enum ManifestFormatName { /// Expect string as output, and write them directly @@ -41,9 +39,8 @@ #[clap(long)] pub preserve_order: bool, } -impl ConfigureState for ManifestOpts { - type Guards = Box; - fn configure(&self, _s: &State) -> Result { +impl ManifestOpts { + pub fn manifest_format(&self) -> Box { let format: Box = if self.string { Box::new(StringFormat) } else { @@ -68,11 +65,11 @@ )), } }; - Ok(if self.yaml_stream { + if self.yaml_stream { Box::new(YamlStreamFormat(format)) } else { format - }) + } } } --- a/crates/jrsonnet-cli/src/stdlib.rs +++ b/crates/jrsonnet-cli/src/stdlib.rs @@ -2,8 +2,7 @@ use clap::Parser; use jrsonnet_evaluator::{error::Result, tb, trace::PathResolver, State}; - -use crate::ConfigureState; +use jrsonnet_stdlib::ContextInitializer; #[derive(Clone)] pub struct ExtStr { @@ -82,14 +81,13 @@ #[clap(long, name = "name=var code path", number_of_values = 1)] ext_code_file: Vec, } -impl ConfigureState for StdOpts { - type Guards = (); - fn configure(&self, s: &State) -> Result<()> { +impl StdOpts { + pub fn context_initializer(&self, s: &State) -> Result> { if self.no_stdlib { - return Ok(()); + return Ok(None); } let ctx = - jrsonnet_stdlib::ContextInitializer::new(s.clone(), PathResolver::new_cwd_fallback()); + ContextInitializer::new(s.clone(), PathResolver::new_cwd_fallback()); for ext in self.ext_str.iter() { ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into()); } @@ -102,7 +100,6 @@ for ext in self.ext_code_file.iter() { ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?; } - s.settings_mut().context_initializer = tb!(ctx); - Ok(()) + Ok(Some(ctx)) } } --- a/crates/jrsonnet-cli/src/tla.rs +++ b/crates/jrsonnet-cli/src/tla.rs @@ -7,7 +7,7 @@ }; use jrsonnet_parser::{ParserSettings, Source}; -use crate::{ConfigureState, ExtFile, ExtStr}; +use crate::{ExtFile, ExtStr}; #[derive(Parser)] #[clap(next_help_heading = "TOP LEVEL ARGUMENTS")] @@ -31,9 +31,8 @@ #[clap(long, name = "name=tla code path", number_of_values = 1)] tla_code_file: Vec, } -impl ConfigureState for TlaOpts { - type Guards = GcHashMap; - fn configure(&self, _s: &State) -> Result { +impl TlaOpts { + pub fn tla_opts(&self) -> Result> { let mut out = GcHashMap::new(); for (name, value) in self .tla_str --- a/crates/jrsonnet-cli/src/trace.rs +++ b/crates/jrsonnet-cli/src/trace.rs @@ -5,8 +5,6 @@ State, }; -use crate::ConfigureState; - #[derive(PartialEq, Eq, ValueEnum, Clone)] pub enum TraceFormatName { /// Only show `filename:line:column` @@ -26,9 +24,8 @@ #[clap(long, short = 't', default_value = "20")] max_trace: usize, } -impl ConfigureState for TraceOpts { - type Guards = Box; - fn configure(&self, _s: &State) -> Result { +impl TraceOpts { + pub fn trace_format(&self) -> Box { let resolver = PathResolver::new_cwd_fallback(); let max_trace = self.max_trace; let format: Box = match self @@ -46,6 +43,6 @@ max_trace, }), }; - Ok(format) + format } }