Skip to content

Commit

Permalink
devenv: escape shell vars in task exports
Browse files Browse the repository at this point in the history
Fixes sourcing exported variables with spaces in them. Hello, macOS.
  • Loading branch information
sandydoo committed Sep 26, 2024
1 parent e02d3bd commit f2e17c6
Showing 1 changed file with 27 additions and 1 deletion.
28 changes: 27 additions & 1 deletion devenv/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,11 @@ impl TaskState {
for (env_key, env_value) in env_obj {
if let Some(env_str) = env_value.as_str() {
command.env(env_key, env_str);
devenv_env.push_str(&format!("export {}={}\n", env_key, env_str));
devenv_env.push_str(&format!(
"export {}={}\n",
env_key,
shell_escape(env_str)
));
}
}
}
Expand Down Expand Up @@ -836,6 +840,21 @@ impl TasksUi {
}
}

/// Escape a shell variable by wrapping it in single quotes.
/// Any single quotes within the variable are escaped.
fn shell_escape(s: &str) -> String {
let mut escaped = String::with_capacity(s.len() + 2);
escaped.push('\'');
for c in s.chars() {
match c {
'\'' => escaped.push_str("'\\''"),
_ => escaped.push(c),
}
}
escaped.push('\'');
escaped
}

#[cfg(test)]
mod test {
use super::*;
Expand All @@ -846,6 +865,13 @@ mod test {
use std::io::Write;
use std::os::unix::fs::PermissionsExt;

#[test]
fn test_shell_escape() {
let escaped = shell_escape("foo'bar");
eprintln!("{escaped}");
assert_eq!(escaped, "'foo'\\''bar'");
}

#[tokio::test]
async fn test_task_name() -> Result<(), Error> {
let invalid_names = vec![
Expand Down

0 comments on commit f2e17c6

Please sign in to comment.