zoi/project/
environment.rs

1use super::{config, executor};
2use crate::utils;
3use anyhow::{Result, anyhow};
4use colored::*;
5use dialoguer::{Select, theme::ColorfulTheme};
6use std::process::Command;
7
8pub fn setup(env_alias: Option<&str>, config: &config::ProjectConfig) -> Result<()> {
9    if config.environments.is_empty() {
10        return Err(anyhow!("No environments defined in zoi.yaml"));
11    }
12
13    let env_to_setup = match env_alias {
14        Some(alias) => config
15            .environments
16            .iter()
17            .find(|e| e.cmd == alias)
18            .ok_or_else(|| anyhow!("Environment '{alias}' not found in zoi.yaml"))?
19            .clone(),
20        None => {
21            let selections: Vec<&str> = config
22                .environments
23                .iter()
24                .map(|e| e.name.as_str())
25                .collect();
26            let selection = Select::with_theme(&ColorfulTheme::default())
27                .with_prompt("Choose an environment to set up")
28                .items(&selections)
29                .default(0)
30                .interact_opt()?
31                .ok_or(anyhow!("No environment chosen."))?;
32
33            config.environments[selection].clone()
34        }
35    };
36
37    println!(
38        "\n--- Setting up environment: {} ---",
39        env_to_setup.name.bold()
40    );
41
42    check_packages(config)?;
43
44    let platform = utils::get_platform()?;
45
46    let run_cmds = match &env_to_setup.run {
47        config::PlatformOrStringVec::StringVec(v) => v.clone(),
48        config::PlatformOrStringVec::Platform(p) => p
49            .get(&platform)
50            .or_else(|| p.get("default"))
51            .cloned()
52            .ok_or_else(|| {
53                anyhow!(
54                    "No commands found for platform '{}' and no default specified",
55                    platform
56                )
57            })?,
58    };
59
60    let env_vars = match &env_to_setup.env {
61        config::PlatformOrEnvMap::EnvMap(m) => m.clone(),
62        config::PlatformOrEnvMap::Platform(p) => p
63            .get(&platform)
64            .or_else(|| p.get("default"))
65            .cloned()
66            .unwrap_or_default(),
67    };
68
69    for cmd_str in &run_cmds {
70        executor::run_shell_command(cmd_str, &env_vars)?;
71    }
72
73    Ok(())
74}
75
76fn check_packages(config: &config::ProjectConfig) -> Result<()> {
77    if config.packages.is_empty() {
78        return Ok(());
79    }
80    println!("\nChecking required packages...");
81    let mut all_ok = true;
82    for package in &config.packages {
83        print!("- Checking for '{}': ", package.name.cyan());
84        let status = Command::new("bash")
85            .arg("-c")
86            .arg(&package.check)
87            .output()?;
88        if status.status.success() {
89            println!("{}", "OK".green());
90        } else {
91            println!("{}", "MISSING".red());
92            all_ok = false;
93        }
94    }
95    if !all_ok {
96        return Err(anyhow!("One or more required packages are missing."));
97    }
98    Ok(())
99}