git.delta.rocks / jrsonnet / refs/commits / dde7edac36b0

difftreelog

refactor(cli) move to split stdlib

Yaroslav Bolyukin2022-07-23parent: #06fa714.patch.diff
in: master

5 files changed

modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -15,6 +15,7 @@
     "jrsonnet-evaluator/exp-preserve-order",
     "jrsonnet-evaluator/exp-serde-preserve-order",
     "jrsonnet-cli/exp-preserve-order",
+    "jrsonnet-cli/exp-serde-preserve-order",
 ]
 # Destructuring of locals
 exp-destruct = ["jrsonnet-evaluator/exp-destruct"]
@@ -27,5 +28,5 @@
 
 mimallocator = { version = "0.1.3", optional = true }
 thiserror = "1.0"
-clap = { version = "3.1", features = ["derive"] }
-clap_complete = { version = "3.1" }
+clap = { version = "3.2", features = ["derive"] }
+clap_complete = { version = "3.2" }
modifiedcrates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-cli/Cargo.toml
+++ b/crates/jrsonnet-cli/Cargo.toml
@@ -7,7 +7,14 @@
 edition = "2021"
 
 [features]
-exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]
+exp-preserve-order = [
+    "jrsonnet-evaluator/exp-preserve-order",
+    "jrsonnet-stdlib/exp-preserve-order",
+]
+exp-serde-preserve-order = [
+    "jrsonnet-evaluator/exp-serde-preserve-order",
+    "jrsonnet-stdlib/exp-serde-preserve-order",
+]
 
 [dependencies]
 jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.4.2", features = [
@@ -15,5 +22,6 @@
 ] }
 jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.4.2" }
 jrsonnet-gcmodule = { version = "0.3.4" }
+jrsonnet-stdlib = { path = "../../crates/jrsonnet-stdlib", version = "0.4.2" }
 
