@@ -5,11 +5,13 @@ mod crate_spec;
5
5
use std:: collections:: BTreeMap ;
6
6
use std:: collections:: BTreeSet ;
7
7
use std:: collections:: VecDeque ;
8
+ use std:: fmt:: Write ;
8
9
use std:: path:: Path ;
9
10
10
11
use anyhow:: Context as _;
11
12
use cargo_util:: paths;
12
13
use indexmap:: IndexSet ;
14
+ use itertools:: Itertools ;
13
15
use termcolor:: Color :: Green ;
14
16
use termcolor:: Color :: Red ;
15
17
use termcolor:: ColorSpec ;
@@ -99,7 +101,7 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
99
101
table_option. map_or ( true , |table| is_sorted ( table. iter ( ) . map ( |( name, _) | name) ) )
100
102
} ) ;
101
103
for dep in deps {
102
- print_msg ( & mut options. config . shell ( ) , & dep, & dep_table) ?;
104
+ print_action_msg ( & mut options. config . shell ( ) , & dep, & dep_table) ?;
103
105
if let Some ( Source :: Path ( src) ) = dep. source ( ) {
104
106
if src. path == manifest. path . parent ( ) . unwrap_or_else ( || Path :: new ( "" ) ) {
105
107
anyhow:: bail!(
@@ -124,11 +126,63 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
124
126
inherited_features. iter ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
125
127
unknown_features. extend ( inherited_features. difference ( & available_features) . copied ( ) ) ;
126
128
}
129
+
127
130
unknown_features. sort ( ) ;
131
+
128
132
if !unknown_features. is_empty ( ) {
129
- anyhow:: bail!( "unrecognized features: {unknown_features:?}" ) ;
133
+ let ( mut activated, mut deactivated) = dep. features ( ) ;
134
+ // Since the unknown features have been added to the DependencyUI we need to remove
135
+ // them to present the "correct" features that can be specified for the crate.
136
+ deactivated. retain ( |f| !unknown_features. contains ( f) ) ;
137
+ activated. retain ( |f| !unknown_features. contains ( f) ) ;
138
+
139
+ let mut message = format ! (
140
+ "unrecognized feature{} for crate {}: {}\n " ,
141
+ if unknown_features. len( ) == 1 { "" } else { "s" } ,
142
+ dep. name,
143
+ unknown_features. iter( ) . format( ", " ) ,
144
+ ) ;
145
+ if activated. is_empty ( ) && deactivated. is_empty ( ) {
146
+ write ! ( message, "no features available for crate {}" , dep. name) ?;
147
+ } else {
148
+ if !deactivated. is_empty ( ) {
149
+ writeln ! (
150
+ message,
151
+ "disabled features:\n {}" ,
152
+ deactivated
153
+ . iter( )
154
+ . map( |s| s. to_string( ) )
155
+ . coalesce( |x, y| if x. len( ) + y. len( ) < 78 {
156
+ Ok ( format!( "{x}, {y}" ) )
157
+ } else {
158
+ Err ( ( x, y) )
159
+ } )
160
+ . into_iter( )
161
+ . format( "\n " )
162
+ ) ?
163
+ }
164
+ if !activated. is_empty ( ) {
165
+ writeln ! (
166
+ message,
167
+ "enabled features:\n {}" ,
168
+ activated
169
+ . iter( )
170
+ . map( |s| s. to_string( ) )
171
+ . coalesce( |x, y| if x. len( ) + y. len( ) < 78 {
172
+ Ok ( format!( "{x}, {y}" ) )
173
+ } else {
174
+ Err ( ( x, y) )
175
+ } )
176
+ . into_iter( )
177
+ . format( "\n " )
178
+ ) ?
179
+ }
180
+ }
181
+ anyhow:: bail!( message. trim( ) . to_owned( ) ) ;
130
182
}
131
183
184
+ print_dep_table_msg ( & mut options. config . shell ( ) , & dep) ?;
185
+
132
186
manifest. insert_into_table ( & dep_table, & dep) ?;
133
187
manifest. gc_dep ( dep. toml_key ( ) ) ;
134
188
}
@@ -634,6 +688,42 @@ impl DependencyUI {
634
688
} )
635
689
. collect ( ) ;
636
690
}
691
+
692
+ fn features ( & self ) -> ( IndexSet < & str > , IndexSet < & str > ) {
693
+ let mut activated: IndexSet < _ > =
694
+ self . features . iter ( ) . flatten ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
695
+ if self . default_features ( ) . unwrap_or ( true ) {
696
+ activated. insert ( "default" ) ;
697
+ }
698
+ activated. extend ( self . inherited_features . iter ( ) . flatten ( ) . map ( |s| s. as_str ( ) ) ) ;
699
+ let mut walk: VecDeque < _ > = activated. iter ( ) . cloned ( ) . collect ( ) ;
700
+ while let Some ( next) = walk. pop_front ( ) {
701
+ walk. extend (
702
+ self . available_features
703
+ . get ( next)
704
+ . into_iter ( )
705
+ . flatten ( )
706
+ . map ( |s| s. as_str ( ) ) ,
707
+ ) ;
708
+ activated. extend (
709
+ self . available_features
710
+ . get ( next)
711
+ . into_iter ( )
712
+ . flatten ( )
713
+ . map ( |s| s. as_str ( ) ) ,
714
+ ) ;
715
+ }
716
+ activated. remove ( "default" ) ;
717
+ activated. sort ( ) ;
718
+ let mut deactivated = self
719
+ . available_features
720
+ . keys ( )
721
+ . filter ( |f| !activated. contains ( f. as_str ( ) ) && * f != "default" )
722
+ . map ( |f| f. as_str ( ) )
723
+ . collect :: < IndexSet < _ > > ( ) ;
724
+ deactivated. sort ( ) ;
725
+ ( activated, deactivated)
726
+ }
637
727
}
638
728
639
729
impl < ' s > From < & ' s Summary > for DependencyUI {
@@ -697,9 +787,7 @@ fn populate_available_features(
697
787
Ok ( dependency)
698
788
}
699
789
700
- fn print_msg ( shell : & mut Shell , dep : & DependencyUI , section : & [ String ] ) -> CargoResult < ( ) > {
701
- use std:: fmt:: Write ;
702
-
790
+ fn print_action_msg ( shell : & mut Shell , dep : & DependencyUI , section : & [ String ] ) -> CargoResult < ( ) > {
703
791
if matches ! ( shell. verbosity( ) , crate :: core:: shell:: Verbosity :: Quiet ) {
704
792
return Ok ( ( ) ) ;
705
793
}
@@ -736,38 +824,14 @@ fn print_msg(shell: &mut Shell, dep: &DependencyUI, section: &[String]) -> Cargo
736
824
} ;
737
825
write ! ( message, " {section}" ) ?;
738
826
write ! ( message, "." ) ?;
739
- shell. status ( "Adding" , message) ?;
740
-
741
- let mut activated: IndexSet < _ > = dep. features . iter ( ) . flatten ( ) . map ( |s| s. as_str ( ) ) . collect ( ) ;
742
- if dep. default_features ( ) . unwrap_or ( true ) {
743
- activated. insert ( "default" ) ;
744
- }
745
- activated. extend ( dep. inherited_features . iter ( ) . flatten ( ) . map ( |s| s. as_str ( ) ) ) ;
746
- let mut walk: VecDeque < _ > = activated. iter ( ) . cloned ( ) . collect ( ) ;
747
- while let Some ( next) = walk. pop_front ( ) {
748
- walk. extend (
749
- dep. available_features
750
- . get ( next)
751
- . into_iter ( )
752
- . flatten ( )
753
- . map ( |s| s. as_str ( ) ) ,
754
- ) ;
755
- activated. extend (
756
- dep. available_features
757
- . get ( next)
758
- . into_iter ( )
759
- . flatten ( )
760
- . map ( |s| s. as_str ( ) ) ,
761
- ) ;
827
+ shell. status ( "Adding" , message)
828
+ }
829
+
830
+ fn print_dep_table_msg ( shell : & mut Shell , dep : & DependencyUI ) -> CargoResult < ( ) > {
831
+ if matches ! ( shell. verbosity( ) , crate :: core:: shell:: Verbosity :: Quiet ) {
832
+ return Ok ( ( ) ) ;
762
833
}
763
- activated. remove ( "default" ) ;
764
- activated. sort ( ) ;
765
- let mut deactivated = dep
766
- . available_features
767
- . keys ( )
768
- . filter ( |f| !activated. contains ( f. as_str ( ) ) && * f != "default" )
769
- . collect :: < Vec < _ > > ( ) ;
770
- deactivated. sort ( ) ;
834
+ let ( activated, deactivated) = dep. features ( ) ;
771
835
if !activated. is_empty ( ) || !deactivated. is_empty ( ) {
772
836
let prefix = format ! ( "{:>13}" , " " ) ;
773
837
let suffix = if let Some ( version) = & dep. available_version {
0 commit comments