| 892 | /// |
| 893 | #[allow(clippy::implicit_hasher)] |
| 894 | pub fn invoke_command(executable: &str, args: Option<Vec<String>>, input: Option<&str>, cwd: Option<&Path>, env: Option<HashMap<String, String>>, exit_codes: &ExitCodesMap) -> Result<(i32, String, String), DscError> { |
| 895 | let executable = canonicalize_which(executable, cwd)?; |
| 896 | |
| 897 | let run_async = async { |
| 898 | trace!("{}", t!("dscresources.commandResource.commandInvoke", executable = executable, args = args : {:?})); |
| 899 | if let Some(cwd) = cwd { |
| 900 | trace!("{}", t!("dscresources.commandResource.commandCwd", cwd = cwd.display())); |
| 901 | } |
| 902 | |
| 903 | match run_process_async(&executable, args, input, cwd, env, exit_codes).await { |
| 904 | Ok((code, stdout, stderr)) => { |
| 905 | Ok((code, stdout, stderr)) |
| 906 | }, |
| 907 | Err(err) => { |
| 908 | error!("{}", t!("dscresources.commandResource.runProcessError", executable = executable, error = err)); |
| 909 | Err(err) |
| 910 | } |
| 911 | } |
| 912 | }; |
| 913 | |
| 914 | // Try to use existing runtime first (e.g. from gRPC or MCP server) |
| 915 | match tokio::runtime::Handle::try_current() { |
| 916 | Ok(handle) => { |
| 917 | tokio::task::block_in_place(|| { |
| 918 | handle.block_on(run_async) |
| 919 | }) |
| 920 | }, |
| 921 | // Otherwise create a new runtime |
| 922 | Err(_) => { |
| 923 | tokio::runtime::Builder::new_multi_thread() |
| 924 | .enable_all() |
| 925 | .build() |
| 926 | .unwrap() |
| 927 | .block_on(run_async) |
| 928 | } |
| 929 | } |
| 930 | } |
| 931 | |
| 932 | /// Process the arguments for a command resource's get operation. |
| 933 | /// |