diff --git a/src/blog_post/definition.rs b/src/blog_post/definition.rs index 4c7da73..5ef06b0 100644 --- a/src/blog_post/definition.rs +++ b/src/blog_post/definition.rs @@ -1,5 +1,13 @@ +use std::path::Path; +use std::path::PathBuf; + +use tokio::task::JoinHandle; +use walkdir::WalkDir; + +use crate::error::CustomError; + #[derive(Debug)] -struct BlogPost { +pub(crate) struct BlogPost { id: String, } @@ -7,11 +15,8 @@ impl BlogPost { pub(crate) async fn load_blog_post, R: AsRef>( root_dir: R, post_dir: P, - ) -> Result> { - async fn inner( - root_dir: &Path, - post_dir: &Path, - ) -> Result> { + ) -> Result { + async fn inner(root_dir: &Path, post_dir: &Path) -> Result { let org_files = { let mut ret = Vec::new(); let org_files_iter = get_org_files(post_dir)?; @@ -23,7 +28,8 @@ impl BlogPost { let parsed_org_files = { let mut ret = Vec::new(); for (path, contents) in org_files.iter() { - let parsed = organic::parser::parse_file(contents.as_str(), Some(path))?; + let parsed = organic::parser::parse_file(contents.as_str(), Some(path)) + .map_err(|_| CustomError::Static("Failed to parse org-mode document."))?; ret.push((path, contents, parsed)); } ret @@ -37,6 +43,11 @@ impl BlogPost { } } +async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> { + let contents = tokio::fs::read_to_string(&path).await?; + Ok((path, contents)) +} + fn get_org_files>( root_dir: P, ) -> Result>>, walkdir::Error> { diff --git a/src/blog_post/mod.rs b/src/blog_post/mod.rs index e69de29..9d44a74 100644 --- a/src/blog_post/mod.rs +++ b/src/blog_post/mod.rs @@ -0,0 +1,2 @@ +mod definition; +pub(crate) use definition::BlogPost; diff --git a/src/command/build/runner.rs b/src/command/build/runner.rs index e241370..38fb73e 100644 --- a/src/command/build/runner.rs +++ b/src/command/build/runner.rs @@ -1,57 +1,23 @@ -use std::path::Path; -use std::path::PathBuf; - +use crate::blog_post::BlogPost; use crate::cli::parameters::BuildArgs; use crate::config::Config; -use tokio::task::JoinHandle; +use crate::error::CustomError; use walkdir::WalkDir; -pub(crate) async fn build_site(args: BuildArgs) -> Result<(), Box> { +pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> { let config = Config::load_from_file(args.config).await?; - let org_files = { - let mut ret = Vec::new(); - let org_files_iter = get_org_files(config.get_root_directory())?; - for entry in org_files_iter { - ret.push(entry.await??); - } - ret - }; - let parsed_org_files = { - let mut ret = Vec::new(); - for (path, contents) in org_files.iter() { - let parsed = organic::parser::parse_file(contents.as_str(), Some(path))?; - ret.push((path, contents, parsed)); - } - ret - }; - - Ok(()) -} - -async fn read_file(path: PathBuf) -> std::io::Result<(PathBuf, String)> { - let contents = tokio::fs::read_to_string(&path).await?; - Ok((path, contents)) -} - -fn get_org_files>( - root_dir: P, -) -> Result>>, walkdir::Error> { - let org_files = WalkDir::new(root_dir) + let root_directory = config.get_root_directory().to_owned(); + let post_directories = WalkDir::new(config.get_posts_directory()) .into_iter() .filter(|e| match e { - Ok(dir_entry) => { - dir_entry.file_type().is_file() - && Path::new(dir_entry.file_name()) - .extension() - .map(|ext| ext.to_ascii_lowercase() == "org") - .unwrap_or(false) - } + Ok(entry) if entry.depth() == 1 && entry.file_type().is_dir() => true, + Ok(_) => false, Err(_) => true, }) .collect::, _>>()?; - let org_files = org_files + let load_jobs = post_directories .into_iter() .map(walkdir::DirEntry::into_path) - .map(|path| tokio::spawn(read_file(path))); - Ok(org_files) + .map(|path| tokio::spawn(BlogPost::load_blog_post(root_directory.clone(), path))); + Ok(()) } diff --git a/src/command/init/runner.rs b/src/command/init/runner.rs index 976f7a2..40d1871 100644 --- a/src/command/init/runner.rs +++ b/src/command/init/runner.rs @@ -1,7 +1,8 @@ use crate::cli::parameters::InitArgs; use crate::config::Config; +use crate::error::CustomError; -pub(crate) async fn init_writer_folder(args: InitArgs) -> Result<(), Box> { +pub(crate) async fn init_writer_folder(args: InitArgs) -> Result<(), CustomError> { if args.path.exists() && !args.path.is_dir() { return Err("The supplied path exists but is not a directory. Aborting.".into()); } diff --git a/src/config/full.rs b/src/config/full.rs index 73837f2..c2aeb61 100644 --- a/src/config/full.rs +++ b/src/config/full.rs @@ -3,6 +3,8 @@ use std::path::PathBuf; use tokio::fs::File; use tokio::io::AsyncWriteExt; +use crate::error::CustomError; + use super::raw::RawConfig; /// This is the config struct used by most of the code, which is an interpreted version of the RawConfig struct which is the raw disk-representation of the config. @@ -12,8 +14,8 @@ pub(crate) struct Config { } impl Config { - pub(crate) fn new>(root_dir: P) -> Result> { - fn inner(root_dir: &Path) -> Result> { + pub(crate) fn new>(root_dir: P) -> Result { + fn inner(root_dir: &Path) -> Result { let file_path = root_dir.join("writer.toml"); Ok(Config { raw: RawConfig::default(), @@ -23,10 +25,8 @@ impl Config { inner(root_dir.as_ref()) } - pub(crate) async fn load_from_file>( - path: P, - ) -> Result> { - async fn inner(path: PathBuf) -> Result> { + pub(crate) async fn load_from_file>(path: P) -> Result { + async fn inner(path: PathBuf) -> Result { let contents = tokio::fs::read_to_string(&path).await?; let parsed_contents: RawConfig = toml::from_str(contents.as_str())?; Ok(Config { @@ -37,7 +37,7 @@ impl Config { inner(path.into()).await } - pub(crate) async fn write_to_disk(&self) -> Result<(), Box> { + pub(crate) async fn write_to_disk(&self) -> Result<(), CustomError> { let mut config_file = File::create(&self.config_path).await?; config_file .write_all(toml::to_string(&self.raw)?.as_bytes()) @@ -51,4 +51,8 @@ impl Config { .parent() .expect("Config file must exist inside a directory.") } + + pub(crate) fn get_posts_directory(&self) -> PathBuf { + self.get_root_directory().join("posts") + } } diff --git a/src/error/error.rs b/src/error/error.rs new file mode 100644 index 0000000..130f283 --- /dev/null +++ b/src/error/error.rs @@ -0,0 +1,45 @@ +#[derive(Debug)] +pub(crate) enum CustomError { + Static(&'static str), + IO(std::io::Error), + TomlSerialize(toml::ser::Error), + TomlDeserialize(toml::de::Error), + WalkDir(walkdir::Error), + Tokio(tokio::task::JoinError), +} + +impl From for CustomError { + fn from(value: std::io::Error) -> Self { + CustomError::IO(value) + } +} + +impl From<&'static str> for CustomError { + fn from(value: &'static str) -> Self { + CustomError::Static(value) + } +} + +impl From for CustomError { + fn from(value: toml::ser::Error) -> Self { + CustomError::TomlSerialize(value) + } +} + +impl From for CustomError { + fn from(value: toml::de::Error) -> Self { + CustomError::TomlDeserialize(value) + } +} + +impl From for CustomError { + fn from(value: walkdir::Error) -> Self { + CustomError::WalkDir(value) + } +} + +impl From for CustomError { + fn from(value: tokio::task::JoinError) -> Self { + CustomError::Tokio(value) + } +} diff --git a/src/error/mod.rs b/src/error/mod.rs new file mode 100644 index 0000000..84e7c7c --- /dev/null +++ b/src/error/mod.rs @@ -0,0 +1,3 @@ +#[allow(clippy::module_inception)] +mod error; +pub(crate) use error::CustomError; diff --git a/src/main.rs b/src/main.rs index b16e9cb..124c99b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,12 +6,14 @@ use self::cli::parameters::Cli; use self::cli::parameters::Commands; use self::command::build::build_site; use self::command::init::init_writer_folder; +use self::error::CustomError; mod blog_post; mod cli; mod command; mod config; +mod error; -fn main() -> Result> { +fn main() -> Result { let rt = tokio::runtime::Runtime::new()?; rt.block_on(async { let main_body_result = main_body().await; @@ -19,7 +21,7 @@ fn main() -> Result> { }) } -async fn main_body() -> Result> { +async fn main_body() -> Result { let args = Cli::parse(); match args.command { Commands::Init(args) => {