use std::{env::current_dir, path::PathBuf}; use serde::Deserialize; const CUDDLE_FILE_NAME: &str = "cuddle.toml"; pub struct ProjectPlan { config: Config, pub root: PathBuf, } impl ProjectPlan { pub fn new(config: Config, root: PathBuf) -> Self { Self { config, root } } pub fn from_file(content: &str, root: PathBuf) -> anyhow::Result { let config: Config = toml::from_str(&content)?; Ok(Self::new(config, root)) } pub async fn from_current_path() -> anyhow::Result> { let cur_dir = current_dir()?; let cuddle_file = cur_dir.join(CUDDLE_FILE_NAME); tracing::trace!( path = cuddle_file.display().to_string(), "searching for cuddle.toml project file" ); if !cuddle_file.exists() { tracing::debug!("no cuddle.toml project file found"); // We may want to recursively search for the file (towards root) return Ok(None); } let cuddle_project_file = tokio::fs::read_to_string(cuddle_file).await?; Ok(Some(Self::from_file(&cuddle_project_file, cur_dir)?)) } pub fn has_plan(&self) -> bool { self.config.plan.is_some() } pub fn get_plan(&self) -> Plan { match &self.config.plan { Some(PlanConfig::Bare(git)) | Some(PlanConfig::Git { git }) => Plan::Git(git.clone()), Some(PlanConfig::Folder { path }) => Plan::Folder(path.clone()), None => Plan::None, } } } pub enum Plan { None, Git(String), Folder(PathBuf), } #[derive(Debug, Clone, Deserialize, PartialEq)] pub struct Config { plan: Option, } #[derive(Debug, Clone, Deserialize, PartialEq)] #[serde(untagged)] pub enum PlanConfig { Bare(String), Git { git: String }, Folder { path: PathBuf }, } #[cfg(test)] mod tests { use super::*; #[test] fn test_can_parse_simple_file() -> anyhow::Result<()> { let project = ProjectPlan::from_file( r##" [plan] git = "https://github.com/kjuulh/some-cuddle-project" "##, PathBuf::new(), )?; assert_eq!( Config { plan: Some(PlanConfig::Git { git: "https://github.com/kjuulh/some-cuddle-project".into() }) }, project.config ); Ok(()) } #[test] fn test_can_parse_simple_file_bare() -> anyhow::Result<()> { let project = ProjectPlan::from_file( r##" plan = "https://github.com/kjuulh/some-cuddle-project" "##, PathBuf::new(), )?; assert_eq!( Config { plan: Some(PlanConfig::Bare( "https://github.com/kjuulh/some-cuddle-project".into() )) }, project.config ); Ok(()) } #[test] fn test_can_parse_simple_file_none() -> anyhow::Result<()> { let project = ProjectPlan::from_file(r##""##, PathBuf::new())?; assert_eq!(Config { plan: None }, project.config); Ok(()) } }