Rust · 2186 bytes Raw Blame History
1 use thiserror::Error;
2 use crate::Context;
3
4 #[derive(Error, Debug)]
5 pub enum CommandSubstError {
6 #[error("Failed to execute command: {0}")]
7 ExecutionFailed(String),
8
9 #[error("I/O error: {0}")]
10 IoError(#[from] std::io::Error),
11 }
12
13 /// Execute a command and capture its stdout
14 /// This implements $(command) substitution
15 pub fn execute_command_substitution(cmd: &str, context: &mut Context) -> Result<String, CommandSubstError> {
16 // Use internal command executor
17 // The executor is registered during Context creation in rush-cli
18 // Clone the Rc to avoid borrow checker issues
19 if let Some(executor) = context.command_executor.0.clone() {
20 return executor(cmd, context)
21 .map_err(|e| CommandSubstError::ExecutionFailed(e));
22 }
23
24 // No executor configured - this should not happen in normal rush usage
25 // Rush is fully bespoke and does not delegate to external shells
26 Err(CommandSubstError::ExecutionFailed(
27 "Internal command executor not configured. Command substitution requires rush's internal executor.".to_string()
28 ))
29 }
30
31 #[cfg(test)]
32 mod tests {
33 use super::*;
34
35 #[test]
36 fn test_simple_command_substitution() {
37 let mut context = Context::empty();
38 let result = execute_command_substitution("echo hello", &mut context).unwrap();
39 assert_eq!(result, "hello");
40 }
41
42 #[test]
43 fn test_command_with_trailing_newline() {
44 let mut context = Context::empty();
45 // echo adds a newline, which should be trimmed
46 let result = execute_command_substitution("printf 'hello\n'", &mut context).unwrap();
47 assert_eq!(result, "hello");
48 }
49
50 #[test]
51 fn test_multiple_trailing_newlines() {
52 let mut context = Context::empty();
53 let result = execute_command_substitution("printf 'hello\n\n\n'", &mut context).unwrap();
54 assert_eq!(result, "hello");
55 }
56
57 #[test]
58 fn test_pwd() {
59 let mut context = Context::empty();
60 // Just make sure it doesn't error
61 let result = execute_command_substitution("pwd", &mut context);
62 assert!(result.is_ok());
63 assert!(!result.unwrap().is_empty());
64 }
65 }
66