@@ -13,6 +13,7 @@ use rustc_middle::ty::TyCtxt;
1313use rustc_session:: Session ;
1414use rustc_span:: source_map:: FileName ;
1515
16+ use std:: cell:: RefCell ;
1617use std:: ffi:: OsStr ;
1718use std:: fs;
1819use std:: path:: { Component , Path , PathBuf } ;
@@ -72,12 +73,22 @@ impl LocalSourcesCollector<'_, '_> {
7273 return ;
7374 }
7475
75- let mut href = String :: new ( ) ;
76- clean_path ( self . src_root , & p, false , |component| {
77- href. push_str ( & component. to_string_lossy ( ) ) ;
78- href. push ( '/' ) ;
79- } ) ;
76+ let href = RefCell :: new ( PathBuf :: new ( ) ) ;
77+ clean_path (
78+ & self . src_root ,
79+ & p,
80+ |component| {
81+ href. borrow_mut ( ) . push ( component) ;
82+ } ,
83+ || {
84+ href. borrow_mut ( ) . pop ( ) ;
85+ } ,
86+ ) ;
8087
88+ let mut href = href. into_inner ( ) . to_string_lossy ( ) . to_string ( ) ;
89+ if let Some ( c) = href. as_bytes ( ) . last ( ) && * c != b'/' {
90+ href. push ( '/' ) ;
91+ }
8192 let mut src_fname = p. file_name ( ) . expect ( "source has no filename" ) . to_os_string ( ) ;
8293 src_fname. push ( ".html" ) ;
8394 href. push_str ( & src_fname. to_string_lossy ( ) ) ;
@@ -180,13 +191,28 @@ impl SourceCollector<'_, '_> {
180191
181192 let shared = Rc :: clone ( & self . cx . shared ) ;
182193 // Create the intermediate directories
183- let mut cur = self . dst . clone ( ) ;
184- let mut root_path = String :: from ( "../../" ) ;
185- clean_path ( & shared. src_root , & p, false , |component| {
186- cur. push ( component) ;
187- root_path. push_str ( "../" ) ;
188- } ) ;
194+ let cur = RefCell :: new ( PathBuf :: new ( ) ) ;
195+ let root_path = RefCell :: new ( PathBuf :: new ( ) ) ;
196+
197+ clean_path (
198+ & shared. src_root ,
199+ & p,
200+ |component| {
201+ cur. borrow_mut ( ) . push ( component) ;
202+ root_path. borrow_mut ( ) . push ( ".." ) ;
203+ } ,
204+ || {
205+ cur. borrow_mut ( ) . pop ( ) ;
206+ root_path. borrow_mut ( ) . pop ( ) ;
207+ } ,
208+ ) ;
189209
210+ let root_path = PathBuf :: from ( "../../" ) . join ( root_path. into_inner ( ) ) ;
211+ let mut root_path = root_path. to_string_lossy ( ) ;
212+ if let Some ( c) = root_path. as_bytes ( ) . last ( ) && * c != b'/' {
213+ root_path += "/" ;
214+ }
215+ let mut cur = self . dst . join ( cur. into_inner ( ) ) ;
190216 shared. ensure_dir ( & cur) ?;
191217
192218 let src_fname = p. file_name ( ) . expect ( "source has no filename" ) . to_os_string ( ) ;
@@ -232,24 +258,26 @@ impl SourceCollector<'_, '_> {
232258/// Takes a path to a source file and cleans the path to it. This canonicalizes
233259/// things like ".." to components which preserve the "top down" hierarchy of a
234260/// static HTML tree. Each component in the cleaned path will be passed as an
235- /// argument to `f`. The very last component of the path (ie the file name) will
236- /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
237- pub ( crate ) fn clean_path < F > ( src_root : & Path , p : & Path , keep_filename : bool , mut f : F )
261+ /// argument to `f`. The very last component of the path (ie the file name) is ignored.
262+ /// If a `..` is encountered, the `parent` closure will be called to allow the callee to
263+ /// handle it.
264+ pub ( crate ) fn clean_path < F , P > ( src_root : & Path , p : & Path , mut f : F , mut parent : P )
238265where
239266 F : FnMut ( & OsStr ) ,
267+ P : FnMut ( ) ,
240268{
241269 // make it relative, if possible
242270 let p = p. strip_prefix ( src_root) . unwrap_or ( p) ;
243271
244272 let mut iter = p. components ( ) . peekable ( ) ;
245273
246274 while let Some ( c) = iter. next ( ) {
247- if !keep_filename && iter. peek ( ) . is_none ( ) {
275+ if iter. peek ( ) . is_none ( ) {
248276 break ;
249277 }
250278
251279 match c {
252- Component :: ParentDir => f ( "up" . as_ref ( ) ) ,
280+ Component :: ParentDir => parent ( ) ,
253281 Component :: Normal ( c) => f ( c) ,
254282 _ => continue ,
255283 }
0 commit comments