use crate::{Cell, Executor};
use anyhow::{Context, Result, bail};
use std::path::PathBuf;
use std::process::Command;
pub struct DaemonExecutor {
qua: PathBuf,
paths: Vec<PathBuf>,
pinned_now: Option<String>,
flags: Vec<String>,
}
impl DaemonExecutor {
pub fn new(
paths: Vec<PathBuf>,
pinned_now: Option<String>,
allow_shell: bool,
hidden: bool,
no_ignore: bool,
descend: bool,
cache: bool,
) -> Result<Self> {
let qua = resolve_qua();
let mut flags = Vec::new();
if allow_shell {
flags.push("--allow-shell".to_string());
}
if hidden {
flags.push("--hidden".to_string());
}
if no_ignore {
flags.push("--no-ignore".to_string());
}
if descend {
flags.push("--descend".to_string());
}
if cache {
flags.push("--cache".to_string());
}
Ok(Self {
qua,
paths,
pinned_now,
flags,
})
}
}
fn resolve_qua() -> PathBuf {
if let Ok(exe) = std::env::current_exe()
&& let Some(dir) = exe.parent()
{
for name in ["qua", "qua.exe"] {
let sib = dir.join(name);
if sib.exists() {
return sib;
}
}
}
PathBuf::from("qua")
}
impl DaemonExecutor {
fn invoke(&self, resident: bool, query: &str) -> Result<Vec<Cell>> {
let mut cmd = Command::new(&self.qua);
if resident {
cmd.arg("--resident");
}
if let Some(iso) = &self.pinned_now {
cmd.arg("--now").arg(iso);
}
for f in &self.flags {
cmd.arg(f);
}
cmd.arg(query);
for p in &self.paths {
cmd.arg(p);
}
let out = cmd.output().with_context(|| {
format!(
"invoking '{}' (is qua installed and on PATH?)",
self.qua.display()
)
})?;
if !out.status.success() {
bail!("{}", String::from_utf8_lossy(&out.stderr).trim());
}
Ok(String::from_utf8_lossy(&out.stdout)
.lines()
.map(|l| Cell::Node(l.to_string()))
.collect())
}
}
impl Executor for DaemonExecutor {
fn run(&self, query: &str) -> Result<Vec<Cell>> {
self.invoke(true, query)
}
fn run_fresh(&self, query: &str) -> Result<Vec<Cell>> {
self.invoke(false, query)
}
}