Skip to content

Commit fdabf85

Browse files
committed
fix: resolved conflicts from main
2 parents 20e07cd + 235b1c9 commit fdabf85

File tree

1 file changed

+148
-23
lines changed

1 file changed

+148
-23
lines changed

src/runtime/cmd.rs

Lines changed: 148 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ pub struct CommandLine {
1616

1717
impl CommandLine {
1818
pub fn from_vec(vec: &Vec<String>) -> anyhow::Result<Self> {
19+
log::debug!("Creating CommandLine from vector: {:?}", vec);
20+
1921
if vec.is_empty() {
22+
log::error!("Empty command line vector provided");
2023
return Err(anyhow::anyhow!("empty command line"));
2124
}
2225

@@ -25,29 +28,44 @@ impl CommandLine {
2528
let mut args = Vec::new();
2629

2730
for arg in vec {
31+
log::trace!("Processing argument: {}", arg);
2832
if arg == "sudo" {
33+
log::debug!("Sudo flag detected");
2934
sudo = true;
3035
} else if app.is_empty() {
36+
log::debug!("Setting application name: {}", arg);
3137
app = arg.to_string();
3238
} else {
39+
log::trace!("Adding argument: {}", arg);
3340
args.push(arg.to_string());
3441
}
3542
}
3643

3744
if app.is_empty() {
45+
log::error!("Could not determine application name from: {:?}", vec);
3846
return Err(anyhow::anyhow!(
3947
"could not determine application name from command line: {:?}",
4048
vec
4149
));
4250
}
4351

4452
let app_in_path = if let Ok(path) = which::which(&app) {
53+
log::debug!("Found application in path: {}", path.display());
4554
app = path.to_string_lossy().to_string();
4655
true
4756
} else {
57+
log::debug!("Application '{}' not found in PATH", app);
4858
false
4959
};
5060

61+
log::debug!(
62+
"Created CommandLine: sudo={}, app={}, app_in_path={}, args={:?}",
63+
sudo,
64+
app,
65+
app_in_path,
66+
args
67+
);
68+
5169
Ok(Self {
5270
sudo,
5371
app,
@@ -62,43 +80,93 @@ impl CommandLine {
6280
vec: &Vec<String>,
6381
env: BTreeMap<String, String>,
6482
) -> anyhow::Result<Self> {
83+
log::debug!("creating CommandLine with environment variables");
84+
log::trace!("environment variables: {:?}", env);
6585
let mut cmd = Self::from_vec(vec)?;
6686
cmd.env = env;
6787
Ok(cmd)
6888
}
6989

90+
fn get_env_interpolated_args(&self) -> Vec<String> {
91+
log::debug!("interpolating variables from environment: {:?}", self.env);
92+
93+
let args = self
94+
.args
95+
.iter()
96+
.map(|arg| {
97+
let mut result = arg.clone();
98+
for (key, value) in &self.env {
99+
let pattern = format!("${{{}}}", key);
100+
if result.contains(&pattern) {
101+
log::debug!("replacing {} with {}", pattern, value);
102+
result = result.replace(&pattern, value);
103+
}
104+
}
105+
result
106+
})
107+
.collect();
108+
109+
log::debug!("after interpolation: {:?}", &args);
110+
111+
args
112+
}
113+
70114
pub async fn execute(&self, ssh: Option<SSHConnection>) -> anyhow::Result<String> {
115+
// execyte via ssh
71116
if let Some(ssh) = ssh {
72-
ssh.execute(self.sudo, &self.app, &self.args).await
73-
} else {
74-
let output = tokio::process::Command::new(&self.app)
75-
.args(&self.args)
76-
.output()
77-
.await?;
117+
return ssh.execute(self.sudo, &self.app, &self.args).await;
118+
}
78119

79-
let mut parts = vec![];
120+
log::debug!("executing command: {}", self);
121+
log::debug!("full command details: {:?}", self);
80122

81-
let stdout = String::from_utf8_lossy(&output.stdout);
82-
let stderr = String::from_utf8_lossy(&output.stderr);
123+
let args = self.get_env_interpolated_args();
83124

84-
if !output.status.success() {
85-
parts.push(format!("EXIT CODE: {}", &output.status));
86-
}
125+
let mut command = tokio::process::Command::new(&self.app);
126+
command.args(&args);
87127

88-
if !stdout.is_empty() {
89-
parts.push(stdout.to_string());
90-
}
128+
// log environment variables if present
129+
if !self.env.is_empty() {
130+
log::debug!("setting environment variables: {:?}", self.env);
131+
command.envs(&self.env);
132+
}
91133

92-
if !stderr.is_empty() {
93-
if output.status.success() {
94-
parts.push(stderr.to_string());
95-
} else {
96-
parts.push(format!("ERROR: {}", stderr));
97-
}
98-
}
134+
let output = command.output().await?;
135+
log::debug!("command completed with status: {:?}", output.status);
136+
137+
let mut parts = vec![];
138+
139+
let stdout = String::from_utf8_lossy(&output.stdout);
140+
let stderr = String::from_utf8_lossy(&output.stderr);
99141

100-
Ok(parts.join("\n"))
142+
if !output.status.success() {
143+
log::warn!("command failed with exit code: {}", output.status);
144+
parts.push(format!("EXIT CODE: {}", &output.status));
101145
}
146+
147+
if !stdout.is_empty() {
148+
log::trace!("command stdout: {}", stdout);
149+
parts.push(stdout.to_string());
150+
}
151+
152+
if !stderr.is_empty() {
153+
if output.status.success() {
154+
log::debug!("command stderr (success): {}", stderr);
155+
parts.push(stderr.to_string());
156+
} else {
157+
log::error!("command stderr (failure): {}", stderr);
158+
parts.push(format!("ERROR: {}", stderr));
159+
}
160+
}
161+
162+
let result = parts.join("\n");
163+
log::debug!(
164+
"command execution completed, output length: {}",
165+
result.len()
166+
);
167+
log::trace!("command output: {}", result);
168+
169+
Ok(result)
102170
}
103171
}
104172

@@ -208,4 +276,61 @@ mod tests {
208276
let result = cmd.execute(None).await;
209277
assert!(result.is_err());
210278
}
279+
280+
#[test]
281+
fn test_get_env_interpolated_args_with_env_vars() {
282+
let mut env = BTreeMap::new();
283+
env.insert("TEST_VAR".to_string(), "test_value".to_string());
284+
env.insert("OTHER_VAR".to_string(), "other_value".to_string());
285+
286+
let cmd = CommandLine {
287+
sudo: false,
288+
app: "echo".to_string(),
289+
args: vec!["${TEST_VAR}".to_string(), "${OTHER_VAR}".to_string()],
290+
app_in_path: true,
291+
env,
292+
temp_env_file: None,
293+
};
294+
295+
let result = cmd.get_env_interpolated_args();
296+
assert_eq!(result, vec!["test_value", "other_value"]);
297+
}
298+
299+
#[test]
300+
fn test_get_env_interpolated_args_with_missing_vars() {
301+
let env = BTreeMap::new();
302+
let cmd = CommandLine {
303+
sudo: false,
304+
app: "echo".to_string(),
305+
args: vec!["${MISSING_VAR}".to_string()],
306+
app_in_path: true,
307+
env,
308+
temp_env_file: None,
309+
};
310+
311+
let result = cmd.get_env_interpolated_args();
312+
assert_eq!(result, vec!["${MISSING_VAR}"]);
313+
}
314+
315+
#[test]
316+
fn test_get_env_interpolated_args_with_mixed_content() {
317+
let mut env = BTreeMap::new();
318+
env.insert("VAR".to_string(), "value".to_string());
319+
320+
let cmd = CommandLine {
321+
sudo: false,
322+
app: "echo".to_string(),
323+
args: vec![
324+
"prefix_${VAR}".to_string(),
325+
"normal_arg".to_string(),
326+
"${VAR}_suffix".to_string(),
327+
],
328+
app_in_path: true,
329+
env,
330+
temp_env_file: None,
331+
};
332+
333+
let result = cmd.get_env_interpolated_args();
334+
assert_eq!(result, vec!["prefix_value", "normal_arg", "value_suffix"]);
335+
}
211336
}

0 commit comments

Comments
 (0)