hawk_cli/models/
config.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::fs;
4use std::path::Path;
5
6use crate::models::environment_files::{list_dirs, search_file, PackageJson, PnpmWorkspace};
7use crate::models::files;
8use crate::models::files::File;
9use crate::models::workspace;
10
11pub type Result<T> = std::result::Result<T, ConfigError>;
12
13#[derive(Debug)]
14pub enum ConfigError {
15    YamlError(serde_yaml::Error),
16    FileNotFound,
17    Any,
18}
19
20impl fmt::Display for ConfigError {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        match self {
23            ConfigError::FileNotFound => write!(f, "Could not find config file"),
24            ConfigError::YamlError(err) => {
25                write!(f, "{}", err)
26            }
27            ConfigError::Any => {
28                write!(f, "Something went wrong")
29            }
30        }
31    }
32}
33
34#[derive(Debug, Clone, Deserialize, Serialize)]
35pub struct Config {
36    pub workspaces: Vec<workspace::Workspace>,
37    pub target: String,
38}
39
40impl Config {
41    #[deprecated(since = "1.0.3")]
42    pub fn load_old(filepath: &str) -> Result<Config> {
43        if !Path::new(filepath).exists() {
44            return Err(ConfigError::FileNotFound);
45        }
46
47        let f = fs::File::open(filepath).expect("Unable to open file");
48
49        match serde_yaml::from_reader(f) {
50            Ok(data) => Ok(data),
51            Err(e) => Err(ConfigError::YamlError(e)),
52        }
53    }
54
55    #[deprecated(since = "1.0.3")]
56    pub fn validate_workspaces(&self) -> workspace::Result<()> {
57        for workspace in &self.workspaces {
58            workspace.validate_name()?;
59            workspace.validate_path()?;
60        }
61
62        Ok(())
63    }
64
65    pub fn new(target: &str) -> Config {
66        Config {
67            target: target.into(),
68            workspaces: Vec::new(),
69        }
70    }
71
72    /// Initialize config reading workspaces from package.json or `pnpm-workspace` if available.
73    /// `pnpm-workspace` has priority over package.json workspaces key.
74    pub fn init(target: &str, workflows_dir: &str) -> files::Result<Config> {
75        let mut config = Config::new(target);
76        let package_json_path = search_file(".", "package.json");
77        let pnpm_workspace_path = search_file(".", "pnpm-workspace.yaml");
78
79        if pnpm_workspace_path.is_some() {
80            let mut workspaces: Vec<workspace::Workspace> = Vec::new();
81            let pnpm_workspace: PnpmWorkspace = PnpmWorkspace::load(&pnpm_workspace_path.unwrap())?;
82
83            for el in pnpm_workspace.packages {
84                add_workspaces(
85                    &mut workspaces,
86                    Path::new(&format!("./{}", el.replace("/*", ""))),
87                    workflows_dir,
88                )?;
89            }
90
91            config.workspaces = workspaces;
92
93            return Ok(config);
94        }
95
96        if let Some(path) = package_json_path {
97            let package_json = PackageJson::load(&path)?;
98            let mut workspaces: Vec<workspace::Workspace> = Vec::new();
99
100            if !package_json.clone().has_workspaces() {
101                return Ok(config);
102            }
103
104            for el in package_json.workspaces.unwrap() {
105                add_workspaces(
106                    &mut workspaces,
107                    Path::new(&format!("./{}", el.replace("/*", ""))),
108                    workflows_dir,
109                )?;
110            }
111
112            config.workspaces = workspaces;
113        }
114
115        Ok(config)
116    }
117}
118
119fn add_workspaces(
120    workspaces: &mut Vec<workspace::Workspace>,
121    directory: &Path,
122    workflows_dir: &str,
123) -> files::Result<()> {
124    for dir in list_dirs(directory) {
125        if search_file(dir.to_str().unwrap(), "package.json").is_some() {
126            let pkg = PackageJson::load(dir.join("package.json").as_path())
127                .expect("could not find package json");
128
129            let wk = workspace::Workspace {
130                name: pkg.name,
131                package_json: Some(dir.to_str().unwrap().into()),
132                path: dir.join(workflows_dir).to_str().unwrap_or_default().into(),
133            };
134
135            workspaces.push(wk);
136        } else {
137            workspaces.push(workspace::Workspace {
138                name: dir.file_stem().unwrap().to_str().unwrap().into(),
139                package_json: None,
140                path: dir.join(workflows_dir).to_str().unwrap_or_default().into(),
141            });
142        }
143    }
144
145    Ok(())
146}
147
148impl File<Config> for Config {}