diff --git a/.changes/command-status-and-output.md b/.changes/command-status-and-output.md new file mode 100644 index 000000000..004de5559 --- /dev/null +++ b/.changes/command-status-and-output.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +Adds `status` and `output` APIs to the `tauri::api::process::Command` struct. diff --git a/core/tauri/src/api/process.rs b/core/tauri/src/api/process.rs index a9db607e8..a7b866a8d 100644 --- a/core/tauri/src/api/process.rs +++ b/core/tauri/src/api/process.rs @@ -134,6 +134,33 @@ impl CommandChild { } } +/// Describes the result of a process after it has terminated. +pub struct ExitStatus { + code: Option, +} + +impl ExitStatus { + /// Returns the exit code of the process, if any. + pub fn code(&self) -> Option { + self.code + } + + /// Was termination successful? Signal termination is not considered a success, and success is defined as a zero exit status. + pub fn success(&self) -> bool { + self.code == Some(0) + } +} + +/// The output of a finished process. +pub struct Output { + /// The status (exit code) of the process. + pub status: ExitStatus, + /// The data that the process wrote to stdout. + pub stdout: String, + /// The data that the process wrote to stderr. + pub stderr: String, +} + #[cfg(not(windows))] fn relative_command_path(command: String) -> crate::Result { match std::env::current_exe()?.parent() { @@ -281,6 +308,57 @@ impl Command { }, )) } + + /// Executes a command as a child process, waiting for it to finish and collecting its exit status. + /// Stdin, stdout and stderr are ignored. + pub fn status(self) -> crate::api::Result { + let (mut rx, _child) = self.spawn()?; + let code = crate::async_runtime::block_on(async move { + let mut code = None; + while let Some(event) = rx.recv().await { + if let CommandEvent::Terminated(payload) = event { + code = payload.code; + } + } + code + }); + Ok(ExitStatus { code }) + } + + /// Executes the command as a child process, waiting for it to finish and collecting all of its output. + /// Stdin is ignored. + pub fn output(self) -> crate::api::Result { + let (mut rx, _child) = self.spawn()?; + + let output = crate::async_runtime::block_on(async move { + let mut code = None; + let mut stdout = String::new(); + let mut stderr = String::new(); + while let Some(event) = rx.recv().await { + match event { + CommandEvent::Terminated(payload) => { + code = payload.code; + } + CommandEvent::Stdout(line) => { + stdout.push_str(line.as_str()); + stdout.push('\n'); + } + CommandEvent::Stderr(line) => { + stderr.push_str(line.as_str()); + stderr.push('\n'); + } + CommandEvent::Error(_) => {} + } + } + Output { + status: ExitStatus { code }, + stdout, + stderr, + } + }); + + Ok(output) + } } // tests for the commands functions.