archetect_core/
requirements.rs

1use crate::Archetect;
2use semver::{Version, VersionReq};
3use std::fs;
4use std::path::PathBuf;
5
6#[derive(Debug, Deserialize, Serialize)]
7pub struct Requirements {
8    #[serde(rename = "archetect")]
9    archetect_requirement: VersionReq,
10}
11
12impl Requirements {
13    pub fn new(archetect_version: VersionReq) -> Requirements {
14        Requirements {
15            archetect_requirement: archetect_version,
16        }
17    }
18
19    pub fn archetect_version(&self) -> &VersionReq {
20        &self.archetect_requirement
21    }
22
23    pub fn load<P: Into<PathBuf>>(path: P) -> Result<Option<Requirements>, RequirementsError> {
24        let mut path = path.into();
25        if path.is_dir() {
26            let candidates = vec!["requirements.yml", "requirements.yaml"];
27            for candidate in candidates {
28                let config_file = path.join(candidate);
29                if config_file.exists() {
30                    path = config_file;
31                    break;
32                }
33            }
34        }
35        if !path.exists() || path.is_dir() {
36            Ok(None)
37        } else {
38            let config = fs::read_to_string(&path)?;
39            match serde_yaml::from_str::<Requirements>(&config) {
40                Ok(result) => {
41                    return Ok(Some(result));
42                }
43                Err(error) => {
44                    return Err(RequirementsError::DeserializationError {
45                        path: path,
46                        cause: error,
47                    });
48                }
49            }
50        }
51    }
52
53    pub fn verify(&self, archetect: &Archetect) -> Result<(), RequirementsError> {
54        if !self.archetect_requirement.matches(&archetect.version()) {
55            Err(RequirementsError::ArchetectVersion(
56                archetect.version().clone(),
57                self.archetect_requirement.clone(),
58            ))
59        } else {
60            Ok(())
61        }
62    }
63}
64
65#[derive(Debug, thiserror::Error)]
66pub enum RequirementsError {
67    #[error("Error Deserializing Requirements File `{path}`: {cause}")]
68    DeserializationError { path: PathBuf, cause: serde_yaml::Error },
69    #[error("Incompatible Archetect Version `{0}`. Requirements: {1}")]
70    ArchetectVersion(Version, VersionReq),
71    #[error("IO Error Reading Requirements File `{0}`.")]
72    IoError(std::io::Error),
73}
74
75impl From<std::io::Error> for RequirementsError {
76    fn from(error: std::io::Error) -> Self {
77        RequirementsError::IoError(error)
78    }
79}