code_executor/
compiler.rs1use std::{path::PathBuf, process::Stdio};
2
3use tokio::{fs, io::AsyncWriteExt, process::Command};
4
5use crate::{CommandArgs, Error, Result, util};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct Compiler<'a> {
9 pub main_file: &'a str,
10 pub args: Option<CommandArgs<'a>>,
11}
12
13impl Compiler<'_> {
14 #[tracing::instrument(err)]
15 async fn create_project(&self, code: &[u8]) -> Result<PathBuf> {
16 let project_path = util::generate_unique_path();
17
18 fs::create_dir_all(&project_path).await?;
19
20 let mut main_file_path = project_path.clone();
21 main_file_path.push(self.main_file);
22
23 let mut main_file = fs::OpenOptions::new()
24 .create_new(true)
25 .write(true)
26 .open(&main_file_path)
27 .await?;
28
29 main_file.write_all(code).await?;
30
31 Ok(project_path)
32 }
33
34 #[tracing::instrument(err)]
35 pub async fn compile(&self, code: &[u8]) -> Result<PathBuf> {
36 let project_path = self.create_project(code).await?;
37
38 let Some(CommandArgs {
39 binary: compiler,
40 args,
41 }) = self.args
42 else {
43 return Ok(project_path);
44 };
45
46 let process = Command::new(compiler)
47 .args(args)
48 .current_dir(&project_path)
49 .stderr(Stdio::piped())
50 .spawn()?;
51
52 let compilation_error = process.wait_with_output().await?.stderr;
53
54 if !compilation_error.is_empty() {
55 return Err(Error::Compilation {
56 message: String::from_utf8(compilation_error)?,
57 });
58 }
59
60 Ok(project_path)
61 }
62}