hermes_tokio_runtime_components/impls/os/
exec_command.rs1use core::str;
2use core::str::Utf8Error;
3use std::ffi::OsStr;
4use std::io::Error as IoError;
5
6use cgp::prelude::*;
7use hermes_runtime_components::traits::fs::file_path::HasFilePathType;
8use hermes_runtime_components::traits::os::exec_command::{CommandWithEnvsExecutor, ExecOutput};
9use tokio::process::Command;
10
11pub struct TokioExecCommand;
12
13pub struct ExecCommandFailure {
14 pub command: String,
15 pub exit_code: Option<i32>,
16 pub stdout: String,
17 pub stderr: String,
18}
19
20impl<Runtime> CommandWithEnvsExecutor<Runtime> for TokioExecCommand
21where
22 Runtime: HasFilePathType
23 + CanRaiseError<IoError>
24 + CanRaiseError<Utf8Error>
25 + CanRaiseError<ExecCommandFailure>,
26 Runtime::FilePath: AsRef<OsStr>,
27{
28 async fn exec_command_with_envs(
29 _runtime: &Runtime,
30 command_path: &Runtime::FilePath,
31 args: &[&str],
32 envs: &[(&str, &str)],
33 ) -> Result<ExecOutput, Runtime::Error> {
34 let output = Command::new(command_path)
35 .args(args)
36 .envs(Vec::from(envs))
37 .kill_on_drop(true)
38 .output()
39 .await
40 .map_err(Runtime::raise_error)?;
41
42 let stdout = str::from_utf8(&output.stdout).map_err(Runtime::raise_error)?;
43
44 let stderr = str::from_utf8(&output.stderr).map_err(Runtime::raise_error)?;
45
46 if output.status.success() {
47 Ok(ExecOutput {
48 stdout: stdout.to_owned(),
49 stderr: stderr.to_owned(),
50 })
51 } else {
52 Err(Runtime::raise_error(ExecCommandFailure {
53 command: Runtime::file_path_to_string(command_path),
54 exit_code: output.status.code(),
55 stdout: stdout.to_owned(),
56 stderr: stderr.to_owned(),
57 }))
58 }
59 }
60}