Skip to main content

ocy_core/
command.rs

1use std::{process::Command, thread::sleep, time::Duration};
2
3use crate::models::FileInfo;
4
5use eyre::{Context, Result, eyre};
6
7pub trait CommandExecutor {
8    fn execute_command(&self, work_dir: &FileInfo, command: &str) -> Result<()>;
9}
10
11#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
12pub struct MockCommandExecutor;
13
14impl CommandExecutor for MockCommandExecutor {
15    fn execute_command(&self, _work_dir: &FileInfo, _command: &str) -> Result<()> {
16        sleep(Duration::from_secs(2));
17        Ok(())
18    }
19}
20
21#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
22pub struct RealCommandExecutor;
23
24impl CommandExecutor for RealCommandExecutor {
25    fn execute_command(&self, work_dir: &FileInfo, command: &str) -> Result<()> {
26        let mut parts = command.split_ascii_whitespace();
27        let program = parts
28            .next()
29            .ok_or_else(|| eyre!("refusing to run an empty command"))?;
30
31        let status = Command::new(program)
32            .current_dir(&work_dir.path)
33            .args(parts)
34            .status()
35            .with_context(|| format!("failed to spawn `{command}`"))?;
36
37        if status.success() {
38            Ok(())
39        } else {
40            Err(eyre!("`{command}` failed: {status}"))
41        }
42    }
43}
44
45#[cfg(test)]
46mod tests;