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

difftreelog

fix cli description

Yaroslav Bolyukin2022-11-20parent: #64f3674.patch.diff
in: master

1 file changed

modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
after · cmds/jrsonnet/src/main.rs
1use 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}