2023-01-20 21:20:38 +00:00
|
|
|
mod command;
|
2022-01-18 08:48:28 +00:00
|
|
|
mod config_files;
|
|
|
|
mod logger;
|
2023-01-20 18:44:49 +00:00
|
|
|
mod signals;
|
2023-01-20 21:20:38 +00:00
|
|
|
mod terminal;
|
2022-02-09 22:08:16 +00:00
|
|
|
mod test_bins;
|
2021-08-10 18:57:08 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2022-03-16 18:17:06 +00:00
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
use crate::config_files::NUSHELL_FOLDER;
|
2023-01-20 21:20:38 +00:00
|
|
|
use crate::{
|
|
|
|
command::parse_commandline_args,
|
|
|
|
config_files::{set_config_path, setup_config},
|
|
|
|
logger::{configure, logger},
|
|
|
|
terminal::acquire_terminal,
|
|
|
|
};
|
2022-10-21 15:20:21 +00:00
|
|
|
use log::{info, Level};
|
2022-01-18 08:48:28 +00:00
|
|
|
use miette::Result;
|
2022-03-16 18:17:06 +00:00
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
use nu_cli::read_plugin_file;
|
|
|
|
use nu_cli::{
|
|
|
|
evaluate_commands, evaluate_file, evaluate_repl, gather_parent_env_vars, get_init_cwd,
|
2023-01-20 21:20:38 +00:00
|
|
|
report_error_new,
|
2022-03-16 18:17:06 +00:00
|
|
|
};
|
2023-01-06 23:22:17 +00:00
|
|
|
use nu_command::create_default_context;
|
2023-01-20 21:20:38 +00:00
|
|
|
use nu_parser::{escape_for_script_arg, escape_quote_string};
|
|
|
|
use nu_protocol::{util::BufferedReader, PipelineData, RawStream};
|
2023-01-20 18:44:49 +00:00
|
|
|
use signals::{ctrlc_protection, sigquit_protection};
|
2022-01-26 14:42:39 +00:00
|
|
|
use std::{
|
2022-05-17 18:28:18 +00:00
|
|
|
io::BufReader,
|
2023-01-23 18:57:40 +00:00
|
|
|
str::FromStr,
|
2023-01-20 18:44:49 +00:00
|
|
|
sync::{atomic::AtomicBool, Arc},
|
2023-01-23 18:57:40 +00:00
|
|
|
time::Instant,
|
2022-01-26 14:42:39 +00:00
|
|
|
};
|
2022-09-29 18:37:48 +00:00
|
|
|
|
2021-09-20 21:37:26 +00:00
|
|
|
fn main() -> Result<()> {
|
2023-01-23 18:57:40 +00:00
|
|
|
let start_time = Instant::now();
|
2021-10-01 16:39:50 +00:00
|
|
|
let miette_hook = std::panic::take_hook();
|
|
|
|
std::panic::set_hook(Box::new(move |x| {
|
2021-12-04 12:38:21 +00:00
|
|
|
crossterm::terminal::disable_raw_mode().expect("unable to disable raw mode");
|
2021-10-01 16:39:50 +00:00
|
|
|
miette_hook(x);
|
|
|
|
}));
|
2021-09-21 19:37:16 +00:00
|
|
|
|
2022-01-04 22:30:34 +00:00
|
|
|
// Get initial current working directory.
|
2022-03-16 18:17:06 +00:00
|
|
|
let init_cwd = get_init_cwd();
|
2022-07-14 14:09:27 +00:00
|
|
|
let mut engine_state = create_default_context();
|
2021-07-17 06:31:34 +00:00
|
|
|
|
2022-01-24 15:05:19 +00:00
|
|
|
// Custom additions
|
|
|
|
let delta = {
|
|
|
|
let mut working_set = nu_protocol::engine::StateWorkingSet::new(&engine_state);
|
|
|
|
working_set.add_decl(Box::new(nu_cli::NuHighlight));
|
2022-02-18 18:43:34 +00:00
|
|
|
working_set.add_decl(Box::new(nu_cli::Print));
|
2022-01-24 15:05:19 +00:00
|
|
|
working_set.render()
|
|
|
|
};
|
2022-07-14 14:09:27 +00:00
|
|
|
|
|
|
|
if let Err(err) = engine_state.merge_delta(delta) {
|
|
|
|
report_error_new(&engine_state, &err);
|
|
|
|
}
|
2022-01-24 15:05:19 +00:00
|
|
|
|
2021-10-28 04:13:10 +00:00
|
|
|
let ctrlc = Arc::new(AtomicBool::new(false));
|
2023-01-20 18:44:49 +00:00
|
|
|
// TODO: make this conditional in the future
|
|
|
|
ctrlc_protection(&mut engine_state, &ctrlc);
|
|
|
|
sigquit_protection(&mut engine_state);
|
2022-06-09 12:08:15 +00:00
|
|
|
|
2022-01-26 14:42:39 +00:00
|
|
|
let mut args_to_nushell = vec![];
|
|
|
|
let mut script_name = String::new();
|
|
|
|
let mut args_to_script = vec![];
|
|
|
|
|
|
|
|
// Would be nice if we had a way to parse this. The first flags we see will be going to nushell
|
|
|
|
// then it'll be the script name
|
|
|
|
// then the args to the script
|
2022-07-26 14:41:05 +00:00
|
|
|
let mut args = std::env::args();
|
|
|
|
let argv0 = args.next();
|
|
|
|
|
2022-04-30 18:23:05 +00:00
|
|
|
while let Some(arg) = args.next() {
|
2022-01-26 14:42:39 +00:00
|
|
|
if !script_name.is_empty() {
|
2022-06-11 08:52:31 +00:00
|
|
|
args_to_script.push(escape_for_script_arg(&arg));
|
2022-01-26 14:42:39 +00:00
|
|
|
} else if arg.starts_with('-') {
|
|
|
|
// Cool, it's a flag
|
2022-04-30 18:23:05 +00:00
|
|
|
let flag_value = match arg.as_ref() {
|
2022-08-18 09:25:52 +00:00
|
|
|
"--commands" | "-c" | "--table-mode" | "-m" | "-e" | "--execute" => {
|
2022-05-11 21:15:31 +00:00
|
|
|
args.next().map(|a| escape_quote_string(&a))
|
|
|
|
}
|
2022-04-30 18:23:05 +00:00
|
|
|
"--config" | "--env-config" => args.next().map(|a| escape_quote_string(&a)),
|
2022-07-17 18:29:19 +00:00
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
"--plugin-config" => args.next().map(|a| escape_quote_string(&a)),
|
2022-08-09 16:44:37 +00:00
|
|
|
"--log-level" | "--log-target" | "--testbin" | "--threads" | "-t" => args.next(),
|
2022-04-30 18:23:05 +00:00
|
|
|
_ => None,
|
|
|
|
};
|
2022-02-19 20:54:43 +00:00
|
|
|
|
2022-01-26 14:42:39 +00:00
|
|
|
args_to_nushell.push(arg);
|
2022-04-30 18:23:05 +00:00
|
|
|
|
|
|
|
if let Some(flag_value) = flag_value {
|
|
|
|
args_to_nushell.push(flag_value);
|
|
|
|
}
|
2022-01-26 14:42:39 +00:00
|
|
|
} else {
|
|
|
|
// Our script file
|
|
|
|
script_name = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
args_to_nushell.insert(0, "nu".into());
|
|
|
|
|
2022-07-26 14:41:05 +00:00
|
|
|
if let Some(argv0) = argv0 {
|
|
|
|
if argv0.starts_with('-') {
|
|
|
|
args_to_nushell.push("--login".into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-26 14:42:39 +00:00
|
|
|
let nushell_commandline_args = args_to_nushell.join(" ");
|
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
let parsed_nu_cli_args = parse_commandline_args(&nushell_commandline_args, &mut engine_state)
|
|
|
|
.unwrap_or_else(|_| std::process::exit(1));
|
|
|
|
|
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
|
|
|
&init_cwd,
|
|
|
|
"config.nu",
|
|
|
|
"config-path",
|
|
|
|
&parsed_nu_cli_args.config_file,
|
|
|
|
);
|
|
|
|
|
|
|
|
set_config_path(
|
|
|
|
&mut engine_state,
|
|
|
|
&init_cwd,
|
|
|
|
"env.nu",
|
|
|
|
"env-path",
|
|
|
|
&parsed_nu_cli_args.env_file,
|
|
|
|
);
|
|
|
|
|
|
|
|
// keep this condition in sync with the branches below
|
|
|
|
acquire_terminal(
|
|
|
|
parsed_nu_cli_args.commands.is_none()
|
|
|
|
&& (script_name.is_empty() || parsed_nu_cli_args.interactive_shell.is_some()),
|
|
|
|
);
|
|
|
|
|
|
|
|
if let Some(t) = parsed_nu_cli_args.threads {
|
|
|
|
// 0 means to let rayon decide how many threads to use
|
|
|
|
let threads = t.as_i64().unwrap_or(0);
|
|
|
|
rayon::ThreadPoolBuilder::new()
|
|
|
|
.num_threads(threads as usize)
|
|
|
|
.build_global()
|
|
|
|
.expect("error setting number of threads");
|
2022-08-22 16:30:09 +00:00
|
|
|
}
|
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
if let Some(level) = parsed_nu_cli_args.log_level.map(|level| level.item) {
|
|
|
|
let level = if Level::from_str(&level).is_ok() {
|
|
|
|
level
|
|
|
|
} else {
|
|
|
|
eprintln!(
|
|
|
|
"ERROR: log library did not recognize log level '{level}', using default 'info'"
|
2022-09-29 18:37:48 +00:00
|
|
|
);
|
2023-01-20 18:44:49 +00:00
|
|
|
"info".to_string()
|
|
|
|
};
|
|
|
|
let target = parsed_nu_cli_args
|
|
|
|
.log_target
|
|
|
|
.map(|target| target.item)
|
|
|
|
.unwrap_or_else(|| "stderr".to_string());
|
|
|
|
|
|
|
|
logger(|builder| configure(&level, &target, builder))?;
|
|
|
|
info!("start logging {}:{}:{}", file!(), line!(), column!());
|
|
|
|
}
|
2022-09-29 18:37:48 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
if let Some(testbin) = &parsed_nu_cli_args.testbin {
|
|
|
|
// Call out to the correct testbin
|
|
|
|
match testbin.item.as_str() {
|
|
|
|
"echo_env" => test_bins::echo_env(true),
|
|
|
|
"echo_env_stderr" => test_bins::echo_env(false),
|
|
|
|
"cococo" => test_bins::cococo(),
|
|
|
|
"meow" => test_bins::meow(),
|
|
|
|
"meowb" => test_bins::meowb(),
|
|
|
|
"relay" => test_bins::relay(),
|
|
|
|
"iecho" => test_bins::iecho(),
|
|
|
|
"fail" => test_bins::fail(),
|
|
|
|
"nonu" => test_bins::nonu(),
|
|
|
|
"chop" => test_bins::chop(),
|
|
|
|
"repeater" => test_bins::repeater(),
|
|
|
|
"nu_repl" => test_bins::nu_repl(),
|
|
|
|
_ => std::process::exit(1),
|
|
|
|
}
|
|
|
|
std::process::exit(0)
|
|
|
|
}
|
|
|
|
let input = if let Some(redirect_stdin) = &parsed_nu_cli_args.redirect_stdin {
|
|
|
|
let stdin = std::io::stdin();
|
|
|
|
let buf_reader = BufReader::new(stdin);
|
|
|
|
|
|
|
|
PipelineData::ExternalStream {
|
|
|
|
stdout: Some(RawStream::new(
|
|
|
|
Box::new(BufferedReader::new(buf_reader)),
|
|
|
|
Some(ctrlc),
|
|
|
|
redirect_stdin.span,
|
|
|
|
None,
|
|
|
|
)),
|
|
|
|
stderr: None,
|
|
|
|
exit_code: None,
|
|
|
|
span: redirect_stdin.span,
|
|
|
|
metadata: None,
|
|
|
|
trim_end_newline: false,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
PipelineData::empty()
|
|
|
|
};
|
2022-10-21 15:20:21 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
info!("redirect_stdin {}:{}:{}", file!(), line!(), column!());
|
2022-08-09 16:44:37 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
// First, set up env vars as strings only
|
|
|
|
gather_parent_env_vars(&mut engine_state, &init_cwd);
|
2022-02-09 22:08:16 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
let mut stack = nu_protocol::engine::Stack::new();
|
2022-01-26 14:42:39 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
if let Some(commands) = &parsed_nu_cli_args.commands {
|
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
read_plugin_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.plugin_file,
|
|
|
|
NUSHELL_FOLDER,
|
|
|
|
);
|
2022-02-09 22:08:16 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
// only want to load config and env if relative argument is provided.
|
|
|
|
if parsed_nu_cli_args.env_file.is_some() {
|
|
|
|
config_files::read_config_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.env_file,
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
config_files::read_default_env_file(&mut engine_state, &mut stack)
|
|
|
|
}
|
2022-07-14 14:09:27 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
if parsed_nu_cli_args.config_file.is_some() {
|
|
|
|
config_files::read_config_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.config_file,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
2022-03-16 18:17:06 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
let ret_val = evaluate_commands(
|
|
|
|
commands,
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
input,
|
|
|
|
parsed_nu_cli_args.table_mode,
|
|
|
|
);
|
|
|
|
info!("-c command execution {}:{}:{}", file!(), line!(), column!());
|
|
|
|
match ret_val {
|
|
|
|
Ok(Some(exit_code)) => std::process::exit(exit_code as i32),
|
|
|
|
Ok(None) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
|
|
|
} else if !script_name.is_empty() && parsed_nu_cli_args.interactive_shell.is_none() {
|
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
read_plugin_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.plugin_file,
|
|
|
|
NUSHELL_FOLDER,
|
|
|
|
);
|
2022-07-10 15:12:24 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
// only want to load config and env if relative argument is provided.
|
|
|
|
if parsed_nu_cli_args.env_file.is_some() {
|
|
|
|
config_files::read_config_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.env_file,
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
config_files::read_default_env_file(&mut engine_state, &mut stack)
|
|
|
|
}
|
2022-02-26 08:57:51 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
if parsed_nu_cli_args.config_file.is_some() {
|
|
|
|
config_files::read_config_file(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
parsed_nu_cli_args.config_file,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
2022-07-10 15:12:24 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
let ret_val = evaluate_file(
|
|
|
|
script_name,
|
|
|
|
&args_to_script,
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
input,
|
|
|
|
);
|
2022-02-26 08:57:51 +00:00
|
|
|
|
2023-01-20 18:44:49 +00:00
|
|
|
let last_exit_code = stack.get_env_var(&engine_state, "LAST_EXIT_CODE");
|
|
|
|
if let Some(last_exit_code) = last_exit_code {
|
|
|
|
let value = last_exit_code.as_integer();
|
|
|
|
if let Ok(value) = value {
|
|
|
|
if value != 0 {
|
|
|
|
std::process::exit(value as i32);
|
2022-07-24 22:57:10 +00:00
|
|
|
}
|
2022-01-26 14:42:39 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-20 18:44:49 +00:00
|
|
|
info!("eval_file execution {}:{}:{}", file!(), line!(), column!());
|
|
|
|
|
|
|
|
ret_val
|
|
|
|
} else {
|
|
|
|
setup_config(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
#[cfg(feature = "plugin")]
|
|
|
|
parsed_nu_cli_args.plugin_file,
|
|
|
|
parsed_nu_cli_args.config_file,
|
|
|
|
parsed_nu_cli_args.env_file,
|
|
|
|
parsed_nu_cli_args.login_shell.is_some(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let ret_val = evaluate_repl(
|
|
|
|
&mut engine_state,
|
|
|
|
&mut stack,
|
|
|
|
config_files::NUSHELL_FOLDER,
|
|
|
|
parsed_nu_cli_args.execute,
|
2023-01-23 18:57:40 +00:00
|
|
|
start_time,
|
2023-01-20 18:44:49 +00:00
|
|
|
);
|
|
|
|
info!("repl eval {}:{}:{}", file!(), line!(), column!());
|
|
|
|
|
|
|
|
ret_val
|
2022-01-26 14:42:39 +00:00
|
|
|
}
|
|
|
|
}
|