| 1 | //! Cargo Feature Flags. | 
| 2 |  | 
|---|
| 3 | #[ derive(Default, Clone, Debug, PartialEq, Eq)] | 
|---|
| 4 | #[ cfg_attr(feature = "clap", derive(clap::Args))] | 
|---|
| 5 | #[ non_exhaustive] | 
|---|
| 6 | pub struct Features { | 
|---|
| 7 | #[ cfg_attr(feature = "clap", arg(long))] | 
|---|
| 8 | /// Activate all available features | 
|---|
| 9 | pub all_features: bool, | 
|---|
| 10 | #[ cfg_attr(feature = "clap", arg(long))] | 
|---|
| 11 | /// Do not activate the `default` feature | 
|---|
| 12 | pub no_default_features: bool, | 
|---|
| 13 | #[ cfg_attr(feature = "clap", arg(short = 'F', long, value_delimiter = ' '))] | 
|---|
| 14 | /// Space-separated list of features to activate | 
|---|
| 15 | pub features: Vec<String>, | 
|---|
| 16 | } | 
|---|
| 17 |  | 
|---|
| 18 | #[ cfg(feature = "cargo_metadata")] | 
|---|
| 19 | impl Features { | 
|---|
| 20 | /// Forward these flags to the `cargo_metadata` crate. | 
|---|
| 21 | /// | 
|---|
| 22 | /// Note: Requires the features `cargo_metadata`. | 
|---|
| 23 | pub fn forward_metadata<'m>( | 
|---|
| 24 | &self, | 
|---|
| 25 | meta: &'m mut cargo_metadata::MetadataCommand, | 
|---|
| 26 | ) -> &'m mut cargo_metadata::MetadataCommand { | 
|---|
| 27 | if self.all_features { | 
|---|
| 28 | meta.features(cargo_metadata::CargoOpt::AllFeatures); | 
|---|
| 29 | } | 
|---|
| 30 | if self.no_default_features { | 
|---|
| 31 | meta.features(cargo_metadata::CargoOpt::NoDefaultFeatures); | 
|---|
| 32 | } | 
|---|
| 33 | if !self.features.is_empty() { | 
|---|
| 34 | meta.features(cargo_metadata::CargoOpt::SomeFeatures( | 
|---|
| 35 | self.features.clone(), | 
|---|
| 36 | )); | 
|---|
| 37 | } | 
|---|
| 38 | meta | 
|---|
| 39 | } | 
|---|
| 40 | } | 
|---|
| 41 |  | 
|---|
| 42 | #[ cfg(test)] | 
|---|
| 43 | mod test { | 
|---|
| 44 | use super::*; | 
|---|
| 45 |  | 
|---|
| 46 | #[ test] | 
|---|
| 47 | #[ cfg(feature = "clap")] | 
|---|
| 48 | fn verify_app() { | 
|---|
| 49 | #[ derive(Debug, clap::Parser)] | 
|---|
| 50 | struct Cli { | 
|---|
| 51 | #[command(flatten)] | 
|---|
| 52 | features: Features, | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | use clap::CommandFactory; | 
|---|
| 56 | Cli::command().debug_assert() | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | #[ test] | 
|---|
| 60 | #[ cfg(feature = "clap")] | 
|---|
| 61 | fn parse_multiple_occurrences() { | 
|---|
| 62 | use clap::Parser; | 
|---|
| 63 |  | 
|---|
| 64 | #[ derive(PartialEq, Eq, Debug, Parser)] | 
|---|
| 65 | struct Args { | 
|---|
| 66 | positional: Option<String>, | 
|---|
| 67 | #[command(flatten)] | 
|---|
| 68 | features: Features, | 
|---|
| 69 | } | 
|---|
| 70 |  | 
|---|
| 71 | assert_eq!( | 
|---|
| 72 | Args { | 
|---|
| 73 | positional: None, | 
|---|
| 74 | features: Features { | 
|---|
| 75 | all_features: false, | 
|---|
| 76 | no_default_features: false, | 
|---|
| 77 | features: vec![] | 
|---|
| 78 | } | 
|---|
| 79 | }, | 
|---|
| 80 | Args::parse_from([ "test"]) | 
|---|
| 81 | ); | 
|---|
| 82 | assert_eq!( | 
|---|
| 83 | Args { | 
|---|
| 84 | positional: Some( "foo".to_owned()), | 
|---|
| 85 | features: Features { | 
|---|
| 86 | all_features: false, | 
|---|
| 87 | no_default_features: false, | 
|---|
| 88 | features: vec![] | 
|---|
| 89 | } | 
|---|
| 90 | }, | 
|---|
| 91 | Args::parse_from([ "test", "foo"]) | 
|---|
| 92 | ); | 
|---|
| 93 | assert_eq!( | 
|---|
| 94 | Args { | 
|---|
| 95 | positional: None, | 
|---|
| 96 | features: Features { | 
|---|
| 97 | all_features: false, | 
|---|
| 98 | no_default_features: false, | 
|---|
| 99 | features: vec![ "foo".to_owned()] | 
|---|
| 100 | } | 
|---|
| 101 | }, | 
|---|
| 102 | Args::parse_from([ "test", "--features", "foo"]) | 
|---|
| 103 | ); | 
|---|
| 104 | assert_eq!( | 
|---|
| 105 | Args { | 
|---|
| 106 | positional: None, | 
|---|
| 107 | features: Features { | 
|---|
| 108 | all_features: false, | 
|---|
| 109 | no_default_features: false, | 
|---|
| 110 | features: vec![ "foo".to_owned(), "bar".to_owned()] | 
|---|
| 111 | } | 
|---|
| 112 | }, | 
|---|
| 113 | Args::parse_from([ "test", "--features", "foo bar"]) | 
|---|
| 114 | ); | 
|---|
| 115 | assert_eq!( | 
|---|
| 116 | Args { | 
|---|
| 117 | positional: Some( "baz".to_owned()), | 
|---|
| 118 | features: Features { | 
|---|
| 119 | all_features: false, | 
|---|
| 120 | no_default_features: false, | 
|---|
| 121 | features: vec![ "foo".to_owned(), "bar".to_owned()] | 
|---|
| 122 | } | 
|---|
| 123 | }, | 
|---|
| 124 | Args::parse_from([ "test", "--features", "foo bar", "baz"]) | 
|---|
| 125 | ); | 
|---|
| 126 | assert_eq!( | 
|---|
| 127 | Args { | 
|---|
| 128 | positional: Some( "baz".to_owned()), | 
|---|
| 129 | features: Features { | 
|---|
| 130 | all_features: false, | 
|---|
| 131 | no_default_features: false, | 
|---|
| 132 | features: vec![ "foo".to_owned(), "bar".to_owned()] | 
|---|
| 133 | } | 
|---|
| 134 | }, | 
|---|
| 135 | Args::parse_from([ "test", "--features", "foo", "--features", "bar", "baz"]) | 
|---|
| 136 | ); | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | #[ cfg(feature = "cargo_metadata")] | 
|---|
| 140 | #[ test] | 
|---|
| 141 | fn features_all() { | 
|---|
| 142 | let mut metadata = cargo_metadata::MetadataCommand::new(); | 
|---|
| 143 | metadata.manifest_path( "tests/fixtures/simple/Cargo.toml"); | 
|---|
| 144 |  | 
|---|
| 145 | let features = Features { | 
|---|
| 146 | all_features: true, | 
|---|
| 147 | ..Default::default() | 
|---|
| 148 | }; | 
|---|
| 149 | features.forward_metadata(&mut metadata); | 
|---|
| 150 | metadata.exec().unwrap(); | 
|---|
| 151 | // TODO verify we forwarded correctly. | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | #[ cfg(feature = "cargo_metadata")] | 
|---|
| 155 | #[ test] | 
|---|
| 156 | fn features_none() { | 
|---|
| 157 | let mut metadata = cargo_metadata::MetadataCommand::new(); | 
|---|
| 158 | metadata.manifest_path( "tests/fixtures/simple/Cargo.toml"); | 
|---|
| 159 |  | 
|---|
| 160 | let features = Features { | 
|---|
| 161 | no_default_features: true, | 
|---|
| 162 | ..Default::default() | 
|---|
| 163 | }; | 
|---|
| 164 | features.forward_metadata(&mut metadata); | 
|---|
| 165 | metadata.exec().unwrap(); | 
|---|
| 166 | // TODO verify we forwarded correctly. | 
|---|
| 167 | } | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|