From 61db3da6953acc15aad806b4fb0d5c1c501061d3 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Sat, 24 Aug 2024 15:16:30 +0200 Subject: [PATCH] feat: add validated state for project Signed-off-by: kjuulh --- crates/cuddle/src/main.rs | 2 +- crates/cuddle/src/state.rs | 96 +++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/crates/cuddle/src/main.rs b/crates/cuddle/src/main.rs index 2940fff..12a5764 100644 --- a/crates/cuddle/src/main.rs +++ b/crates/cuddle/src/main.rs @@ -82,7 +82,7 @@ impl Cuddle { state.validate_state(&raw_state).await? } else { - ValidatedState {} + ValidatedState::default() }; Ok(Cuddle { state }) diff --git a/crates/cuddle/src/state.rs b/crates/cuddle/src/state.rs index 32ddef5..0f0a846 100644 --- a/crates/cuddle/src/state.rs +++ b/crates/cuddle/src/state.rs @@ -1,3 +1,5 @@ +use validated_project::Project; + use crate::{ plan::{self, ClonedPlan, PlanPathExt}, project::{self, ProjectPlan}, @@ -33,8 +35,12 @@ impl State { } // 3. Match against schema from plan + let project = validated_project::Project::from_path(&state.project.root).await?; - Ok(ValidatedState {}) + Ok(ValidatedState { + project: Some(project), + plan: None, + }) } } @@ -42,4 +48,90 @@ pub struct RawState { project: project::RawProject, plan: Option, } -pub struct ValidatedState {} + +#[derive(Default)] +pub struct ValidatedState { + project: Option, + plan: Option, +} + +mod validated_project { + use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, + }; + + use anyhow::anyhow; + use toml::Table; + + use crate::project::CUDDLE_PROJECT_FILE; + + pub struct Project { + value: Value, + pub root: PathBuf, + } + + impl Project { + pub fn new(value: Value, root: &Path) -> Self { + Self { + value, + root: root.to_path_buf(), + } + } + + pub fn from_file(content: &str, root: &Path) -> anyhow::Result { + let table: Table = toml::from_str(content)?; + let config = Config::default(); + + let project = table + .get("project") + .ok_or(anyhow!("cuddle.toml doesn't provide a [project] table"))?; + + let value: Value = project.into(); + + Ok(Self::new(value, root)) + } + + pub async fn from_path(path: &Path) -> anyhow::Result { + let cuddle_file = path.join(CUDDLE_PROJECT_FILE); + + if !cuddle_file.exists() { + anyhow::bail!("no cuddle.toml project file found"); + } + + let cuddle_project_file = tokio::fs::read_to_string(cuddle_file).await?; + + Self::from_file(&cuddle_project_file, path) + } + } + + #[derive(Default)] + struct Config { + project: BTreeMap, + } + + pub enum Value { + String(String), + Bool(bool), + Array(Vec), + Map(BTreeMap), + } + + impl From<&toml::Value> for Value { + fn from(value: &toml::Value) -> Self { + match value { + toml::Value::String(s) => Self::String(s.clone()), + toml::Value::Integer(i) => Self::String(i.to_string()), + toml::Value::Float(f) => Self::String(f.to_string()), + toml::Value::Boolean(b) => Self::Bool(*b), + toml::Value::Datetime(dt) => Self::String(dt.to_string()), + toml::Value::Array(array) => Self::Array(array.iter().map(|i| i.into()).collect()), + toml::Value::Table(tbl) => { + Self::Map(tbl.iter().map(|(k, v)| (k.clone(), v.into())).collect()) + } + } + } + } +} + +pub struct Plan {}