forked from extern/nushell
Add exec
command for Windows (#11001)
# Description Based of the work and discussion in #10844, this PR adds the `exec` command for Windows. This is done by simply spawning a `std::process::Command` and then immediately exiting via `std::process::exit` once the child process is finished. The child process's exit code is passed to `exit`. # User-Facing Changes The `exec` command is now available on Windows, and there should be no change in behaviour for Unix systems.
This commit is contained in:
parent
59ea28cf06
commit
1fd3bc1ba6
@ -115,6 +115,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
bind_command! {
|
||||
Complete,
|
||||
External,
|
||||
Exec,
|
||||
NuCheck,
|
||||
Sys,
|
||||
};
|
||||
@ -145,9 +146,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
ViewSpan,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
bind_command! { Exec }
|
||||
|
||||
#[cfg(windows)]
|
||||
bind_command! { RegistryQuery }
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
use super::run_external::create_external_command;
|
||||
use nu_engine::{current_dir, CallExt};
|
||||
use nu_engine::current_dir;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type,
|
||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Type,
|
||||
};
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Exec;
|
||||
@ -24,11 +23,12 @@ impl Command for Exec {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Execute a command, replacing the current process."
|
||||
"Execute a command, replacing or exiting the current process, depending on platform."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"Currently supported only on Unix-based systems."
|
||||
r#"On Unix-based systems, the current process is replaced with the command.
|
||||
On Windows based systems, Nushell will wait for the command to finish and then exit with the command's exit code."#
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -62,36 +62,49 @@ fn exec(
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let name_span = name.span;
|
||||
|
||||
let redirect_stdout = call.has_flag("redirect-stdout");
|
||||
let redirect_stderr = call.has_flag("redirect-stderr");
|
||||
let redirect_combine = call.has_flag("redirect-combine");
|
||||
let trim_end_newline = call.has_flag("trim-end-newline");
|
||||
|
||||
let external_command = create_external_command(
|
||||
engine_state,
|
||||
stack,
|
||||
call,
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
redirect_combine,
|
||||
trim_end_newline,
|
||||
)?;
|
||||
let external_command =
|
||||
create_external_command(engine_state, stack, call, false, false, false, false)?;
|
||||
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
let mut command = external_command.spawn_simple_command(&cwd.to_string_lossy())?;
|
||||
command.current_dir(cwd);
|
||||
command.envs(&external_command.env_vars);
|
||||
command.envs(external_command.env_vars);
|
||||
|
||||
let err = command.exec(); // this replaces our process, should not return
|
||||
// this either replaces our process and should not return,
|
||||
// or the exec fails and we get an error back
|
||||
exec_impl(command, call.head)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn exec_impl(mut command: std::process::Command, span: Span) -> Result<PipelineData, ShellError> {
|
||||
use std::os::unix::process::CommandExt;
|
||||
|
||||
let error = command.exec();
|
||||
|
||||
Err(ShellError::GenericError(
|
||||
"Error on exec".to_string(),
|
||||
err.to_string(),
|
||||
Some(name_span),
|
||||
"Error on exec".into(),
|
||||
error.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn exec_impl(mut command: std::process::Command, span: Span) -> Result<PipelineData, ShellError> {
|
||||
match command.spawn() {
|
||||
Ok(mut child) => match child.wait() {
|
||||
Ok(status) => std::process::exit(status.code().unwrap_or(0)),
|
||||
Err(e) => Err(ShellError::ExternalCommand {
|
||||
label: "Error in external command".into(),
|
||||
help: e.to_string(),
|
||||
span,
|
||||
}),
|
||||
},
|
||||
Err(e) => Err(ShellError::ExternalCommand {
|
||||
label: "Error spawning external command".into(),
|
||||
help: e.to_string(),
|
||||
span,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
mod complete;
|
||||
#[cfg(unix)]
|
||||
mod exec;
|
||||
mod nu_check;
|
||||
#[cfg(any(
|
||||
@ -16,7 +15,6 @@ mod sys;
|
||||
mod which_;
|
||||
|
||||
pub use complete::Complete;
|
||||
#[cfg(unix)]
|
||||
pub use exec::Exec;
|
||||
pub use nu_check::NuCheck;
|
||||
#[cfg(any(
|
||||
|
@ -24,7 +24,6 @@ mod echo;
|
||||
mod empty;
|
||||
mod error_make;
|
||||
mod every;
|
||||
#[cfg(not(windows))]
|
||||
mod exec;
|
||||
mod export_def;
|
||||
mod fill;
|
||||
|
Loading…
Reference in New Issue
Block a user