use super::{BrowserOptions, Error, ErrorKind, Result};
use log::debug;
use std::process::{Command, Stdio};
pub(crate) fn for_each_token<F>(line: &str, mut op: F)
where
F: FnMut(&str),
{
let mut start: Option<usize> = None;
let mut in_quotes = false;
let mut idx = 0;
for ch in line.chars() {
idx += 1;
match ch {
'"' => {
if let Some(start_idx) = start {
op(&line[start_idx..idx - 1]);
start = None;
in_quotes = false;
} else {
start = Some(idx);
in_quotes = true;
}
}
' ' => {
if !in_quotes {
if let Some(start_idx) = start {
op(&line[start_idx..idx - 1]);
start = None;
}
}
}
_ => {
if start.is_none() {
start = Some(idx - 1);
}
}
}
}
if let Some(start_idx) = start {
op(&line[start_idx..idx]);
}
}
pub(crate) fn run_command(
cmd: &mut Command,
background: bool,
options: &BrowserOptions,
) -> Result<()> {
if options.dry_run {
debug!("dry-run enabled, so not running: {:?}", &cmd);
return Ok(());
}
if background {
debug!("background spawn: {:?}", &cmd);
if options.suppress_output {
cmd.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
} else {
cmd
}
.spawn()
.map(|_| ())
} else {
debug!("foreground exec: {:?}", &cmd);
cmd.status().and_then(|status| {
if status.success() {
Ok(())
} else {
Err(Error::new(
ErrorKind::Other,
"command present but exited unsuccessfully",
))
}
})
}
}