Skip to content

Commit

Permalink
basic env sub (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrPicklePinosaur authored Mar 1, 2023
1 parent 9751132 commit 163bb0a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 4 deletions.
1 change: 0 additions & 1 deletion shrs_lib/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern {
"&" => lexer::Token::AMP,
"|" => lexer::Token::PIPE,
"`" => lexer::Token::BACKTICK,
"$" => lexer::Token::DOLLAR,
"=" => lexer::Token::EQUAL,
"\\" => lexer::Token::BACKSLASH,
"'" => lexer::Token::SINGLEQUOTE,
Expand Down
2 changes: 0 additions & 2 deletions shrs_lib/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub enum Token<'input> {
AMP,
PIPE,
BACKTICK,
DOLLAR,
EQUAL,
BACKSLASH,
SINGLEQUOTE,
Expand Down Expand Up @@ -207,7 +206,6 @@ impl<'input> Iterator for Lexer<'input> {
_ => Some(Ok((start, Token::PIPE, end))),
},
'`' => Some(Ok((start, Token::BACKTICK, end))),
'$' => Some(Ok((start, Token::DOLLAR, end))),
'=' => Some(Ok((start, Token::EQUAL, end))),
'\\' => Some(Ok((start, Token::BACKSLASH, end))),
'\'' => Some(Ok((start, Token::SINGLEQUOTE, end))),
Expand Down
2 changes: 2 additions & 0 deletions shrs_lib/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl ParserContext {
}
}

/*
#[cfg(test)]
mod tests {
Expand All @@ -39,3 +40,4 @@ mod tests {
println!("{:?}", res);
}
}
*/
57 changes: 56 additions & 1 deletion shrs_lib/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,11 @@ impl Shell {

let envs = assigns.iter().map(|word| (&word.var, &word.val));

let subst_args = args.iter().map(|x| envsubst(rt, x)).collect::<Vec<_>>();

// TODO might need to do subst on cmd too
let child = Command::new(cmd)
.args(args)
.args(subst_args)
.stdin(stdin)
.stdout(stdout)
.process_group(pgid.unwrap_or(0)) // pgid of 0 means use own pid as pgid
Expand All @@ -446,3 +449,55 @@ pub fn dummy_child() -> anyhow::Result<Child> {
let cmd = Command::new("true").spawn()?;
Ok(cmd)
}

/// Performs environment substition on a string
// TODO regex replace might not be the best way. could also recognize the env var during parsing
// TODO handle escaped characters
fn envsubst(rt: &mut Runtime, arg: &str) -> String {
use regex::Regex;

// TODO precompile regex in lazy_static
let r_0 = Regex::new(r"\$(?P<env>[a-zA-Z_]+)").unwrap(); // no braces
let r_1 = Regex::new(r"\$\{(?P<env>[a-zA-Z_]+)\}").unwrap(); // with braces

let mut subst = arg.to_string();

for cap in r_0.captures_iter(arg) {
// look up env var
let var = &cap["env"];
// TODO stupid code
let val = match rt.env.get(var) {
Some(val) => val.clone(),
None => String::new(),
};
let fmt_env = format!("${}", var); // format $VAR
subst = subst.as_str().replace(&fmt_env, &val);
}

// TODO this is dumb stupid and bad repeated code
for cap in r_1.captures_iter(arg) {
let var = &cap["env"];
let val = match rt.env.get(var) {
Some(val) => val.clone(),
None => String::new(),
};
let fmt_env = format!("${{{}}}", var); // format ${VAR}
subst = subst.as_str().replace(&fmt_env, &val);
}
subst
}

#[cfg(test)]
mod tests {
use super::{envsubst, Runtime};

#[test]
fn envsubst_test() {
let mut rt = Runtime::default();
rt.env.set("EDITOR", "vim");
rt.env.set("SHELL", "/bin/shrs");
let text = "$SHELL ${EDITOR}";
let subst = envsubst(&mut rt, text);
assert_eq!(subst, String::from("/bin/shrs vim"));
}
}

0 comments on commit 163bb0a

Please sign in to comment.