code_executor/
compiler.rs

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