-clap = { version = "3.1", features = ["derive"] }
+clap = { version = "3.2", features = ["derive"] }
deletedcrates/jrsonnet-cli/src/ext.rsdiffbeforeafterboth
--- a/crates/jrsonnet-cli/src/ext.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-use std::{fs::read_to_string, str::FromStr};
-
-use clap::Parser;
-use jrsonnet_evaluator::{error::Result, State};
-
-use crate::ConfigureState;
-
-#[derive(Clone)]
-pub struct ExtStr {
-	pub name: String,
-	pub value: String,
-}
-
-impl FromStr for ExtStr {
-	type Err = &'static str;
-	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-		let out: Vec<_> = s.split('=').collect();
-		match out.len() {
-			1 => Ok(ExtStr {
-				name: out[0].to_owned(),
-				value: std::env::var(out[0]).or(Err("missing env var"))?,
-			}),
-			2 => Ok(ExtStr {
-				name: out[0].to_owned(),
-				value: out[1].to_owned(),
-			}),
-
-			_ => Err("bad ext-str syntax"),
-		}
-	}
-}
-
-#[derive(Clone)]
-pub struct ExtFile {
-	pub name: String,
-	pub value: String,
-}
-
-impl FromStr for ExtFile {
-	type Err = String;
-
-	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-		let out: Vec<&str> = s.split('=').collect();
-		if out.len() != 2 {
-			return Err("bad ext-file syntax".to_owned());
-		}
-		let file = read_to_string(&out[1]);
-		match file {
-			Ok(content) => Ok(Self {
-				name: out[0].into(),
-				value: content,
-			}),
-			Err(e) => Err(format!("{}", e)),
-		}
-	}
-}
-
-#[derive(Parser)]
-#[clap(next_help_heading = "EXTERNAL VARIABLES")]
-pub struct ExtVarOpts {
-	/// Add string external variable.
-	/// External variables are globally available so it is preferred
-	/// to use top level arguments whenever it's possible.
-	/// If [=data] is not set then it will be read from `name` env variable.
-	/// Can be accessed from code via `std.extVar("name")`.
-	#[clap(
-		long,
-		short = 'V',
-		name = "name[=var data]",
-		number_of_values = 1,
-		multiple_occurrences = true
-	)]
-	ext_str: Vec<ExtStr>,
-	/// Read string external variable from file.
-	/// See also `--ext-str`
-	#[clap(
-		long,
-		name = "name=var path",
-		number_of_values = 1,
-		multiple_occurrences = true
-	)]
-	ext_str_file: Vec<ExtFile>,
-	/// Add external variable from code.
-	/// See also `--ext-str`
-	#[clap(
-		long,
-		name = "name[=var source]",
-		number_of_values = 1,
-		multiple_occurrences = true
-	)]
-	ext_code: Vec<ExtStr>,
-	/// Read string external variable from file.
-	/// See also `--ext-str`
-	#[clap(
-		long,
-		name = "name=var code path",
-		number_of_values = 1,
-		multiple_occurrences = true
-	)]
-	ext_code_file: Vec<ExtFile>,
-}
-impl ConfigureState for ExtVarOpts {
-	fn configure(&self, s: &State) -> Result<()> {
-		for ext in self.ext_str.iter() {
-			s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
-		}
-		for ext in self.ext_str_file.iter() {
-			s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
-		}
-		for ext in self.ext_code.iter() {
-			s.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;
-		}
-		for ext in self.ext_code_file.iter() {
-			s.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;
-		}
-		Ok(())
-	}
-}
modifiedcrates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth
before · crates/jrsonnet-cli/src/lib.rs
1mod ext;2mod manifest;3mod tla;4mod trace;56use std::{env, path::PathBuf};78use clap::Parser;9pub use ext::*;10use jrsonnet_evaluator::{error::Result, FileImportResolver, State};11use jrsonnet_gcmodule::with_thread_object_space;12pub use manifest::*;13pub use tla::*;14pub use trace::*;1516pub trait ConfigureState {17	fn configure(&self, s: &State) -> Result<()>;18}1920#[derive(Parser)]21#[clap(next_help_heading = "INPUT")]22pub struct InputOpts {23	/// Treat input as code, evaluate them instead of reading file24	#[clap(long, short = 'e')]25	pub exec: bool,2627	/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself28	pub input: String,29}3031#[derive(Parser)]32#[clap(next_help_heading = "OPTIONS")]33pub struct MiscOpts {34	/// Disable standard library.35	/// By default standard library will be available via global `std` variable.36	/// Note that standard library will still be loaded37	/// if chosen manifestification method is not `none`.38	#[clap(long)]39	no_stdlib: bool,4041	/// Maximal allowed number of stack frames,42	/// stack overflow error will be raised if this number gets exceeded.43	#[clap(long, short = 's', default_value = "200")]44	max_stack: usize,4546	/// Library search dirs. (right-most wins)47	/// Any not found `imported` file will be searched in these.48	/// This can also be specified via `JSONNET_PATH` variable,49	/// which should contain a colon-separated (semicolon-separated on Windows) list of directories.50	#[clap(long, short = 'J', multiple_occurrences = true)]51	jpath: Vec<PathBuf>,52}53impl ConfigureState for MiscOpts {54	fn configure(&self, s: &State) -> Result<()> {55		if !self.no_stdlib {56			s.with_stdlib();57		}5859		let mut library_paths = self.jpath.clone();60		library_paths.reverse();61		if let Some(path) = env::var_os("JSONNET_PATH") {62			library_paths.extend(env::split_paths(path.as_os_str()));63		}6465		s.set_import_resolver(Box::new(FileImportResolver { library_paths }));6667		s.set_max_stack(self.max_stack);68		Ok(())69	}70}7172/// General configuration of jsonnet73#[derive(Parser)]74#[clap(name = "jrsonnet", version, author)]75pub struct GeneralOpts {76	#[clap(flatten)]77	misc: MiscOpts,7879	#[clap(flatten)]80	tla: TLAOpts,81	#[clap(flatten)]82	ext: ExtVarOpts,8384	#[clap(flatten)]85	trace: TraceOpts,86}8788impl ConfigureState for GeneralOpts {89	fn configure(&self, s: &State) -> Result<()> {90		// Configure trace first, because tla-code/ext-code can throw91		self.trace.configure(s)?;92		self.misc.configure(s)?;93		self.tla.configure(s)?;94		self.ext.configure(s)?;95		Ok(())96	}97}9899#[derive(Parser)]100#[clap(next_help_heading = "GARBAGE COLLECTION")]101pub struct GcOpts {102	/// Do not skip gc on exit103	#[clap(long)]104	gc_collect_on_exit: bool,105	/// Print gc stats before exit106	#[clap(long)]107	gc_print_stats: bool,108	/// Force garbage collection before printing stats109	/// Useful for checking for memory leaks110	/// Does nothing useless --gc-print-stats is specified111	#[clap(long)]112	gc_collect_before_printing_stats: bool,113}114impl GcOpts {115	pub fn stats_printer(&self) -> (Option<GcStatsPrinter>, Option<LeakSpace>) {116		(117			self.gc_print_stats.then(|| GcStatsPrinter {118				collect_before_printing_stats: self.gc_collect_before_printing_stats,119			}),120			(!self.gc_collect_on_exit).then(|| LeakSpace {}),121		)122	}123}124125pub struct LeakSpace {}126127impl Drop for LeakSpace {128	fn drop(&mut self) {129		with_thread_object_space(|s| s.leak())130	}131}132133pub struct GcStatsPrinter {134	collect_before_printing_stats: bool,135}136impl Drop for GcStatsPrinter {137	fn drop(&mut self) {138		eprintln!("=== GC STATS ===");139		if self.collect_before_printing_stats {140			let collected = jrsonnet_gcmodule::collect_thread_cycles();141			eprintln!("Collected: {}", collected);142		}143		eprintln!("Tracked: {}", jrsonnet_gcmodule::count_thread_tracked())144	}145}
after · crates/jrsonnet-cli/src/lib.rs
1mod manifest;2mod stdlib;3mod tla;4mod trace;56use std::{env, path::PathBuf};78use clap::Parser;9use jrsonnet_evaluator::{error::Result, FileImportResolver, State};10use jrsonnet_gcmodule::with_thread_object_space;11pub use manifest::*;12pub use stdlib::*;13pub use tla::*;14pub use trace::*;1516pub trait ConfigureState {17	fn configure(&self, s: &State) -> Result<()>;18}1920#[derive(Parser)]21#[clap(next_help_heading = "INPUT")]22pub struct InputOpts {23	/// Treat input as code, evaluate them instead of reading file24	#[clap(long, short = 'e')]25	pub exec: bool,2627	/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself28	pub input: String,29}3031#[derive(Parser)]32#[clap(next_help_heading = "OPTIONS")]33pub struct MiscOpts {34	/// Maximal allowed number of stack frames,35	/// stack overflow error will be raised if this number gets exceeded.36	#[clap(long, short = 's', default_value = "200")]37	max_stack: usize,3839	/// Library search dirs. (right-most wins)40	/// Any not found `imported` file will be searched in these.41	/// This can also be specified via `JSONNET_PATH` variable,42	/// which should contain a colon-separated (semicolon-separated on Windows) list of directories.43	#[clap(long, short = 'J', multiple_occurrences = true)]44	jpath: Vec<PathBuf>,45}46impl ConfigureState for MiscOpts {47	fn configure(&self, s: &State) -> Result<()> {48		let mut library_paths = self.jpath.clone();49		library_paths.reverse();50		if let Some(path) = env::var_os("JSONNET_PATH") {51			library_paths.extend(env::split_paths(path.as_os_str()));52		}5354		s.set_import_resolver(Box::new(FileImportResolver { library_paths }));5556		s.set_max_stack(self.max_stack);57		Ok(())58	}59}6061/// General configuration of jsonnet62#[derive(Parser)]63#[clap(name = "jrsonnet", version, author)]64pub struct GeneralOpts {65	#[clap(flatten)]66	misc: MiscOpts,6768	#[clap(flatten)]69	tla: TLAOpts,70	#[clap(flatten)]71	std: StdOpts,7273	#[clap(flatten)]74	trace: TraceOpts,75}7677impl ConfigureState for GeneralOpts {78	fn configure(&self, s: &State) -> Result<()> {79		// Configure trace first, because tla-code/ext-code can throw80		self.trace.configure(s)?;81		self.misc.configure(s)?;82		self.tla.configure(s)?;83		self.std.configure(s)?;84		Ok(())85	}86}8788#[derive(Parser)]89#[clap(next_help_heading = "GARBAGE COLLECTION")]90pub struct GcOpts {91	/// Do not skip gc on exit92	#[clap(long)]93	gc_collect_on_exit: bool,94	/// Print gc stats before exit95	#[clap(long)]96	gc_print_stats: bool,97	/// Force garbage collection before printing stats98	/// Useful for checking for memory leaks99	/// Does nothing useless --gc-print-stats is specified100	#[clap(long)]101	gc_collect_before_printing_stats: bool,102}103impl GcOpts {104	pub fn stats_printer(&self) -> (Option<GcStatsPrinter>, Option<LeakSpace>) {105		(106			self.gc_print_stats.then_some(GcStatsPrinter {107				collect_before_printing_stats: self.gc_collect_before_printing_stats,108			}),109			(!self.gc_collect_on_exit).then_some(LeakSpace {}),110		)111	}112}113114pub struct LeakSpace {}115116impl Drop for LeakSpace {117	fn drop(&mut self) {118		with_thread_object_space(|s| s.leak())119	}120}121122pub struct GcStatsPrinter {123	collect_before_printing_stats: bool,124}125impl Drop for GcStatsPrinter {126	fn drop(&mut self) {127		eprintln!("=== GC STATS ===");128		if self.collect_before_printing_stats {129			let collected = jrsonnet_gcmodule::collect_thread_cycles();130			eprintln!("Collected: {}", collected);131		}132		eprintln!("Tracked: {}", jrsonnet_gcmodule::count_thread_tracked())133	}134}
addedcrates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-cli/src/stdlib.rs
@@ -0,0 +1,129 @@
+use std::{fs::read_to_string, str::FromStr};
+
+use clap::Parser;
+use jrsonnet_evaluator::{error::Result, State};
+
+use crate::ConfigureState;
+
+#[derive(Clone)]
+pub struct ExtStr {
+	pub name: String,
+	pub value: String,
+}
+
+impl FromStr for ExtStr {
+	type Err = &'static str;
+	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+		let out: Vec<_> = s.split('=').collect();
+		match out.len() {
+			1 => Ok(ExtStr {
+				name: out[0].to_owned(),
+				value: std::env::var(out[0]).or(Err("missing env var"))?,
+			}),
+			2 => Ok(ExtStr {
+				name: out[0].to_owned(),
+				value: out[1].to_owned(),
+			}),
+
+			_ => Err("bad ext-str syntax"),
+		}
+	}
+}
+
+#[derive(Clone)]
+pub struct ExtFile {
+	pub name: String,
+	pub value: String,
+}
+
+impl FromStr for ExtFile {
+	type Err = String;
+
+	fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+		let out: Vec<&str> = s.split('=').collect();
+		if out.len() != 2 {
+			return Err("bad ext-file syntax".to_owned());
+		}
+		let file = read_to_string(&out[1]);
+		match file {
+			Ok(content) => Ok(Self {
+				name: out[0].into(),
+				value: content,
+			}),
+			Err(e) => Err(format!("{}", e)),
+		}
+	}
+}
+
+#[derive(Parser)]
+#[clap(next_help_heading = "STANDARD LIBRARY")]
+pub struct StdOpts {
+	/// Disable standard library.
+	/// By default standard library will be available via global `std` variable.
+	/// Note that standard library will still be loaded
+	/// if chosen manifestification method is not `none`.
+	#[clap(long)]
+	no_stdlib: bool,
+	/// Add string external variable.
+	/// External variables are globally available so it is preferred
+	/// to use top level arguments whenever it's possible.
+	/// If [=data] is not set then it will be read from `name` env variable.
+	/// Can be accessed from code via `std.extVar("name")`.
+	#[clap(
+		long,
+		short = 'V',
+		name = "name[=var data]",
+		number_of_values = 1,
+		multiple_occurrences = true
+	)]
+	ext_str: Vec<ExtStr>,
+	/// Read string external variable from file.
+	/// See also `--ext-str`
+	#[clap(
+		long,
+		name = "name=var path",
+		number_of_values = 1,
+		multiple_occurrences = true
+	)]
+	ext_str_file: Vec<ExtFile>,
+	/// Add external variable from code.
+	/// See also `--ext-str`
+	#[clap(
+		long,
+		name = "name[=var source]",
+		number_of_values = 1,
+		multiple_occurrences = true
+	)]
+	ext_code: Vec<ExtStr>,
+	/// Read string external variable from file.
+	/// See also `--ext-str`
+	#[clap(
+		long,
+		name = "name=var code path",
+		number_of_values = 1,
+		multiple_occurrences = true
+	)]
+	ext_code_file: Vec<ExtFile>,
+}
+impl ConfigureState for StdOpts {
+	fn configure(&self, s: &State) -> Result<()> {
+		if self.no_stdlib {
+			return Ok(());
+		}
+		let ctx = jrsonnet_stdlib::ContextInitializer::new(s.clone());
+		for ext in self.ext_str.iter() {
+			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
+		}
+		for ext in self.ext_str_file.iter() {
+			ctx.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());
+		}
+		for ext in self.ext_code.iter() {
+			ctx.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;
+		}
+		for ext in self.ext_code_file.iter() {
+			ctx.add_ext_code(&ext.name as &str, (&ext.value as &str).into())?;
+		}
+		s.settings_mut().context_initializer = Box::new(ctx);
+		Ok(())
+	}
+}