difftreelog
refactor(cli) move to split stdlib
in: master
5 files changed
cmds/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" }
crates/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"] }
crates/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(())
- }
-}
crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth1mod 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}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}crates/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(())
+ }
+}