git.delta.rocks / jrsonnet / refs/commits / 2cecfb0ba471

difftreelog

refactor remove GeneralOpts/ConfigureState

Yaroslav Bolyukin2023-01-20parent: #1f5d87f.patch.diff
in: master
Because many options were removed from global state, everything should
be configured manually now

6 files changed

modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
--- 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();
modifiedcrates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth
--- 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<Self::Guards>;
-}
-
 #[derive(Parser)]
 #[clap(next_help_heading = "INPUT")]
 pub struct InputOpts {
@@ -45,50 +39,18 @@
 	#[clap(long, short = 'J')]
 	jpath: Vec<PathBuf>,
 }
-impl ConfigureState for MiscOpts {
-	type Guards = ();
-	fn configure(&self, s: &State) -> Result<Self::Guards> {
+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 = (
-		<TlaOpts as ConfigureState>::Guards,
-		<GcOpts as ConfigureState>::Guards,
-	);
-	fn configure(&self, s: &State) -> Result<Self::Guards> {
-		// 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<GcStatsPrinter>, Option<LeakSpace>);
-
-	fn configure(&self, _s: &State) -> Result<Self::Guards> {
-		// 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<GcStatsPrinter> {
+		self.gc_print_stats.then(|| GcStatsPrinter {
+			collect_before_printing_stats: self.gc_collect_before_printing_stats,
+		})
+	}
+	pub fn leak_on_exit(&self) -> Option<LeakSpace> {
+		(!self.gc_collect_on_exit).then(|| LeakSpace(PhantomData))
 	}
 }
 
modifiedcrates/jrsonnet-cli/src/manifest.rsdiffbeforeafterboth
--- 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<dyn ManifestFormat>;
-	fn configure(&self, _s: &State) -> Result<Self::Guards> {
+impl ManifestOpts {
+	pub fn manifest_format(&self) -> Box<dyn ManifestFormat> {
 		let format: Box<dyn ManifestFormat> = 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
-		})
+		}
 	}
 }
 
