From 7030f68f98052214ff925698fb9f051b09abc4b0 Mon Sep 17 00:00:00 2001 From: d1t2 Date: Sun, 21 Jul 2024 12:16:01 +0800 Subject: [PATCH] fix: image not found in README.md while mdbook build Since commit 1ca2a860, all assets embed to top directory in book and could not be found on reading. Another issue is not handle README.md path correctly while applying mdbook link preprocessor. This commit fixes above issues and update an integration test to ensure assets is embedded to expected path. svg image is from https://commons.wikimedia.org/wiki/File:Epub_logo.svg --- src/errors.rs | 5 ++++- src/resources/asset.rs | 17 +++++++------- src/resources/resource.rs | 12 +++++++--- tests/dummy/src/02_advanced/Epub_logo.svg | 9 ++++++++ tests/dummy/src/02_advanced/README.md | 5 +++++ tests/dummy/src/SUMMARY.md | 4 ++++ tests/integration_tests.rs | 27 ++++++++++++++++++++--- 7 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 tests/dummy/src/02_advanced/Epub_logo.svg create mode 100644 tests/dummy/src/02_advanced/README.md diff --git a/src/errors.rs b/src/errors.rs index 97972ffab..f741cd862 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,5 @@ -use thiserror::Error; use std::path::PathBuf; +use thiserror::Error; #[derive(Error, Debug)] pub enum Error { @@ -42,6 +42,9 @@ pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), + #[error(transparent)] + AssetOutsideSrcDir(#[from] std::path::StripPrefixError), + #[error(transparent)] Book(#[from] mdbook::errors::Error), #[error(transparent)] diff --git a/src/resources/asset.rs b/src/resources/asset.rs index 57e9c5879..7f981860d 100644 --- a/src/resources/asset.rs +++ b/src/resources/asset.rs @@ -82,14 +82,7 @@ impl Asset { return Err(Error::AssetFile(absolute_location)); } // Use filename as embedded file path with content from absolute_location. - let binding = utils::normalize_path(Path::new(link)); - debug!("Extracting file name from = {:?}, binding = '{binding:?}'", &full_filename.display()); - let filename = if cfg!(target_os = "windows") { - binding.as_os_str().to_os_string() - .into_string().expect("Error getting filename for Local Asset").replace('\\', "/") - } else { - String::from(binding.as_path().to_str().unwrap()) - }; + let filename = full_filename.strip_prefix(src_dir)?; let asset = Asset::new( filename, @@ -112,7 +105,13 @@ impl Asset { pub(crate) fn compute_asset_path_by_src_and_link(link: &str, chapter_dir: &PathBuf) -> PathBuf { let mut reassigned_asset_root: PathBuf = PathBuf::from(chapter_dir); let link_string = String::from(link); - // if chapter is a MD file, remove if from path + // mdbook built-in link preprocessor have `README.md` renamed and `index.md` is not exist + // strip the converted filename in the path + if chapter_dir.ends_with("index.md") && !chapter_dir.exists() { + debug!("It seems a `README.md` chapter, adjust the chapter root."); + reassigned_asset_root.pop(); + } + // if chapter is a MD file or not exist, remove if from path if chapter_dir.is_file() { reassigned_asset_root.pop(); } diff --git a/src/resources/resource.rs b/src/resources/resource.rs index 9735fcaaf..743f97fc4 100644 --- a/src/resources/resource.rs +++ b/src/resources/resource.rs @@ -48,9 +48,15 @@ pub(crate) fn find(ctx: &RenderContext) -> Result, Error> continue; } for link in find_assets_in_markdown(&ch.content)? { - let asset = match Url::parse(&link) { - Ok(url) => Asset::from_url(url, &ctx.destination), - Err(_) => Asset::from_local(&link, &src_dir, ch.path.as_ref().unwrap()), + let asset = if let Ok(url) = Url::parse(&link) { + Asset::from_url(url, &ctx.destination) + } else { + let result = Asset::from_local(&link, &src_dir, ch.path.as_ref().unwrap()); + if let Err(Error::AssetOutsideSrcDir(_)) = result { + warn!("Asset '{link}' is outside source dir '{src_dir:?}' and ignored"); + continue; + }; + result }?; // that is CORRECT generation way diff --git a/tests/dummy/src/02_advanced/Epub_logo.svg b/tests/dummy/src/02_advanced/Epub_logo.svg new file mode 100644 index 000000000..d53b002d8 --- /dev/null +++ b/tests/dummy/src/02_advanced/Epub_logo.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/tests/dummy/src/02_advanced/README.md b/tests/dummy/src/02_advanced/README.md new file mode 100644 index 000000000..5d5a566b8 --- /dev/null +++ b/tests/dummy/src/02_advanced/README.md @@ -0,0 +1,5 @@ +# README.md tests + +## image link + +![Awesome image in the same folder](Epub_logo.svg "Awesome") diff --git a/tests/dummy/src/SUMMARY.md b/tests/dummy/src/SUMMARY.md index dd840d0f7..2d62376e5 100644 --- a/tests/dummy/src/SUMMARY.md +++ b/tests/dummy/src/SUMMARY.md @@ -2,3 +2,7 @@ - [Chapter 1](./chapter_1.md) - [Getting started](01_getting_started/02_article.md) + +# Advanced + +- [README.md tests](./02_advanced/README.md) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index dd1283c48..5ebad41e2 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -125,17 +125,38 @@ fn look_for_chapter_1_heading() { assert!(content.contains("

Chapter 1

")); } +#[test] +#[serial] +fn look_for_chapter_2_image_link_in_readme() { + init_logging(); + let mut doc = generate_epub().unwrap(); + + let path = if cfg!(target_os = "linux") { + Path::new("OEBPS").join("02_advanced").join("README.html") // linux + } else { + Path::new("OEBPS/02_advanced/README.html").to_path_buf() // windows with 'forward slash' / + }; + let content = doc.0.get_resource_str_by_path(path).unwrap(); + + assert!(content.contains("