use project::Project; #[tokio::main] async fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); tracing_subscriber::fmt::init(); Cuddle::new().await?; Ok(()) } struct Cuddle { project: Option, } impl Cuddle { pub async fn new() -> anyhow::Result { let project = Project::from_current_path().await?; Ok(Self { project }) } } mod project { use std::env::current_dir; use serde::Deserialize; const CUDDLE_FILE_NAME: &str = "cuddle.toml"; pub struct Project { config: Config, } impl Project { pub fn new(config: Config) -> Self { Self { config } } pub fn from_file(content: &str) -> anyhow::Result { let config: Config = toml::from_str(&content)?; Ok(Self::new(config)) } pub async fn from_current_path() -> anyhow::Result> { let cur_dir = current_dir()?; let cuddle_file = cur_dir.join(CUDDLE_FILE_NAME); if !cuddle_file.exists() { // 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)?)) } } #[derive(Debug, Clone, Deserialize, PartialEq)] pub struct Config { project: ProjectConfig, } #[derive(Debug, Clone, Deserialize, PartialEq)] pub struct ProjectConfig { name: String, } #[cfg(test)] mod tests { use super::*; #[test] fn test_can_parse_simple_file() -> anyhow::Result<()> { let project = Project::from_file( r##" [project] name = "simple_file" "##, )?; assert_eq!( Config { project: ProjectConfig { name: "simple_file".into() } }, project.config ); Ok(()) } } }