1717//! should catch the majority of "broken link" cases.
1818
1919use std:: cell:: { Cell , RefCell } ;
20+ use std:: collections:: hash_map:: Entry ;
2021use std:: collections:: { HashMap , HashSet } ;
2122use std:: fs;
2223use std:: io:: ErrorKind ;
24+ use std:: iter:: once;
2325use std:: path:: { Component , Path , PathBuf } ;
2426use std:: rc:: Rc ;
2527use std:: time:: Instant ;
@@ -114,13 +116,19 @@ macro_rules! t {
114116#[ derive( Parser ) ]
115117struct Cli {
116118 docs : PathBuf ,
119+ #[ clap( long) ]
120+ link_targets_dir : Vec < PathBuf > ,
117121}
118122
119123fn main ( ) {
120124 let mut cli = Cli :: parse ( ) ;
121125 cli. docs = cli. docs . canonicalize ( ) . unwrap ( ) ;
122126
123- let mut checker = Checker { root : cli. docs . clone ( ) , cache : HashMap :: new ( ) } ;
127+ let mut checker = Checker {
128+ root : cli. docs . clone ( ) ,
129+ link_targets_dirs : cli. link_targets_dir ,
130+ cache : HashMap :: new ( ) ,
131+ } ;
124132 let mut report = Report {
125133 errors : 0 ,
126134 start : Instant :: now ( ) ,
@@ -142,6 +150,7 @@ fn main() {
142150
143151struct Checker {
144152 root : PathBuf ,
153+ link_targets_dirs : Vec < PathBuf > ,
145154 cache : Cache ,
146155}
147156
@@ -434,15 +443,23 @@ impl Checker {
434443 let pretty_path =
435444 file. strip_prefix ( & self . root ) . unwrap_or ( file) . to_str ( ) . unwrap ( ) . to_string ( ) ;
436445
437- let entry =
438- self . cache . entry ( pretty_path. clone ( ) ) . or_insert_with ( || match fs:: metadata ( file) {
446+ for base in once ( & self . root ) . chain ( self . link_targets_dirs . iter ( ) ) {
447+ let entry = self . cache . entry ( pretty_path. clone ( ) ) ;
448+ if let Entry :: Occupied ( e) = & entry
449+ && !matches ! ( e. get( ) , FileEntry :: Missing )
450+ {
451+ break ;
452+ }
453+
454+ let file = base. join ( & pretty_path) ;
455+ entry. insert_entry ( match fs:: metadata ( & file) {
439456 Ok ( metadata) if metadata. is_dir ( ) => FileEntry :: Dir ,
440457 Ok ( _) => {
441458 if file. extension ( ) . and_then ( |s| s. to_str ( ) ) != Some ( "html" ) {
442459 FileEntry :: OtherFile
443460 } else {
444461 report. html_files += 1 ;
445- load_html_file ( file, report)
462+ load_html_file ( & file, report)
446463 }
447464 }
448465 Err ( e) if e. kind ( ) == ErrorKind :: NotFound => FileEntry :: Missing ,
@@ -458,6 +475,9 @@ impl Checker {
458475 panic ! ( "unexpected read error for {}: {}" , file. display( ) , e) ;
459476 }
460477 } ) ;
478+ }
479+
480+ let entry = self . cache . get ( & pretty_path) . unwrap ( ) ;
461481 ( pretty_path, entry)
462482 }
463483}
0 commit comments