use std::path::{Path, PathBuf};
use std::process::Stdio;
use anyhow::{Context, Result};
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use crate::config::Config;
#[derive(Debug)]
#[allow(dead_code)]
pub struct CompileOutput {
pub cgr: Vec<u8>,
pub stderr: String,
pub success: bool,
pub overlay_path: Option<PathBuf>,
}
pub async fn compile_file(
config: &Config,
file_path: &Path,
overlay_text: Option<&str>,
) -> Result<CompileOutput> {
let (path_to_compile, _tmp, overlay_path) = match overlay_text {
Some(text) => {
let dir = file_path
.parent()
.map(Path::to_path_buf)
.unwrap_or_else(|| PathBuf::from("."));
let name = file_path
.file_name()
.map(|s| s.to_owned())
.unwrap_or_else(|| "buffer.capnp".into());
let mut overlay = dir.clone();
overlay.push(format!(".capnprotols.{}", name.to_string_lossy()));
tokio::fs::write(&overlay, text)
.await
.with_context(|| format!("writing overlay {}", overlay.display()))?;
let guard = TempFile(overlay.clone());
(overlay.clone(), Some(guard), Some(overlay))
}
None => (file_path.to_path_buf(), None, None),
};
let mut cmd = Command::new(&config.compiler_path);
cmd.arg("compile").arg("-o-");
for inc in &config.import_paths {
cmd.arg("-I").arg(inc);
}
cmd.arg(&path_to_compile);
cmd
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = cmd
.spawn()
.with_context(|| format!("spawning {}", config.compiler_path))?;
if let Some(mut stdin) = child.stdin.take() {
let _ = stdin.shutdown().await;
}
let output = child
.wait_with_output()
.await
.context("capnp compile wait")?;
Ok(CompileOutput {
cgr: output.stdout,
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
success: output.status.success(),
overlay_path,
})
}
struct TempFile(PathBuf);
impl Drop for TempFile {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.0);
}
}