diff --git a/crates/nu-cli/src/cli.rs b/crates/nu-cli/src/cli.rs index e51709158d..1e49e8c551 100644 --- a/crates/nu-cli/src/cli.rs +++ b/crates/nu-cli/src/cli.rs @@ -79,6 +79,7 @@ pub fn create_default_context( context.add_commands(vec![ // System/file operations + whole_stream_command(Exec), whole_stream_command(Pwd), whole_stream_command(Ls), whole_stream_command(Du), diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index f0e61e78cd..f5398683ca 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -36,6 +36,7 @@ pub(crate) mod each; pub(crate) mod echo; pub(crate) mod enter; pub(crate) mod every; +pub(crate) mod exec; pub(crate) mod exit; pub(crate) mod first; pub(crate) mod format; @@ -165,6 +166,7 @@ pub(crate) use clear::Clear; pub(crate) mod touch; pub(crate) use enter::Enter; pub(crate) use every::Every; +pub(crate) use exec::Exec; pub(crate) use exit::Exit; pub(crate) use first::First; pub(crate) use format::Format; diff --git a/crates/nu-cli/src/commands/exec.rs b/crates/nu-cli/src/commands/exec.rs new file mode 100644 index 0000000000..e3e24b8b4c --- /dev/null +++ b/crates/nu-cli/src/commands/exec.rs @@ -0,0 +1,87 @@ +use crate::commands::WholeStreamCommand; +use crate::context::CommandRegistry; +use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{Signature, SyntaxShape}; +use nu_source::Tagged; +use std::path::PathBuf; + +pub struct Exec; + +#[derive(Deserialize)] +pub struct ExecArgs { + pub command: Tagged, + pub rest: Vec>, +} + +#[async_trait] +impl WholeStreamCommand for Exec { + fn name(&self) -> &str { + "exec" + } + + fn signature(&self) -> Signature { + Signature::build("exec") + .required("command", SyntaxShape::Path, "the command to execute") + .rest(SyntaxShape::Pattern, "any additional arguments for command") + } + + fn usage(&self) -> &str { + "Execute command" + } + + async fn run( + &self, + args: CommandArgs, + registry: &CommandRegistry, + ) -> Result { + exec(args, registry).await + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Execute 'ps aux'", + example: "exec ps aux", + result: None, + }, + Example { + description: "Execute 'nautilus'", + example: "exec nautilus", + result: None, + }, + ] + } +} + +#[cfg(unix)] +async fn exec(args: CommandArgs, registry: &CommandRegistry) -> Result { + use std::os::unix::process::CommandExt; + use std::process::Command; + + let registry = registry.clone(); + let name = args.call_info.name_tag.clone(); + let (args, _): (ExecArgs, _) = args.process(®istry).await?; + + let mut command = Command::new(args.command.item); + for tagged_arg in args.rest { + command.arg(tagged_arg.item); + } + + let err = command.exec(); // this replaces our process, should not return + + Err(ShellError::labeled_error( + "Error on exec", + format!("{}", err), + &name, + )) +} + +#[cfg(not(unix))] +async fn exec(args: CommandArgs, _registry: &CommandRegistry) -> Result { + Err(ShellError::labeled_error( + "Error on exec", + "exec is not supported on your platform", + &args.call_info.name_tag, + )) +}