difftreelog
refactor remove GeneralOpts/ConfigureState
in: master
Because many options were removed from global state, everything should be configured manually now
6 files changed
cmds/jrsonnet/src/main.rsdiffbeforeafterboth1use std::{2 fs::{create_dir_all, File},3 io::{Read, Write},4};56use clap::{CommandFactory, Parser};7use clap_complete::Shell;8use jrsonnet_cli::{ConfigureState, GeneralOpts, ManifestOpts, OutputOpts, TraceOpts};9use jrsonnet_evaluator::{10 apply_tla,11 error::{Error as JrError, ErrorKind},12 throw, ResultExt, State, Val,13};1415#[cfg(feature = "mimalloc")]16#[global_allocator]17static GLOBAL: mimallocator::Mimalloc = mimallocator::Mimalloc;1819#[derive(Parser)]20enum SubOpts {21 /// Generate completions for specified shell22 Generate {23 /// Target shell name24 shell: Shell,25 },26}2728#[derive(Parser)]29#[clap(next_help_heading = "DEBUG")]30struct DebugOpts {31 /// Required OS stack size.32 /// This shouldn't be changed unless jrsonnet is failing with stack overflow error.33 #[clap(long, name = "size")]34 pub os_stack: Option<usize>,35}3637#[derive(Parser)]38#[clap(next_help_heading = "INPUT")]39struct InputOpts {40 /// Treat input as code, evaluate them instead of reading file41 #[clap(long, short = 'e')]42 pub exec: bool,4344 /// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself45 pub input: Option<String>,46}4748/// Jsonnet commandline interpreter (Rust implementation)49#[derive(Parser)]50#[clap(51 args_conflicts_with_subcommands = true,52 disable_version_flag = true,53 version,54 author55)]56struct Opts {57 #[clap(subcommand)]58 sub: Option<SubOpts>,5960 #[clap(flatten)]61 input: InputOpts,62 #[clap(flatten)]63 general: GeneralOpts,6465 #[clap(flatten)]66 trace: TraceOpts,67 #[clap(flatten)]68 manifest: ManifestOpts,69 #[clap(flatten)]70 output: OutputOpts,71 #[clap(flatten)]72 debug: DebugOpts,73}7475fn main() {76 let opts: Opts = Opts::parse();7778 if let Some(sub) = opts.sub {79 match sub {80 SubOpts::Generate { shell } => {81 use clap_complete::generate;82 let app = &mut Opts::command();83 let buf = &mut std::io::stdout();84 generate(shell, app, "jrsonnet", buf);85 std::process::exit(0)86 }87 }88 }8990 let success = if let Some(size) = opts.debug.os_stack {91 std::thread::Builder::new()92 .stack_size(size * 1024 * 1024)93 .spawn(|| main_catch(opts))94 .expect("new thread spawned")95 .join()96 .expect("thread finished successfully")97 } else {98 main_catch(opts)99 };100 if !success {101 std::process::exit(1);102 }103}104105#[derive(thiserror::Error, Debug)]106enum Error {107 // Handled differently108 #[error("evaluation error")]109 Evaluation(JrError),110 #[error("io error")]111 Io(#[from] std::io::Error),112 #[error("input is not utf8 encoded")]113 Utf8(#[from] std::str::Utf8Error),114 #[error("missing input argument")]115 MissingInputArgument,116}117impl From<JrError> for Error {118 fn from(e: JrError) -> Self {119 Self::Evaluation(e)120 }121}122impl From<ErrorKind> for Error {123 fn from(e: ErrorKind) -> Self {124 Self::from(JrError::from(e))125 }126}127128fn main_catch(opts: Opts) -> bool {129 let s = State::default();130 let trace = opts131 .trace132 .configure(&s)133 .expect("this configurator doesn't fail");134 if let Err(e) = main_real(&s, opts) {135 if let Error::Evaluation(e) = e {136 let mut out = String::new();137 trace.write_trace(&mut out, &e).expect("format error");138 eprintln!("{out}")139 } else {140 eprintln!("{}", e);141 }142 return false;143 }144 true145}146147fn main_real(s: &State, opts: Opts) -> Result<(), Error> {148 let (tla, _gc_guard) = opts.general.configure(s)?;149 let manifest_format = opts.manifest.configure(s)?;150151 let input = opts.input.input.ok_or(Error::MissingInputArgument)?;152 let val = if opts.input.exec {153 s.evaluate_snippet("<cmdline>".to_owned(), &input as &str)?154 } else if input == "-" {155 let mut input = Vec::new();156 std::io::stdin().read_to_end(&mut input)?;157 let input_str = std::str::from_utf8(&input)?;158 s.evaluate_snippet("<stdin>".to_owned(), input_str)?159 } else {160 s.import(&input)?161 };162163 let val = apply_tla(s.clone(), &tla, val)?;164165 if let Some(multi) = opts.output.multi {166 if opts.output.create_output_dirs {167 let mut dir = multi.clone();168 dir.pop();169 create_dir_all(dir)?;170 }171 let Val::Obj(obj) = val else {172 throw!("value should be object for --multi manifest, got {}", val.value_type())173 };174 for (field, data) in obj.iter(175 #[cfg(feature = "exp-preserve-order")]176 opts.manifest.preserve_order,177 ) {178 let data = data.with_description(|| format!("getting field {field} for manifest"))?;179180 let mut path = multi.clone();181 path.push(&field as &str);182 if opts.output.create_output_dirs {183 let mut dir = path.clone();184 dir.pop();185 create_dir_all(dir)?;186 }187 println!("{}", path.to_str().expect("path"));188 let mut file = File::create(path)?;189 writeln!(190 file,191 "{}",192 data.manifest(&manifest_format)193 .with_description(|| format!("manifesting {field}"))?194 )?;195 }196 } else if let Some(path) = opts.output.output_file {197 if opts.output.create_output_dirs {198 let mut dir = path.clone();199 dir.pop();200 create_dir_all(dir)?;201 }202 let mut file = File::create(path)?;203 writeln!(file, "{}", val.manifest(manifest_format)?)?;204 } else {205 let output = val.manifest(manifest_format)?;206 if !output.is_empty() {207 println!("{}", output);208 }209 }210211 Ok(())212}crates/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))
}
}
crates/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
- })
+ }
}
}
crates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth--- 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<ExtFile>,
}
-impl ConfigureState for StdOpts {
- type Guards = ();
- fn configure(&self, s: &State) -> Result<()> {
+impl StdOpts {
+ pub fn context_initializer(&self, s: &State) -> Result<Option<ContextInitializer>> {
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))
}
}
crates/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
crates/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
}
}