Skip to content

Commit 92a4c7e

Browse files
authored
Merge pull request #10 from dreadnode/bugfix/variable_substitutions
Fixing variable interpolation in cmd.rs
2 parents 5c72f79 + 17a235e commit 92a4c7e

File tree

2 files changed

+75
-5
lines changed

2 files changed

+75
-5
lines changed

robopages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit d24c9c9284ec38fef14d529ba5b038d9553644dd

src/runtime/cmd.rs

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,25 @@ pub struct CommandLine {
1212
pub temp_env_file: Option<tempfile::NamedTempFile>,
1313
}
1414

15+
impl Clone for CommandLine {
16+
fn clone(&self) -> Self {
17+
Self {
18+
sudo: self.sudo,
19+
app: self.app.clone(),
20+
app_in_path: self.app_in_path,
21+
args: self.args.clone(),
22+
env: self.env.clone(),
23+
temp_env_file: None, // Don't clone the temp file, create a new one if needed
24+
}
25+
}
26+
}
27+
1528
impl CommandLine {
1629
pub fn from_vec(vec: &Vec<String>) -> anyhow::Result<Self> {
30+
log::debug!("Creating CommandLine from vector: {:?}", vec);
31+
1732
if vec.is_empty() {
33+
log::error!("Empty command line vector provided");
1834
return Err(anyhow::anyhow!("empty command line"));
1935
}
2036

@@ -23,29 +39,39 @@ impl CommandLine {
2339
let mut args = Vec::new();
2440

2541
for arg in vec {
42+
log::trace!("Processing argument: {}", arg);
2643
if arg == "sudo" {
44+
log::debug!("Sudo flag detected");
2745
sudo = true;
2846
} else if app.is_empty() {
47+
log::debug!("Setting application name: {}", arg);
2948
app = arg.to_string();
3049
} else {
50+
log::trace!("Adding argument: {}", arg);
3151
args.push(arg.to_string());
3252
}
3353
}
3454

3555
if app.is_empty() {
56+
log::error!("Could not determine application name from: {:?}", vec);
3657
return Err(anyhow::anyhow!(
3758
"could not determine application name from command line: {:?}",
3859
vec
3960
));
4061
}
4162

4263
let app_in_path = if let Ok(path) = which::which(&app) {
64+
log::debug!("Found application in path: {}", path.display());
4365
app = path.to_string_lossy().to_string();
4466
true
4567
} else {
68+
log::debug!("Application '{}' not found in PATH", app);
4669
false
4770
};
4871

72+
log::debug!("Created CommandLine: sudo={}, app={}, app_in_path={}, args={:?}",
73+
sudo, app, app_in_path, args);
74+
4975
Ok(Self {
5076
sudo,
5177
app,
@@ -60,39 +86,82 @@ impl CommandLine {
6086
vec: &Vec<String>,
6187
env: BTreeMap<String, String>,
6288
) -> anyhow::Result<Self> {
89+
log::debug!("Creating CommandLine with environment variables");
90+
log::trace!("Environment variables: {:?}", env);
6391
let mut cmd = Self::from_vec(vec)?;
6492
cmd.env = env;
6593
Ok(cmd)
6694
}
6795

96+
fn interpolate_variables(&mut self) -> anyhow::Result<()> {
97+
log::debug!("Interpolating variables from environment: {:?}", self.env);
98+
99+
self.args = self.args.iter().map(|arg| {
100+
let mut result = arg.clone();
101+
for (key, value) in &self.env {
102+
let pattern = format!("${{{}}}", key);
103+
if result.contains(&pattern) {
104+
log::debug!("Replacing {} with {}", pattern, value);
105+
result = result.replace(&pattern, value);
106+
}
107+
}
108+
result
109+
}).collect();
110+
111+
log::debug!("After interpolation: {:?}", self.args);
112+
Ok(())
113+
}
114+
68115
pub async fn execute(&self) -> anyhow::Result<String> {
69-
let output = tokio::process::Command::new(&self.app)
70-
.args(&self.args)
71-
.output()
72-
.await?;
116+
log::info!("Executing command: {}", self);
117+
log::debug!("Full command details: {:?}", self);
118+
119+
// Create a mutable copy for interpolation
120+
let mut cmd = self.clone();
121+
cmd.interpolate_variables()?;
122+
123+
let mut command = tokio::process::Command::new(&cmd.app);
124+
command.args(&cmd.args);
125+
126+
// Log environment variables if present
127+
if !cmd.env.is_empty() {
128+
log::debug!("Setting environment variables: {:?}", cmd.env);
129+
command.envs(&cmd.env);
130+
}
131+
132+
let output = command.output().await?;
133+
log::debug!("Command completed with status: {:?}", output.status);
73134

74135
let mut parts = vec![];
75136

76137
let stdout = String::from_utf8_lossy(&output.stdout);
77138
let stderr = String::from_utf8_lossy(&output.stderr);
78139

79140
if !output.status.success() {
141+
log::warn!("Command failed with exit code: {}", output.status);
80142
parts.push(format!("EXIT CODE: {}", &output.status));
81143
}
82144

83145
if !stdout.is_empty() {
146+
log::trace!("Command stdout: {}", stdout);
84147
parts.push(stdout.to_string());
85148
}
86149

87150
if !stderr.is_empty() {
88151
if output.status.success() {
152+
log::debug!("Command stderr (success): {}", stderr);
89153
parts.push(stderr.to_string());
90154
} else {
155+
log::error!("Command stderr (failure): {}", stderr);
91156
parts.push(format!("ERROR: {}", stderr));
92157
}
93158
}
94159

95-
Ok(parts.join("\n"))
160+
let result = parts.join("\n");
161+
log::debug!("Command execution completed, output length: {}", result.len());
162+
log::trace!("Command output: {}", result);
163+
164+
Ok(result)
96165
}
97166
}
98167

0 commit comments

Comments
 (0)