modifiedcrates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth
before · crates/jrsonnet-cli/src/stdlib.rs
1use std::{fs::read_to_string, str::FromStr};23use clap::Parser;4use jrsonnet_evaluator::{error::Result, tb, trace::PathResolver, State};56use crate::ConfigureState;78#[derive(Clone)]9pub struct ExtStr {10	pub name: String,11	pub value: String,12}1314impl FromStr for ExtStr {15	type Err = &'static str;16	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {17		let out: Vec<_> = s.split('=').collect();18		match out.len() {19			1 => Ok(ExtStr {20				name: out[0].to_owned(),21				value: std::env::var(out[0]).or(Err("missing env var"))?,22			}),23			2 => Ok(ExtStr {24				name: out[0].to_owned(),25				value: out[1].to_owned(),26			}),2728			_ => Err("bad ext-str syntax"),29		}30	}31}3233#[derive(Clone)]34pub struct ExtFile {35	pub name: String,36	pub value: String,37}3839impl FromStr for ExtFile {40	type Err = String;4142	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {43		let out: Vec<&str> = s.split('=').collect();44		if out.len() != 2 {45			return Err("bad ext-file syntax".to_owned());46		}47		let file = read_to_string(out[1]);48		match file {49			Ok(content) => Ok(Self {50				name: out[0].into(),51				value: content,52			}),53			Err(e) => Err(format!("{}", e)),54		}55	}56}5758#[derive(Parser)]59#[clap(next_help_heading = "STANDARD LIBRARY")]60pub struct StdOpts {61	/// Disable standard library.62	/// By default standard library will be available via global `std` variable.63	#[clap(long)]64	no_stdlib: bool,65	/// Add string external variable.66	/// External variables are globally available so it is preferred67	/// to use top level arguments whenever it's possible.68	/// If [=data] is not set then it will be read from `name` env variable.69	/// Can be accessed from code via `std.extVar("name")`.70	#[clap(long, short = 'V', name = "name[=var data]", number_of_values = 1)]71	ext_str: Vec<ExtStr>,72	/// Read string external variable from file.73	/// See also `--ext-str`74	#[clap(long, name = "name=var path", number_of_values = 1)]75	ext_str_file: Vec<ExtFile>,76	/// Add external variable from code.77	/// See also `--ext-str`78	#[clap(long, name = "name[=var source]", number_of_values = 1)]79	ext_code: Vec<ExtStr>,80	/// Read string external variable from file.81	/// See also `--ext-str`82	#[clap(long, name = "name=var code path", number_of_values = 1)]83	ext_code_file: Vec<ExtFile>,84}85impl ConfigureState for StdOpts {86	type Guards = ();87	fn configure(&self, s: &State) -> Result<()> {88		if self.no_stdlib {89			return Ok(());90		}91		let ctx =92			jrsonnet_stdlib::ContextInitializer::new(s.clone(), PathResolver::new_cwd_fallback());93		for ext in self.ext_str.iter() {94			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());95		}96		for ext in self.ext_str_file.iter() {97			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());98		}99		for ext in self.ext_code.iter() {100			ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;101		}102		for ext in self.ext_code_file.iter() {103			ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;104		}105		s.settings_mut().context_initializer = tb!(ctx);106		Ok(())107	}108}
after · crates/jrsonnet-cli/src/stdlib.rs
1use std::{fs::read_to_string, str::FromStr};23use clap::Parser;4use jrsonnet_evaluator::{error::Result, tb, trace::PathResolver, State};5use jrsonnet_stdlib::ContextInitializer;67#[derive(Clone)]8pub struct ExtStr {9	pub name: String,10	pub value: String,11}1213impl FromStr for ExtStr {14	type Err = &'static str;15	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {16		let out: Vec<_> = s.split('=').collect();17		match out.len() {18			1 => Ok(ExtStr {19				name: out[0].to_owned(),20				value: std::env::var(out[0]).or(Err("missing env var"))?,21			}),22			2 => Ok(ExtStr {23				name: out[0].to_owned(),24				value: out[1].to_owned(),25			}),2627			_ => Err("bad ext-str syntax"),28		}29	}30}3132#[derive(Clone)]33pub struct ExtFile {34	pub name: String,35	pub value: String,36}3738impl FromStr for ExtFile {39	type Err = String;4041	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {42		let out: Vec<&str> = s.split('=').collect();43		if out.len() != 2 {44			return Err("bad ext-file syntax".to_owned());45		}46		let file = read_to_string(out[1]);47		match file {48			Ok(content) => Ok(Self {49				name: out[0].into(),50				value: content,51			}),52			Err(e) => Err(format!("{}", e)),53		}54	}55}5657#[derive(Parser)]58#[clap(next_help_heading = "STANDARD LIBRARY")]59pub struct StdOpts {60	/// Disable standard library.61	/// By default standard library will be available via global `std` variable.62	#[clap(long)]63	no_stdlib: bool,64	/// Add string external variable.65	/// External variables are globally available so it is preferred66	/// to use top level arguments whenever it's possible.67	/// If [=data] is not set then it will be read from `name` env variable.68	/// Can be accessed from code via `std.extVar("name")`.69	#[clap(long, short = 'V', name = "name[=var data]", number_of_values = 1)]70	ext_str: Vec<ExtStr>,71	/// Read string external variable from file.72	/// See also `--ext-str`73	#[clap(long, name = "name=var path", number_of_values = 1)]74	ext_str_file: Vec<ExtFile>,75	/// Add external variable from code.76	/// See also `--ext-str`77	#[clap(long, name = "name[=var source]", number_of_values = 1)]78	ext_code: Vec<ExtStr>,79	/// Read string external variable from file.80	/// See also `--ext-str`81	#[clap(long, name = "name=var code path", number_of_values = 1)]82	ext_code_file: Vec<ExtFile>,83}84impl StdOpts {85	pub fn context_initializer(&self, s: &State) -> Result<Option<ContextInitializer>> {86		if self.no_stdlib {87			return Ok(None);88		}89		let ctx =90			ContextInitializer::new(s.clone(), PathResolver::new_cwd_fallback());91		for ext in self.ext_str.iter() {92			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());93		}94		for ext in self.ext_str_file.iter() {95			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());96		}97		for ext in self.ext_code.iter() {98			ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;99		}100		for ext in self.ext_code_file.iter() {101			ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;102		}103		Ok(Some(ctx))104	}105}
modifiedcrates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth
--- 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<ExtFile>,
 }
-impl ConfigureState for TlaOpts {
-	type Guards = GcHashMap<IStr, TlaArg>;
-	fn configure(&self, _s: &State) -> Result<Self::Guards> {
+impl TlaOpts {
+	pub fn tla_opts(&self) -> Result<GcHashMap<IStr, TlaArg>> {
 		let mut out = GcHashMap::new();
 		for (name, value) in self
 			.tla_str
modifiedcrates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth
--- 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<dyn TraceFormat>;
-	fn configure(&self, _s: &State) -> Result<Self::Guards> {
+impl TraceOpts {
+	pub fn trace_format(&self) -> Box<dyn TraceFormat> {
 		let resolver = PathResolver::new_cwd_fallback();
 		let max_trace = self.max_trace;
 		let format: Box<dyn TraceFormat> = match self
@@ -46,6 +43,6 @@
 				max_trace,
 			}),
 		};
-		Ok(format)
+		format
 	}
 }