///|
pub(all) suberror ExecError {
CommandFailed(cmd~ : String, code~ : Int)
} derive(Eq, Show)
///|
pub fn shell_escape(s : String) -> String {
let sb = StringBuilder::new()
sb.write_char('\'')
for c in s {
if c == '\'' {
sb.write_char('\'')
sb.write_char('\\')
sb.write_char('\'')
sb.write_char('\'')
} else {
sb.write_char(c)
}
}
sb.write_char('\'')
sb.to_string()
}
///|
pub fn shell_join(args : Array[String]) -> String {
args.iter().map(arg => shell_escape(arg)).join(" ")
}
///|
pub fn run_shell(cmd : String) -> Result[Unit, ExecError] {
let code = system(to_c_string(cmd))
if code == 0 {
Ok(())
} else {
Err(ExecError::CommandFailed(cmd~, code~))
}
}
///|
pub fn run_shell_in_dir(
dir : String,
args : Array[String],
) -> Result[Unit, ExecError] {
let cmd = "cd " + shell_escape(dir) + " && " + shell_join(args)
run_shell(cmd)
}
///|
fn to_c_string(s : String) -> Bytes {
let bytes = @utf8.encode(s)
let arr = bytes.to_array()
arr.push(0)
Bytes::from_array(arr)
}
///|
#borrow(cmd)
extern "C" fn system(cmd : Bytes) -> Int = "system"