@@ -5,7 +5,7 @@ use clap::Parser;
55use collector:: category:: Category ;
66use database:: { ArtifactId , Commit } ;
77use log:: debug;
8- use std:: collections:: HashSet ;
8+ use std:: collections:: HashMap ;
99use std:: fs;
1010use std:: fs:: File ;
1111use std:: io:: BufWriter ;
@@ -331,26 +331,37 @@ fn get_benchmarks(
331331 paths. push ( ( path, name) ) ;
332332 }
333333
334- let mut includes = include. map ( |list| list. split ( ',' ) . collect :: < HashSet < & str > > ( ) ) ;
335- let mut excludes = exclude. map ( |list| list. split ( ',' ) . collect :: < HashSet < & str > > ( ) ) ;
334+ // For each --include/--exclude entry, we count how many times it's used,
335+ // to enable `check_for_unused` below.
336+ fn to_hashmap ( xyz : Option < & str > ) -> Option < HashMap < & str , usize > > {
337+ xyz. map ( |list| {
338+ list. split ( ',' )
339+ . map ( |x| ( x, 0 ) )
340+ . collect :: < HashMap < & str , usize > > ( )
341+ } )
342+ }
343+
344+ let mut includes = to_hashmap ( include) ;
345+ let mut excludes = to_hashmap ( exclude) ;
336346
337347 for ( path, name) in paths {
338348 let mut skip = false ;
339- if let Some ( includes ) = includes . as_mut ( ) {
340- if !includes . remove ( name . as_str ( ) ) {
341- debug ! (
342- "benchmark {} - not named by --include argument, skipping" ,
343- name
344- ) ;
345- skip = true ;
349+
350+ let name_matches = | prefixes : & mut HashMap < & str , usize > | {
351+ for ( prefix , n ) in prefixes . iter_mut ( ) {
352+ if name . as_str ( ) . starts_with ( prefix ) {
353+ * n += 1 ;
354+ return true ;
355+ }
346356 }
347- }
357+ false
358+ } ;
348359
360+ if let Some ( includes) = includes. as_mut ( ) {
361+ skip |= !name_matches ( includes) ;
362+ }
349363 if let Some ( excludes) = excludes. as_mut ( ) {
350- if excludes. remove ( name. as_str ( ) ) {
351- debug ! ( "benchmark {} - named by --exclude argument, skipping" , name) ;
352- skip = true ;
353- }
364+ skip |= name_matches ( excludes) ;
354365 }
355366 if skip {
356367 continue ;
@@ -360,22 +371,26 @@ fn get_benchmarks(
360371 benchmarks. push ( Benchmark :: new ( name, path) ?) ;
361372 }
362373
363- if let Some ( includes ) = includes {
364- if !includes . is_empty ( ) {
365- bail ! (
366- "Warning: one or more invalid --include entries: {:?}" ,
367- includes
368- ) ;
369- }
370- }
371- if let Some ( excludes ) = excludes {
372- if !excludes . is_empty ( ) {
373- bail ! (
374- "Warning: one or more invalid --exclude entries: {:?}" ,
375- excludes
376- ) ;
374+ // All prefixes must be used at least once. This is to catch typos.
375+ let check_for_unused = |option , prefixes : Option < HashMap < & str , usize > > | {
376+ if let Some ( prefixes ) = prefixes {
377+ let unused : Vec < _ > = prefixes
378+ . into_iter ( )
379+ . filter_map ( | ( i , n ) | if n == 0 { Some ( i ) } else { None } )
380+ . collect ( ) ;
381+ if !unused . is_empty ( ) {
382+ bail ! (
383+ "Warning: one or more unused --{} entries: {:?}" ,
384+ option ,
385+ unused
386+ ) ;
387+ }
377388 }
378- }
389+ Ok ( ( ) )
390+ } ;
391+
392+ check_for_unused ( "include" , includes) ?;
393+ check_for_unused ( "exclude" , excludes) ?;
379394
380395 benchmarks. sort_by_key ( |benchmark| benchmark. name . clone ( ) ) ;
381396
@@ -729,11 +744,11 @@ struct LocalOptions {
729744 #[ clap( long, parse( from_os_str) ) ]
730745 cargo : Option < PathBuf > ,
731746
732- /// Exclude all benchmarks in this comma-separated list
747+ /// Exclude all benchmarks matching a prefix in this comma-separated list
733748 #[ clap( long) ]
734749 exclude : Option < String > ,
735750
736- /// Include only benchmarks in this comma-separated list
751+ /// Include only benchmarks matching a prefix in this comma-separated list
737752 #[ clap( long) ]
738753 include : Option < String > ,
739754
0 commit comments