aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.rs
blob: ecada2a8641a2b805d2604875cea9e5b023a62c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use serde::Deserialize;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

pub const TEMP_CONFIG_PATH: &str = "/var/lib/forge/.tmp";

pub enum ConfigCommand {
    Build,
    Install,
    Uninstall,
}

#[derive(Deserialize)]
pub struct Config {
    pub update: Option<String>,
    pub build: Option<String>,
    pub install: Option<String>,
    pub uninstall: Option<String>,
    pub dependencies: Option<Vec<String>>,
}

impl Config {
    pub fn new<P: AsRef<Path>>(filepath: P) -> Option<Self> {
        let contents = match fs::read_to_string(filepath) {
            Ok(c) => c,
            Err(_) => {
                eprintln!("no package config found");
                return None;
            }
        };
        let config: Config = toml::from_str(&contents).expect("failed to parse config");
        Some(config)
    }
}

pub fn create_config(package: &str) -> Result<(), String> {
    let filename = format!("{package}.toml");
    let mut path = PathBuf::from(TEMP_CONFIG_PATH);

    if !path.exists() {
        fs::create_dir_all(&path)
            .map_err(|e| format!("failed to create temp config directory: {}", e))?;
    }

    path.push(filename);

    let template = format!(
        r#"# {package} configuration
update = "tagged" # no | live | tagged
build = "make"
install = "make install"
uninstall = "make uninstall"
dependencies = []
    "#
    );

    fs::write(path, template).map_err(|e| format!("failed to create config: {}", e))?;

    Ok(())
}

pub fn run_config_command(
    config_path: &Path,
    repo_path: &Path,
    command: ConfigCommand,
) -> Result<(), String> {
    let config = Config::new(config_path).ok_or("config not found".to_string())?;

    let cmd = match command {
        ConfigCommand::Build => config.build,
        ConfigCommand::Install => config.install,
        ConfigCommand::Uninstall => config.uninstall,
    };

    if let Some(c) = cmd {
        let mut parts = c.split_whitespace();
        let cmd_base = parts.next().ok_or("empty command".to_string())?;
        let args: Vec<&str> = parts.collect();

        let status = Command::new(cmd_base)
            .args(&args)
            .current_dir(repo_path)
            .status()
            .map_err(|e| format!("failed to execute command: {}", e))?;

        if !status.success() {
            return Err(format!("command exited with non-zero status: {}", status));
        }
    }

    Ok(())
}