@@ -37,6 +37,8 @@ pub(crate) struct Args {
3737 pub ( crate ) each_feature : bool ,
3838 /// --feature-powerset
3939 pub ( crate ) feature_powerset : bool ,
40+ /// --must-have-and-exclude-feature <FEATURE>
41+ pub ( crate ) must_have_and_exclude_feature : Option < String > ,
4042 /// --no-dev-deps
4143 pub ( crate ) no_dev_deps : bool ,
4244 /// --remove-dev-deps
@@ -152,6 +154,7 @@ impl Args {
152154 let mut remove_dev_deps = false ;
153155 let mut each_feature = false ;
154156 let mut feature_powerset = false ;
157+ let mut must_have_and_exclude_feature = None ;
155158 let mut no_private = false ;
156159 let mut ignore_private = false ;
157160 let mut ignore_unknown_features = false ;
@@ -303,6 +306,9 @@ impl Args {
303306 Long ( "remove-dev-deps" ) => parse_flag ! ( remove_dev_deps) ,
304307 Long ( "each-feature" ) => parse_flag ! ( each_feature) ,
305308 Long ( "feature-powerset" ) => parse_flag ! ( feature_powerset) ,
309+ Long ( "must-have-and-exclude-feature" ) => {
310+ parse_opt ! ( must_have_and_exclude_feature, false ) ;
311+ }
306312 Long ( "at-least-one-of" ) => at_least_one_of. push ( parser. value ( ) ?. parse ( ) ?) ,
307313 Long ( "no-private" ) => parse_flag ! ( no_private) ,
308314 Long ( "ignore-private" ) => parse_flag ! ( ignore_private) ,
@@ -492,6 +498,8 @@ impl Args {
492498 conflicts ( "--all-features" , "--each-feature" ) ?;
493499 } else if feature_powerset {
494500 conflicts ( "--all-features" , "--feature-powerset" ) ?;
501+ } else if must_have_and_exclude_feature. is_some ( ) {
502+ conflicts ( "--all-features" , "--must-have-and-exclude-feature" ) ?;
495503 }
496504 }
497505 if no_default_features {
@@ -520,6 +528,21 @@ impl Args {
520528 }
521529 }
522530
531+ if let Some ( f) = must_have_and_exclude_feature. as_ref ( ) {
532+ if features. contains ( f) {
533+ bail ! ( "feature `{f}` specified by both --must-have-and-exclude-feature and --features" ) ;
534+ }
535+ if optional_deps. as_ref ( ) . is_some_and ( |d| d. contains ( f) ) {
536+ bail ! ( "feature `{f}` specified by both --must-have-and-exclude-feature and --optional-deps" ) ;
537+ }
538+ if group_features. iter ( ) . any ( |v| v. matches ( f) ) {
539+ bail ! ( "feature `{f}` specified by both --must-have-and-exclude-feature and --group-features" ) ;
540+ }
541+ if include_features. contains ( f) {
542+ bail ! ( "feature `{f}` specified by both --must-have-and-exclude-feature and --include-features" ) ;
543+ }
544+ }
545+
523546 if subcommand. is_none ( ) {
524547 if cargo_args. iter ( ) . any ( |a| a == "--list" ) {
525548 cmd ! ( cargo, "--list" ) . run ( ) ?;
@@ -591,7 +614,8 @@ impl Args {
591614 exclude_no_default_features |= !include_features. is_empty ( ) ;
592615 exclude_all_features |= !include_features. is_empty ( )
593616 || !exclude_features. is_empty ( )
594- || !mutually_exclusive_features. is_empty ( ) ;
617+ || !mutually_exclusive_features. is_empty ( )
618+ || must_have_and_exclude_feature. is_some ( ) ;
595619 exclude_features. extend_from_slice ( & features) ;
596620
597621 term:: verbose:: set ( verbose != 0 ) ;
@@ -613,6 +637,7 @@ impl Args {
613637 workspace,
614638 each_feature,
615639 feature_powerset,
640+ must_have_and_exclude_feature,
616641 no_dev_deps,
617642 remove_dev_deps,
618643 no_private,
@@ -758,6 +783,11 @@ const HELP: &[HelpText<'_>] = &[
758783 --feature-powerset flag.",
759784 ] ,
760785 ) ,
786+ ( "" , "--must-have-and-exclude-feature" , "<FEATURE>" , "Require the specified feature to be present but excluded" , & [
787+ "Exclude the specified feature and all other features which depend on it." ,
788+ "Exclude packages which don't have the specified feature." ,
789+ "This is useful for doing no_std testing with --must-have-and-exclude-feature std." ,
790+ ] ) ,
761791 ( "" , "--no-dev-deps" , "" , "Perform without dev-dependencies" , & [
762792 "Note that this flag removes dev-dependencies from real `Cargo.toml` while cargo-hack is \
763793 running and restores it when finished.",
0 commit comments