git.delta.rocks / jrsonnet / refs/commits / 7b01ecbd8fbc

difftreelog

source

cmds/jrsonnet/src/main.rs4.1 KiBsourcehistory
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};9use jrsonnet_evaluator::{error::LocError, State};1011#[cfg(feature = "mimalloc")]12#[global_allocator]13static GLOBAL: mimallocator::Mimalloc = mimallocator::Mimalloc;1415#[derive(Parser)]16enum SubOpts {17	/// Generate completions for specified shell18	Generate {19		/// Target shell name20		shell: Shell,21	},22}2324#[derive(Parser)]25#[clap(next_help_heading = "DEBUG")]26struct DebugOpts {27	/// Required OS stack size.28	/// This shouldn't be changed unless jrsonnet is failing with stack overflow error.29	#[clap(long, name = "size")]30	pub os_stack: Option<usize>,31}3233#[derive(Parser)]34#[clap(next_help_heading = "INPUT")]35struct InputOpts {36	/// Treat input as code, evaluate them instead of reading file37	#[clap(long, short = 'e')]38	pub exec: bool,3940	/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself41	pub input: Option<String>,42}4344#[derive(Parser)]45#[clap(args_conflicts_with_subcommands = true, disable_version_flag = true)]46struct Opts {47	#[clap(subcommand)]48	sub: Option<SubOpts>,4950	#[clap(flatten)]51	input: InputOpts,52	#[clap(flatten)]53	general: GeneralOpts,54	#[clap(flatten)]55	manifest: ManifestOpts,56	#[clap(flatten)]57	output: OutputOpts,58	#[clap(flatten)]59	debug: DebugOpts,60}6162fn main() {63	let opts: Opts = Opts::parse();6465	if let Some(sub) = opts.sub {66		match sub {67			SubOpts::Generate { shell } => {68				use clap_complete::generate;69				let app = &mut Opts::command();70				let buf = &mut std::io::stdout();71				generate(shell, app, "jrsonnet", buf);72				std::process::exit(0)73			}74		}75	}7677	let success = if let Some(size) = opts.debug.os_stack {78		std::thread::Builder::new()79			.stack_size(size * 1024 * 1024)80			.spawn(|| main_catch(opts))81			.expect("new thread spawned")82			.join()83			.expect("thread finished successfully")84	} else {85		main_catch(opts)86	};87	if !success {88		std::process::exit(1);89	}90}9192#[derive(thiserror::Error, Debug)]93enum Error {94	// Handled differently95	#[error("evaluation error")]96	Evaluation(jrsonnet_evaluator::error::LocError),97	#[error("io error")]98	Io(#[from] std::io::Error),99	#[error("input is not utf8 encoded")]100	Utf8(#[from] std::str::Utf8Error),101	#[error("missing input argument")]102	MissingInputArgument,103}104impl From<LocError> for Error {105	fn from(e: LocError) -> Self {106		Self::Evaluation(e)107	}108}109110fn main_catch(opts: Opts) -> bool {111	let s = State::default();112	if let Err(e) = main_real(&s, opts) {113		if let Error::Evaluation(e) = e {114			eprintln!("{}", s.stringify_err(&e));115		} else {116			eprintln!("{}", e);117		}118		return false;119	}120	true121}122123fn main_real(s: &State, opts: Opts) -> Result<(), Error> {124	let _guards = opts.general.configure(s)?;125	opts.manifest.configure(s)?;126127	let input = opts.input.input.ok_or(Error::MissingInputArgument)?;128	let val = if opts.input.exec {129		s.evaluate_snippet("<cmdline>".to_owned(), &input as &str)?130	} else if input == "-" {131		let mut input = Vec::new();132		std::io::stdin().read_to_end(&mut input)?;133		let input_str = std::str::from_utf8(&input)?;134		s.evaluate_snippet("<stdin>".to_owned(), input_str)?135	} else {136		s.import(&input)?137	};138139	let val = s.with_tla(val)?;140141	if let Some(multi) = opts.output.multi {142		if opts.output.create_output_dirs {143			let mut dir = multi.clone();144			dir.pop();145			create_dir_all(dir)?;146		}147		for (file, data) in s.manifest_multi(val)?.iter() {148			let mut path = multi.clone();149			path.push(file as &str);150			if opts.output.create_output_dirs {151				let mut dir = path.clone();152				dir.pop();153				create_dir_all(dir)?;154			}155			println!("{}", path.to_str().expect("path"));156			let mut file = File::create(path)?;157			writeln!(file, "{}", data)?;158		}159	} else if let Some(path) = opts.output.output_file {160		if opts.output.create_output_dirs {161			let mut dir = path.clone();162			dir.pop();163			create_dir_all(dir)?;164		}165		let mut file = File::create(path)?;166		writeln!(file, "{}", s.manifest(val)?)?;167	} else {168		let output = s.manifest(val)?;169		if !output.is_empty() {170			println!("{}", output);171		}172	}173174	Ok(())175}