@@ -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,18 @@ 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 ) . unwrap_or_else ( |err| {
529+ panic ! ( "modified_tests got error from dir: {}, error: {}" , config. src_base. display( ) , err)
530+ } ) ;
531+ collect_tests_from_dir (
532+ config,
533+ & config. src_base ,
534+ & PathBuf :: new ( ) ,
535+ & inputs,
536+ tests,
537+ & modified_tests,
538+ )
539+ . unwrap_or_else ( |_| panic ! ( "Could not read tests from {}" , config. src_base. display( ) ) ) ;
526540}
527541
528542/// Returns a stamp constructed from input files common to all test cases.
@@ -561,12 +575,35 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
561575 stamp
562576}
563577
578+ fn modified_tests ( config : & Config , dir : & Path ) -> Result < Vec < PathBuf > , String > {
579+ if !config. only_modified {
580+ return Ok ( vec ! [ ] ) ;
581+ }
582+ let files =
583+ get_git_modified_files ( Some ( dir) , & vec ! [ "rs" , "stderr" , "fixed" ] ) ?. unwrap_or ( vec ! [ ] ) ;
584+ // Add new test cases to the list, it will be convenient in daily development.
585+ let untracked_files = get_git_untracked_files ( None ) ?. unwrap_or ( vec ! [ ] ) ;
586+
587+ let all_paths = [ & files[ ..] , & untracked_files[ ..] ] . concat ( ) ;
588+ let full_paths = {
589+ let mut full_paths: Vec < PathBuf > = all_paths
590+ . into_iter ( )
591+ . map ( |f| fs:: canonicalize ( & f) . unwrap ( ) . with_extension ( "" ) . with_extension ( "rs" ) )
592+ . collect ( ) ;
593+ full_paths. dedup ( ) ;
594+ full_paths. sort_unstable ( ) ;
595+ full_paths
596+ } ;
597+ Ok ( full_paths)
598+ }
599+
564600fn collect_tests_from_dir (
565601 config : & Config ,
566602 dir : & Path ,
567603 relative_dir_path : & Path ,
568604 inputs : & Stamp ,
569605 tests : & mut Vec < test:: TestDescAndFn > ,
606+ modified_tests : & Vec < PathBuf > ,
570607) -> io:: Result < ( ) > {
571608 // Ignore directories that contain a file named `compiletest-ignore-dir`.
572609 if dir. join ( "compiletest-ignore-dir" ) . exists ( ) {
@@ -597,7 +634,7 @@ fn collect_tests_from_dir(
597634 let file = file?;
598635 let file_path = file. path ( ) ;
599636 let file_name = file. file_name ( ) ;
600- if is_test ( & file_name) {
637+ if is_test ( & file_name) && ( !config . only_modified || modified_tests . contains ( & file_path ) ) {
601638 debug ! ( "found test file: {:?}" , file_path. display( ) ) ;
602639 let paths =
603640 TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
@@ -607,7 +644,14 @@ fn collect_tests_from_dir(
607644 let relative_file_path = relative_dir_path. join ( file. file_name ( ) ) ;
608645 if & file_name != "auxiliary" {
609646 debug ! ( "found directory: {:?}" , file_path. display( ) ) ;
610- collect_tests_from_dir ( config, & file_path, & relative_file_path, inputs, tests) ?;
647+ collect_tests_from_dir (
648+ config,
649+ & file_path,
650+ & relative_file_path,
651+ inputs,
652+ tests,
653+ modified_tests,
654+ ) ?;
611655 }
612656 } else {
613657 debug ! ( "found other file/directory: {:?}" , file_path. display( ) ) ;
0 commit comments