@@ -8,15 +8,17 @@ extern crate test;
88use crate :: common:: { expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS } ;
99use crate :: common:: { CompareMode , Config , Debugger , Mode , PassMode , TestPaths } ;
1010use crate :: util:: logv;
11+ use build_helper:: git:: { get_git_modified_files, get_git_untracked_files} ;
12+ use core:: panic;
1113use getopts:: Options ;
1214use lazycell:: LazyCell ;
13- use std:: env;
1415use std:: ffi:: OsString ;
1516use std:: fs;
1617use std:: io:: { self , ErrorKind } ;
1718use std:: path:: { Path , PathBuf } ;
1819use std:: process:: { Command , Stdio } ;
1920use std:: time:: SystemTime ;
21+ use std:: { env, vec} ;
2022use test:: ColorConfig ;
2123use tracing:: * ;
2224use walkdir:: WalkDir ;
@@ -145,9 +147,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
145147 "" ,
146148 "rustfix-coverage" ,
147149 "enable this to generate a Rustfix coverage file, which is saved in \
148- `./<build_base>/rustfix_missing_coverage.txt`",
150+ `./<build_base>/rustfix_missing_coverage.txt`",
149151 )
150152 . optflag ( "" , "force-rerun" , "rerun tests even if the inputs are unchanged" )
153+ . optflag ( "" , "only-modified" , "only run tests that result been modified" )
151154 . optflag ( "h" , "help" , "show this message" )
152155 . reqopt ( "" , "channel" , "current Rust channel" , "CHANNEL" )
153156 . optopt ( "" , "edition" , "default Rust edition" , "EDITION" ) ;
@@ -279,6 +282,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
279282 lldb_python_dir : matches. opt_str ( "lldb-python-dir" ) ,
280283 verbose : matches. opt_present ( "verbose" ) ,
281284 quiet : matches. opt_present ( "quiet" ) ,
285+ only_modified : matches. opt_present ( "only-modified" ) ,
282286 color,
283287 remote_test_client : matches. opt_str ( "remote-test-client" ) . map ( PathBuf :: from) ,
284288 compare_mode : matches. opt_str ( "compare-mode" ) . map ( CompareMode :: parse) ,
@@ -521,8 +525,16 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
521525pub fn make_tests ( config : & Config , tests : & mut Vec < test:: TestDescAndFn > ) {
522526 debug ! ( "making tests from {:?}" , config. src_base. display( ) ) ;
523527 let inputs = common_inputs_stamp ( config) ;
524- collect_tests_from_dir ( config, & config. src_base , & PathBuf :: new ( ) , & inputs, tests)
525- . unwrap_or_else ( |_| panic ! ( "Could not read tests from {}" , config. src_base. display( ) ) ) ;
528+ let modified_tests = modified_tests ( config, & config. src_base ) ;
529+ collect_tests_from_dir (
530+ config,
531+ & config. src_base ,
532+ & PathBuf :: new ( ) ,
533+ & inputs,
534+ tests,
535+ & modified_tests,
536+ )
537+ . unwrap_or_else ( |_| panic ! ( "Could not read tests from {}" , config. src_base. display( ) ) ) ;
526538}
527539
528540/// Returns a stamp constructed from input files common to all test cases.
@@ -561,12 +573,34 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
561573 stamp
562574}
563575
576+ fn modified_tests ( config : & Config , dir : & Path ) -> Vec < PathBuf > {
577+ if !config. only_modified {
578+ return vec ! [ ] ;
579+ }
580+ let Ok ( Some ( files) ) = get_git_modified_files ( Some ( dir) , & vec ! [ "rs" , "stderr" , "fixed" ] ) else { return vec ! [ ] ; } ;
581+ // Add new test cases to the list, it will be convenient in daily development.
582+ let Ok ( Some ( untracked_files) ) = get_git_untracked_files ( None ) else { return vec ! [ ] ; } ;
583+
584+ let all_paths = [ & files[ ..] , & untracked_files[ ..] ] . concat ( ) ;
585+ let full_paths = {
586+ let mut full_paths: Vec < PathBuf > = all_paths
587+ . into_iter ( )
588+ . map ( |f| fs:: canonicalize ( & f) . unwrap ( ) . with_extension ( "" ) . with_extension ( "rs" ) )
589+ . collect ( ) ;
590+ full_paths. dedup ( ) ;
591+ full_paths. sort_unstable ( ) ;
592+ full_paths
593+ } ;
594+ full_paths
595+ }
596+
564597fn collect_tests_from_dir (
565598 config : & Config ,
566599 dir : & Path ,
567600 relative_dir_path : & Path ,
568601 inputs : & Stamp ,
569602 tests : & mut Vec < test:: TestDescAndFn > ,
603+ only_modified : & Vec < PathBuf > ,
570604) -> io:: Result < ( ) > {
571605 // Ignore directories that contain a file named `compiletest-ignore-dir`.
572606 if dir. join ( "compiletest-ignore-dir" ) . exists ( ) {
@@ -597,7 +631,7 @@ fn collect_tests_from_dir(
597631 let file = file?;
598632 let file_path = file. path ( ) ;
599633 let file_name = file. file_name ( ) ;
600- if is_test ( & file_name) {
634+ if is_test ( & file_name) && ( !config . only_modified || only_modified . contains ( & file_path ) ) {
601635 debug ! ( "found test file: {:?}" , file_path. display( ) ) ;
602636 let paths =
603637 TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
@@ -607,7 +641,14 @@ fn collect_tests_from_dir(
607641 let relative_file_path = relative_dir_path. join ( file. file_name ( ) ) ;
608642 if & file_name != "auxiliary" {
609643 debug ! ( "found directory: {:?}" , file_path. display( ) ) ;
610- collect_tests_from_dir ( config, & file_path, & relative_file_path, inputs, tests) ?;
644+ collect_tests_from_dir (
645+ config,
646+ & file_path,
647+ & relative_file_path,
648+ inputs,
649+ tests,
650+ only_modified,
651+ ) ?;
611652 }
612653 } else {
613654 debug ! ( "found other file/directory: {:?}" , file_path. display( ) ) ;
0 commit comments