@@ -287,6 +287,7 @@ pub fn compute_stamp_hash(config: &Config) -> String {
287
287
format ! ( "{:x}" , hash. finish( ) )
288
288
}
289
289
290
+ #[ derive( Copy , Clone ) ]
290
291
struct TestCx < ' test > {
291
292
config : & ' test Config ,
292
293
props : & ' test TestProps ,
@@ -1729,7 +1730,7 @@ impl<'test> TestCx<'test> {
1729
1730
self . config . target . contains ( "vxworks" ) && !self . is_vxworks_pure_static ( )
1730
1731
}
1731
1732
1732
- fn compose_and_run_compiler ( & self , mut rustc : Command , input : Option < String > ) -> ProcRes {
1733
+ fn build_all_auxiliary ( & self , rustc : & mut Command ) -> PathBuf {
1733
1734
let aux_dir = self . aux_output_dir_name ( ) ;
1734
1735
1735
1736
if !self . props . aux_builds . is_empty ( ) {
@@ -1748,6 +1749,11 @@ impl<'test> TestCx<'test> {
1748
1749
rustc. arg ( "--extern" ) . arg ( format ! ( "{}={}/{}" , aux_name, aux_dir. display( ) , lib_name) ) ;
1749
1750
}
1750
1751
1752
+ aux_dir
1753
+ }
1754
+
1755
+ fn compose_and_run_compiler ( & self , mut rustc : Command , input : Option < String > ) -> ProcRes {
1756
+ let aux_dir = self . build_all_auxiliary ( & mut rustc) ;
1751
1757
self . props . unset_rustc_env . clone ( ) . iter ( ) . fold ( & mut rustc, |rustc, v| rustc. env_remove ( v) ) ;
1752
1758
rustc. envs ( self . props . rustc_env . clone ( ) ) ;
1753
1759
self . compose_and_run (
@@ -2209,7 +2215,17 @@ impl<'test> TestCx<'test> {
2209
2215
2210
2216
fn fatal_proc_rec ( & self , err : & str , proc_res : & ProcRes ) -> ! {
2211
2217
self . error ( err) ;
2212
- proc_res. fatal ( None ) ;
2218
+ proc_res. fatal ( None , || ( ) ) ;
2219
+ }
2220
+
2221
+ fn fatal_proc_rec_with_ctx (
2222
+ & self ,
2223
+ err : & str ,
2224
+ proc_res : & ProcRes ,
2225
+ on_failure : impl FnOnce ( Self ) ,
2226
+ ) -> ! {
2227
+ self . error ( err) ;
2228
+ proc_res. fatal ( None , || on_failure ( * self ) ) ;
2213
2229
}
2214
2230
2215
2231
// codegen tests (using FileCheck)
@@ -2326,15 +2342,131 @@ impl<'test> TestCx<'test> {
2326
2342
let res = self . cmd2procres (
2327
2343
Command :: new ( & self . config . docck_python )
2328
2344
. arg ( root. join ( "src/etc/htmldocck.py" ) )
2329
- . arg ( out_dir)
2345
+ . arg ( & out_dir)
2330
2346
. arg ( & self . testpaths . file ) ,
2331
2347
) ;
2332
2348
if !res. status . success ( ) {
2333
- self . fatal_proc_rec ( "htmldocck failed!" , & res) ;
2349
+ self . fatal_proc_rec_with_ctx ( "htmldocck failed!" , & res, |mut this| {
2350
+ this. compare_to_default_rustdoc ( & out_dir)
2351
+ } ) ;
2334
2352
}
2335
2353
}
2336
2354
}
2337
2355
2356
+ fn compare_to_default_rustdoc ( & mut self , out_dir : & Path ) {
2357
+ println ! ( "info: generating a diff against nightly rustdoc" ) ;
2358
+
2359
+ let suffix =
2360
+ self . safe_revision ( ) . map_or ( "nightly" . into ( ) , |path| path. to_owned ( ) + "-nightly" ) ;
2361
+ let compare_dir = output_base_dir ( self . config , self . testpaths , Some ( & suffix) ) ;
2362
+ // Don't give an error if the directory didn't already exist
2363
+ let _ = fs:: remove_dir_all ( & compare_dir) ;
2364
+ create_dir_all ( & compare_dir) . unwrap ( ) ;
2365
+
2366
+ // We need to create a new struct for the lifetimes on `config` to work.
2367
+ let new_rustdoc = TestCx {
2368
+ config : & Config {
2369
+ // FIXME: use beta or a user-specified rustdoc instead of
2370
+ // hardcoding the default toolchain
2371
+ rustdoc_path : Some ( "rustdoc" . into ( ) ) ,
2372
+ // Needed for building auxiliary docs below
2373
+ rustc_path : "rustc" . into ( ) ,
2374
+ ..self . config . clone ( )
2375
+ } ,
2376
+ ..* self
2377
+ } ;
2378
+
2379
+ let output_file = TargetLocation :: ThisDirectory ( new_rustdoc. aux_output_dir_name ( ) ) ;
2380
+ let mut rustc = new_rustdoc. make_compile_args (
2381
+ & new_rustdoc. testpaths . file ,
2382
+ output_file,
2383
+ EmitMetadata :: No ,
2384
+ AllowUnused :: Yes ,
2385
+ ) ;
2386
+ rustc. arg ( "-L" ) . arg ( & new_rustdoc. aux_output_dir_name ( ) ) ;
2387
+ new_rustdoc. build_all_auxiliary ( & mut rustc) ;
2388
+
2389
+ let proc_res = new_rustdoc. document ( & compare_dir) ;
2390
+ if !proc_res. status . success ( ) {
2391
+ proc_res. fatal ( Some ( "failed to run nightly rustdoc" ) , || ( ) ) ;
2392
+ }
2393
+
2394
+ #[ rustfmt:: skip]
2395
+ let tidy_args = [
2396
+ "--indent" , "yes" ,
2397
+ "--indent-spaces" , "2" ,
2398
+ "--wrap" , "0" ,
2399
+ "--show-warnings" , "no" ,
2400
+ "--markup" , "yes" ,
2401
+ "--quiet" , "yes" ,
2402
+ "-modify" ,
2403
+ ] ;
2404
+ let tidy_dir = |dir| {
2405
+ let tidy = |file : & _ | {
2406
+ Command :: new ( "tidy" )
2407
+ . args ( & tidy_args)
2408
+ . arg ( file)
2409
+ . spawn ( )
2410
+ . unwrap_or_else ( |err| {
2411
+ self . fatal ( & format ! ( "failed to run tidy - is it installed? - {}" , err) )
2412
+ } )
2413
+ . wait ( )
2414
+ . unwrap ( )
2415
+ } ;
2416
+ for entry in walkdir:: WalkDir :: new ( dir) {
2417
+ let entry = entry. expect ( "failed to read file" ) ;
2418
+ if entry. file_type ( ) . is_file ( )
2419
+ && entry. path ( ) . extension ( ) . and_then ( |p| p. to_str ( ) ) == Some ( "html" . into ( ) )
2420
+ {
2421
+ tidy ( entry. path ( ) ) ;
2422
+ }
2423
+ }
2424
+ } ;
2425
+ tidy_dir ( out_dir) ;
2426
+ tidy_dir ( & compare_dir) ;
2427
+
2428
+ let pager = {
2429
+ let output = Command :: new ( "git" ) . args ( & [ "config" , "--get" , "core.pager" ] ) . output ( ) . ok ( ) ;
2430
+ output. and_then ( |out| {
2431
+ if out. status . success ( ) {
2432
+ Some ( String :: from_utf8 ( out. stdout ) . expect ( "invalid UTF8 in git pager" ) )
2433
+ } else {
2434
+ None
2435
+ }
2436
+ } )
2437
+ } ;
2438
+ let mut diff = Command :: new ( "diff" ) ;
2439
+ diff. args ( & [ "-u" , "-r" ] ) . args ( & [ out_dir, & compare_dir] ) ;
2440
+
2441
+ let output = if let Some ( pager) = pager {
2442
+ let diff_pid = diff. stdout ( Stdio :: piped ( ) ) . spawn ( ) . expect ( "failed to run `diff`" ) ;
2443
+ let pager = pager. trim ( ) ;
2444
+ if self . config . verbose {
2445
+ eprintln ! ( "using pager {}" , pager) ;
2446
+ }
2447
+ let output = Command :: new ( pager)
2448
+ // disable paging; we want this to be non-interactive
2449
+ . env ( "PAGER" , "" )
2450
+ . stdin ( diff_pid. stdout . unwrap ( ) )
2451
+ // Capture output and print it explicitly so it will in turn be
2452
+ // captured by libtest.
2453
+ . output ( )
2454
+ . unwrap ( ) ;
2455
+ assert ! ( output. status. success( ) ) ;
2456
+ output
2457
+ } else {
2458
+ eprintln ! ( "warning: no pager configured, falling back to `diff --color`" ) ;
2459
+ eprintln ! (
2460
+ "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`"
2461
+ ) ;
2462
+ let output = diff. arg ( "--color" ) . output ( ) . unwrap ( ) ;
2463
+ assert ! ( output. status. success( ) || output. status. code( ) == Some ( 1 ) ) ;
2464
+ output
2465
+ } ;
2466
+ println ! ( "{}" , String :: from_utf8_lossy( & output. stdout) ) ;
2467
+ eprintln ! ( "{}" , String :: from_utf8_lossy( & output. stderr) ) ;
2468
+ }
2469
+
2338
2470
fn get_lines < P : AsRef < Path > > (
2339
2471
& self ,
2340
2472
path : & P ,
@@ -3591,7 +3723,7 @@ pub struct ProcRes {
3591
3723
}
3592
3724
3593
3725
impl ProcRes {
3594
- pub fn fatal ( & self , err : Option < & str > ) -> ! {
3726
+ pub fn fatal ( & self , err : Option < & str > , on_failure : impl FnOnce ( ) ) -> ! {
3595
3727
if let Some ( e) = err {
3596
3728
println ! ( "\n error: {}" , e) ;
3597
3729
}
@@ -3613,6 +3745,7 @@ impl ProcRes {
3613
3745
json:: extract_rendered( & self . stdout) ,
3614
3746
json:: extract_rendered( & self . stderr) ,
3615
3747
) ;
3748
+ on_failure ( ) ;
3616
3749
// Use resume_unwind instead of panic!() to prevent a panic message + backtrace from
3617
3750
// compiletest, which is unnecessary noise.
3618
3751
std:: panic:: resume_unwind ( Box :: new ( ( ) ) ) ;
0 commit comments