use std::path::Path; use std::path::PathBuf; use crate::config::Config; use crate::error::CustomError; use super::render_context::GlobalSettings; use super::render_context::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)?; // Subtracting 1 from the depth to "remove" the file name. let depth_from_web_root = containing_file_relative_to_output_directory .components() .count() - 1; let prefix = "../".repeat(depth_from_web_root); // TODO: It should be possible to strip some of the "../" components based on whether the path_from_web_root goes down the same path as the containing file. let final_path = PathBuf::from(prefix).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) } 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) } } #[allow(dead_code)] fn count_shared_steps, B: AsRef>(left: A, right: B) -> usize { let left = left.as_ref(); let right = right.as_ref(); left.components() .zip(right.components()) .position(|(l, r)| l != r) .unwrap_or_else(|| left.components().count()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_count_shared_steps() { assert_eq!(count_shared_steps("", ""), 0); assert_eq!(count_shared_steps("foo.txt", "foo.txt"), 1); assert_eq!(count_shared_steps("cat/foo.txt", "dog/foo.txt"), 0); assert_eq!( count_shared_steps("foo/bar/baz/lorem.txt", "foo/bar/ipsum/dolar.txt"), 2 ); } }