use std::path::Component; use std::path::Path; use std::path::PathBuf; use crate::config::Config; use crate::error::CustomError; use crate::types::GlobalSettings; use crate::types::RenderBlogPostPage; use super::BlogPost; use super::BlogPostPage; pub(crate) fn convert_blog_post_page_to_render_context, F: AsRef>( config: &Config, output_directory: D, output_file: F, _post: &BlogPost, page: &BlogPostPage, ) -> Result { let output_directory = output_directory.as_ref(); let output_file = output_file.as_ref(); let css_files = vec![get_web_path( config, output_directory, output_file, "main.css", )?]; let js_files = vec![get_web_path( config, output_directory, output_file, "blog_post.js", )?]; let global_settings = GlobalSettings::new(page.title.clone(), css_files, js_files); let link_to_blog_post = get_web_path( config, output_directory, output_file, output_file.strip_prefix(output_directory)?, )?; let ret = RenderBlogPostPage::new(global_settings, page.title.clone(), Some(link_to_blog_post)); Ok(ret) } fn get_web_path, F: AsRef, P: AsRef>( config: &Config, output_directory: D, containing_file: F, path_from_web_root: P, ) -> Result { let path_from_web_root = path_from_web_root.as_ref(); if config.use_relative_paths() { let output_directory = output_directory.as_ref(); let containing_file = containing_file.as_ref(); let containing_file_relative_to_output_directory = containing_file.strip_prefix(output_directory)?; let shared_stem = get_shared_steps( containing_file_relative_to_output_directory .parent() .ok_or("File should exist in a folder.")?, path_from_web_root .parent() .ok_or("File should exist in a folder.")?, ) .collect::(); // Subtracting 1 from the depth to "remove" the file name. let depth_from_shared_stem = containing_file_relative_to_output_directory .strip_prefix(&shared_stem)? .components() .count() - 1; let final_path = PathBuf::from("../".repeat(depth_from_shared_stem)) .join(path_from_web_root.strip_prefix(shared_stem)?); let final_string = final_path .as_path() .to_str() .map(str::to_string) .ok_or("Path should be valid utf-8.")?; Ok(final_string) } else { let web_root = config .get_web_root() .ok_or("Must either use_relative_paths or set the web_root in the config.")?; let final_path = PathBuf::from(web_root).join(path_from_web_root); let final_string = final_path .as_path() .to_str() .map(str::to_string) .ok_or("Path should be valid utf-8.")?; Ok(final_string) } } fn get_shared_steps<'a>(left: &'a Path, right: &'a Path) -> impl Iterator> { let shared_stem = left .components() .zip(right.components()) .take_while(|(l, r)| l == r) .map(|(l, _r)| l); shared_stem } #[cfg(test)] mod tests { use super::*; #[test] fn test_get_shared_steps() { assert_eq!( get_shared_steps(Path::new(""), Path::new("")).collect::(), PathBuf::from("") ); assert_eq!( get_shared_steps(Path::new("foo.txt"), Path::new("foo.txt")).collect::(), PathBuf::from("foo.txt") ); assert_eq!( get_shared_steps(Path::new("cat/foo.txt"), Path::new("dog/foo.txt")) .collect::(), PathBuf::from("") ); assert_eq!( get_shared_steps( Path::new("foo/bar/baz/lorem.txt"), Path::new("foo/bar/ipsum/dolar.txt") ) .collect::(), PathBuf::from("foo/bar") ); } }