use std::path::Path;
use serde::Deserialize;
use crate::error::{Error, Result};
use crate::indicator::Indicator;
use crate::project_type::ProjectType;
use crate::registry::Registry;
#[derive(Debug, Default, Deserialize)]
pub struct Config {
#[serde(default)]
pub project_types: Vec<ConfigEntry>,
}
#[derive(Debug, Deserialize)]
pub struct ConfigEntry {
#[serde(default)]
pub name: String,
#[serde(default)]
pub description: String,
#[serde(default)]
pub indicators: Vec<ConfigIndicator>,
}
#[derive(Debug, Default, Deserialize)]
pub struct ConfigIndicator {
#[serde(default)]
pub has_file: Option<String>,
#[serde(default)]
pub has_glob: Option<String>,
#[serde(default)]
pub has_subdir_glob: Option<String>,
#[serde(default)]
pub cel: Option<String>,
}
impl Registry {
pub fn load_from_file(&mut self, path: impl AsRef<Path>) -> Result<usize> {
let path = path.as_ref();
let data = std::fs::read_to_string(path).map_err(|source| Error::Io {
path: path.to_path_buf(),
source,
})?;
let cfg: Config = serde_norway::from_str(&data).map_err(|source| Error::Yaml {
path: path.to_path_buf(),
source,
})?;
let mut registered = 0;
for entry in cfg.project_types {
let pt = build_project_type(entry)?;
self.register(pt)?;
registered += 1;
}
Ok(registered)
}
}
fn build_project_type(entry: ConfigEntry) -> Result<ProjectType> {
if entry.name.is_empty() {
return Err(Error::Config {
name: entry.name,
reason: "name is required".to_string(),
});
}
if entry.indicators.is_empty() {
return Err(Error::Config {
name: entry.name,
reason: "at least one indicator is required".to_string(),
});
}
let mut indicators = Vec::with_capacity(entry.indicators.len());
for (j, ci) in entry.indicators.into_iter().enumerate() {
let ind = if let Some(s) = ci.has_file {
Indicator::HasFile(s)
} else if let Some(s) = ci.has_glob {
Indicator::HasGlob(s)
} else if let Some(s) = ci.has_subdir_glob {
Indicator::HasSubdirGlob(s)
} else if let Some(s) = ci.cel {
Indicator::Cel(s)
} else {
return Err(Error::Config {
name: entry.name,
reason: format!(
"indicator[{j}]: must set has_file / has_glob / has_subdir_glob / cel"
),
});
};
indicators.push(ind);
}
Ok(ProjectType::new(
entry.name,
entry.description,
indicators,
Vec::new(),
))
}