Skip to content

Commit 897605a

Browse files
committed
Fix built html saved outside build directory
The fix reconstructs the directory tree inside the build path so links still work the same.
1 parent 6bf7fad commit 897605a

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

crates/mdbook-html/src/html_handlebars/hbs_renderer.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use mdbook_core::utils::fs;
1212
use mdbook_renderer::{RenderContext, Renderer};
1313
use serde_json::json;
1414
use std::collections::{BTreeMap, HashMap};
15-
use std::path::{Path, PathBuf};
15+
use std::iter::{repeat, zip};
16+
use std::path::{Component, Path, PathBuf};
1617
use tracing::error;
1718
use tracing::{debug, info, trace, warn};
1819

@@ -119,8 +120,30 @@ impl HtmlHandlebars {
119120
debug!("Render template");
120121
let rendered = ctx.handlebars.render("index", &ctx.data)?;
121122

123+
// Calculate an output path that's contained in the specified destination
124+
// This is required to be able to reference files in the parent directory
125+
// without putting the HTML files there
126+
let out_path = ctx.destination.join(
127+
&filepath
128+
.parent()
129+
.context("filepath points to a directory")?,
130+
);
131+
fs::create_dir_all(&out_path).context("could not create output directories")?;
132+
let fixed_path: PathBuf = zip(
133+
ctx.destination
134+
.components()
135+
// padding destination because it's always shorter
136+
.chain(repeat(Component::CurDir)),
137+
std::fs::canonicalize(&out_path)?.components(),
138+
)
139+
.skip_while(|(out, canonicalized)| out == canonicalized)
140+
.map(|(_, canonicalized)| canonicalized)
141+
.collect();
142+
let out_path = ctx
143+
.destination
144+
.join(fixed_path)
145+
.join(filepath.file_name().context("filepath points to parent")?);
122146
// Write to file
123-
let out_path = ctx.destination.join(filepath);
124147
fs::write(&out_path, rendered)?;
125148

126149
if prev_ch.is_none() {

tests/testsuite/rendering.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,18 @@ HTML tags must be closed before exiting a markdown element.
304304
str![[r##"<h3 id="option"><a class="header" href="#option">Option<t></t></a></h3>"##]],
305305
);
306306
}
307+
308+
#[test]
309+
fn including_files_from_parent_directories_works() {
310+
let mut test =
311+
BookTest::from_dir("rendering/including_files_from_parent_directories_works/parent");
312+
test.check_main_file(
313+
"book/index.html",
314+
str![[r##"<h1 id="test"><a class="header" href="#test">Test!</a></h1>"##]],
315+
);
316+
317+
assert!(
318+
!std::fs::exists(test.dir.join("../test.html")).unwrap(),
319+
"test.html was rendered outside build directory"
320+
);
321+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[test](../test.md)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Test!

0 commit comments

Comments
 (0)