Add support for stderr and split output handling.
More percent sign doubling support.
This commit is contained in:
parent
36ba81e4c4
commit
3e0030b85f
|
@ -13,9 +13,13 @@ if %echo some words%.contains("me wo") {
|
|||
let mem = %free -h%.lines().nth(1).unwrap()
|
||||
.split_whitespace().nth(3).unwrap().to_owned();
|
||||
|
||||
let (_stdout, _stderr) = %^curl bob%;
|
||||
println!("Collect stdout and stderr separately!");
|
||||
|
||||
// for i in 0..10000 {
|
||||
// println!("x contains %% example? [{}]", x.contains("example"));
|
||||
// }
|
||||
|
||||
%echo Double-up your percent signs to display them literally 100%%!%
|
||||
|
||||
println!("There are {} of memory free", &mem);
|
||||
%echo hello%
|
||||
|
|
95
src/main.rs
95
src/main.rs
|
@ -1,5 +1,3 @@
|
|||
#![feature(option_result_contains)]
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use std::env;
|
||||
|
@ -16,12 +14,12 @@ use std::process::Command;
|
|||
|
||||
#[derive(PartialEq, Clone)]
|
||||
enum PrintType {
|
||||
Out, Err, All
|
||||
StdOut, StdErr, AllOutputs
|
||||
}
|
||||
|
||||
fn com(print: &PrintType, command_string: &str) -> String {
|
||||
fn com(print: &PrintType, command_text: &str) -> String {
|
||||
let command_output = Command::new("bash").arg("-c")
|
||||
.arg(command_string)
|
||||
.arg(command_text)
|
||||
.output().unwrap();
|
||||
|
||||
let to_string = |bytes| str::from_utf8(bytes).unwrap().to_string();
|
||||
|
@ -29,9 +27,9 @@ fn com(print: &PrintType, command_string: &str) -> String {
|
|||
let err = to_string(&command_output.stderr);
|
||||
|
||||
match print {
|
||||
PrintType::Out => { print!("{}", out); out },
|
||||
PrintType::Err => { print!("{}", err); err },
|
||||
PrintType::All => {
|
||||
PrintType::StdOut => { print!("{}", out); out },
|
||||
PrintType::StdErr => { print!("{}", err); err },
|
||||
PrintType::AllOutputs => {
|
||||
print!("{}", out);
|
||||
if err.trim().is_empty() {
|
||||
print!("{}", err);
|
||||
|
@ -68,7 +66,11 @@ fn output_filename(script_name: &str) -> String {
|
|||
}
|
||||
|
||||
fn run_compiled(script_name: &str) {
|
||||
com(&PrintType::All, &output_filename(script_name));
|
||||
com(&PrintType::AllOutputs, &output_filename(script_name));
|
||||
}
|
||||
|
||||
fn contains<T: std::cmp::PartialEq>(opt: Option<T>, value: T) -> bool {
|
||||
opt.is_some() && opt.unwrap() == value
|
||||
}
|
||||
|
||||
fn parse_bash_command(
|
||||
|
@ -76,12 +78,28 @@ fn parse_bash_command(
|
|||
code: &mut String,
|
||||
is_expr: bool
|
||||
) -> Result<()> {
|
||||
code.push_str(&format!("com({}, \"", !is_expr));
|
||||
let next = iter.peek().expect("Unexpected EOF");
|
||||
code.push_str(&(match next {
|
||||
'^' => {
|
||||
iter.next();
|
||||
format!("out_and_err_com({}, \"", !is_expr)
|
||||
},
|
||||
'?' => {
|
||||
iter.next();
|
||||
format!("stderr_com({}, \"", !is_expr)
|
||||
},
|
||||
_ => format!("stdout_com({}, \"", !is_expr)
|
||||
}));
|
||||
loop {
|
||||
if let Some(c) = iter.next() {
|
||||
if c == '%' {
|
||||
// Double percents count as a single literal percent
|
||||
if contains(iter.peek(), &'%') {
|
||||
iter.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
code.push(c);
|
||||
} else {
|
||||
bail!("Unexpected end-of-file while parsing bash command");
|
||||
|
@ -89,7 +107,7 @@ fn parse_bash_command(
|
|||
}
|
||||
code.push_str("\")");
|
||||
let peek = iter.peek();
|
||||
if !is_expr && (peek.is_none() || peek.contains(&&' ') || peek.contains(&&'\n')) {
|
||||
if !is_expr && (peek.is_none() || contains(peek, &&' ') || contains(peek, &&'\n')) {
|
||||
code.push(';');
|
||||
}
|
||||
Ok(())
|
||||
|
@ -98,23 +116,45 @@ fn parse_bash_command(
|
|||
fn collect_code(script_name: &str) -> Result<String> {
|
||||
let script = fs::read_to_string(&script_name)?;
|
||||
|
||||
let mut code = "
|
||||
let mut code =
|
||||
"#![allow(dead_code)]
|
||||
|
||||
use std::str;
|
||||
use std::process::Command;
|
||||
|
||||
fn com(print: bool, comcom: &str) -> String {
|
||||
let s = str::from_utf8(&Command::new(\"bash\").arg(\"-c\")
|
||||
.arg(comcom).output().unwrap().stdout).unwrap().to_string();
|
||||
if print {
|
||||
fn stdout_com(print: bool, command_text: &str) -> String {
|
||||
let s = str::from_utf8(&Command::new(\"bash\").arg(\"-c\")
|
||||
.arg(command_text).output().unwrap().stdout).unwrap().to_string();
|
||||
if print {
|
||||
print!(\"{}\", s)
|
||||
};
|
||||
return s;
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn stderr_com(print: bool, command_text: &str) -> String {
|
||||
let s = str::from_utf8(&Command::new(\"bash\").arg(\"-c\")
|
||||
.arg(command_text).output().unwrap().stderr).unwrap().to_string();
|
||||
if print {
|
||||
print!(\"{}\", s)
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
fn out_and_err_com(print: bool, command_text: &str) -> (String, String) {
|
||||
let output = Command::new(\"bash\").arg(\"-c\")
|
||||
.arg(command_text).output().unwrap();
|
||||
let stdout = str::from_utf8(&output.stdout).unwrap().to_string();
|
||||
let stderr = str::from_utf8(&output.stderr).unwrap().to_string();
|
||||
if print {
|
||||
print!(\"{}\", stdout);
|
||||
eprint!(\"{}\", stderr);
|
||||
};
|
||||
return (stdout, stderr);
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
".to_string();
|
||||
|
||||
let mut is_expr = false;
|
||||
|
||||
let mut iter = script.chars().peekable();
|
||||
if script.starts_with("#!/") {
|
||||
|
@ -125,10 +165,11 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let mut is_expr = false;
|
||||
while let Some(c) = iter.next() {
|
||||
if c == '%' {
|
||||
// Double percents count as a single literal percent
|
||||
if iter.peek().contains(&&'%') {
|
||||
if contains(iter.peek(), &&'%') {
|
||||
code.push('%');
|
||||
iter.next();
|
||||
} else {
|
||||
|
@ -136,13 +177,13 @@ fn main() {
|
|||
}
|
||||
} else {
|
||||
code.push(c);
|
||||
if (c == 'i' && iter.peek().contains(&&'f'))
|
||||
|| (c == '=' && !iter.peek().contains(&&'=')) {
|
||||
if (c == 'i' && contains(iter.peek(), &&'f'))
|
||||
|| (c == '=' && !contains(iter.peek(), &&'=')) {
|
||||
is_expr = true;
|
||||
} else if c == 'f' && iter.peek().contains(&&'o') {
|
||||
} else if c == 'f' && contains(iter.peek(), &&'o') {
|
||||
iter.next();
|
||||
code.push('o');
|
||||
if iter.peek().contains(&&'r') {
|
||||
if contains(iter.peek(), &&'r') {
|
||||
is_expr = true;
|
||||
}
|
||||
} else if (c == '{' || c == ';') && is_expr {
|
||||
|
@ -152,7 +193,7 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
code.push('}');
|
||||
code.push_str(" Ok(())\n}");
|
||||
return Ok(code);
|
||||
}
|
||||
|
||||
|
@ -182,7 +223,7 @@ fn main() -> Result<()> {
|
|||
code_filename,
|
||||
output_filename(&script_name)
|
||||
);
|
||||
com(&PrintType::Err, &compile_command);
|
||||
com(&PrintType::StdErr, &compile_command);
|
||||
println!("[32m[Compiled in {}ms][0m\n", now.elapsed().as_millis());
|
||||
run_compiled(&script_name);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue