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