diff --git a/src/site.rs b/src/site.rs index d8fab1d..da279e1 100644 --- a/src/site.rs +++ b/src/site.rs @@ -1,12 +1,69 @@ //! Management of on-disk layout of the source of a site -use std::{collections::HashMap, path::PathBuf}; +use std::{ + collections::HashMap, + fs::{create_dir_all, File}, + io::Write, + path::{Path, PathBuf}, +}; + +use snafu::{ensure, ResultExt, Snafu}; +use tracing::{debug, instrument}; use self::{config::Config, page::Page}; pub mod config; pub mod page; +/// Error encountered interacting with a [`Site`] +#[derive(Snafu, Debug)] +pub enum SiteError { + /// Error checking to see if a path exists + #[snafu(display("Error checking if path exists: {:?}", path))] + ExistanceCheck { + /// Path being checked + path: PathBuf, + /// Underlying error + source: std::io::Error, + }, + /// Error creating a directory + #[snafu(display("Error creating directory:: {:?}", path))] + CreateDirectory { + /// Path being checked + path: PathBuf, + /// Underlying error + source: std::io::Error, + }, + /// Site repository dir was not a directory + #[snafu(display("Site repository path was not a directory: {:?}", path))] + NotADirectory { + /// Path being checked + path: PathBuf, + }, + /// Failed to reify the configuration + ConfigReify { + /// The underlying error + #[snafu(source(from(serde_dhall::Error, Box::new)))] + source: Box, + }, + /// Failed to write out the configuration + WriteConfig { + /// The path we tried to write the config to + path: PathBuf, + /// The underlying error + source: std::io::Error, + }, + /// Error writing out a page + #[snafu(display("Error writing out page {:?}", page))] + PageWrite { + /// The page we were trying to write out + page: PathBuf, + /// The underlying error + #[snafu(source(from(SiteError, Box::new)))] + source: Box, + }, +} + /// Representation of the on-disk structure of a site #[derive(Debug)] pub struct Site { @@ -26,3 +83,42 @@ impl Default for Site { } } } + +impl Site { + /// Writes out the configuration for a `Site`, and makes sure the files for all the pages exist + /// + /// # Errors + /// + /// Will return an error if serialization fails, the user does not have write permissions for + /// the directory, or any other IO errors occur while writing out the config. + #[instrument(skip(site_dir))] + pub fn write(&self, site_dir: impl AsRef) -> Result<(), SiteError> { + let site_dir = site_dir.as_ref(); + debug!(?site_dir); + // Make sure the site_dir is a directory, if it exists, otherwise create it + if site_dir + .try_exists() + .context(ExistanceCheckSnafu { path: site_dir })? + { + ensure!(site_dir.is_dir(), NotADirectorySnafu { path: site_dir }); + } else { + create_dir_all(site_dir).context(CreateDirectorySnafu { path: site_dir })?; + } + // Serialize the config + let config_path = site_dir.join("config.dhall"); + let serialized_config = serde_dhall::serialize(&self.config) + .to_string() + .context(ConfigReifySnafu)?; + let mut config_file = + File::create(&config_path).context(WriteConfigSnafu { path: &config_path })?; + config_file + .write_all(serialized_config.as_bytes()) + .context(WriteConfigSnafu { path: &config_path })?; + // Write out the pages + for (page_path, page) in &self.pages { + page.write(site_dir, page_path) + .context(PageWriteSnafu { page: page_path })?; + } + Ok(()) + } +} diff --git a/src/site/page.rs b/src/site/page.rs index 0a17770..3ad061c 100644 --- a/src/site/page.rs +++ b/src/site/page.rs @@ -1,9 +1,11 @@ //! Management of a page -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; +use super::SiteError; + /// Representation of the configuration for a page #[derive(Serialize, Deserialize, Debug)] pub struct PageConfig { @@ -47,3 +49,19 @@ impl Default for Page { } } } + +impl Page { + /// Writes out the configuration for a `Page`, and makes sure the file for the page exists + /// + /// # Errors + /// + /// Will return an error if serialization fails, the user does not have write permissions for + /// the directory, or any other IO errors occur while writing out the config. + pub fn write( + &self, + site_path: impl AsRef, + page_path: impl AsRef, + ) -> Result<(), SiteError> { + todo!() + } +}