@@ -5,7 +5,8 @@ use std::{env, fs};
5
5
6
6
use crate :: core:: compiler:: { CompileKind , DefaultExecutor , Executor , Freshness , UnitOutput } ;
7
7
use crate :: core:: { Dependency , Edition , Package , PackageId , Source , SourceId , Workspace } ;
8
- use crate :: ops:: common_for_install_and_uninstall:: * ;
8
+ use crate :: ops:: CompileFilter ;
9
+ use crate :: ops:: { common_for_install_and_uninstall:: * , FilterRule } ;
9
10
use crate :: sources:: { GitSource , PathSource , SourceConfigMap } ;
10
11
use crate :: util:: errors:: CargoResult ;
11
12
use crate :: util:: { Config , Filesystem , Rustc , ToSemver , VersionReqExt } ;
@@ -272,7 +273,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
272
273
Ok ( duplicates)
273
274
}
274
275
275
- fn install_one ( mut self ) -> CargoResult < ( ) > {
276
+ fn install_one ( mut self ) -> CargoResult < bool > {
276
277
self . config . shell ( ) . status ( "Installing" , & self . pkg ) ?;
277
278
278
279
let dst = self . root . join ( "bin" ) . into_path_unlocked ( ) ;
@@ -322,7 +323,41 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
322
323
} )
323
324
. collect :: < CargoResult < _ > > ( ) ?;
324
325
if binaries. is_empty ( ) {
325
- bail ! ( "no binaries are available for install using the selected features" ) ;
326
+ // Cargo already warns the user if they use a target specifier that matches nothing,
327
+ // but we want to error if the user asked for a _particular_ binary to be installed,
328
+ // and we didn't end up installing it.
329
+ //
330
+ // NOTE: This _should_ be impossible to hit since --bin=does_not_exist will fail on
331
+ // target selection, and --bin=requires_a without --features=a will fail with "target
332
+ // .. requires the features ..". But rather than assume that's the case, we define the
333
+ // behavior for this fallback case as well.
334
+ if matches ! (
335
+ self . opts. filter,
336
+ CompileFilter :: Only {
337
+ bins: FilterRule :: Just ( ..) ,
338
+ ..
339
+ }
340
+ ) {
341
+ bail ! ( "no binaries are available for install using the selected features" ) ;
342
+ }
343
+
344
+ // If the user did not specify a filter and there _are_ binaries available, but none
345
+ // were selected given the current set of features, let the user know.
346
+ if matches ! (
347
+ self . opts. filter,
348
+ CompileFilter :: Default { .. }
349
+ | CompileFilter :: Only {
350
+ bins: FilterRule :: All ,
351
+ ..
352
+ }
353
+ ) && self . pkg . targets ( ) . iter ( ) . any ( |t| t. is_bin ( ) )
354
+ {
355
+ self . config
356
+ . shell ( )
357
+ . warn ( "none of the package's binaries are available for install using the selected features" ) ?;
358
+ }
359
+
360
+ return Ok ( false ) ;
326
361
}
327
362
// This is primarily to make testing easier.
328
363
binaries. sort_unstable ( ) ;
@@ -455,7 +490,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
455
490
executables( successful_bins. iter( ) )
456
491
) ,
457
492
) ?;
458
- Ok ( ( ) )
493
+ Ok ( true )
459
494
} else {
460
495
if !to_install. is_empty ( ) {
461
496
self . config . shell ( ) . status (
@@ -481,7 +516,7 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
481
516
) ,
482
517
) ?;
483
518
}
484
- Ok ( ( ) )
519
+ Ok ( true )
485
520
}
486
521
}
487
522
@@ -545,10 +580,11 @@ pub fn install(
545
580
no_track,
546
581
true ,
547
582
) ?;
583
+ let mut installed_anything = true ;
548
584
if let Some ( installable_pkg) = installable_pkg {
549
- installable_pkg. install_one ( ) ?;
585
+ installed_anything = installable_pkg. install_one ( ) ?;
550
586
}
551
- ( true , false )
587
+ ( installed_anything , false )
552
588
} else {
553
589
let mut succeeded = vec ! [ ] ;
554
590
let mut failed = vec ! [ ] ;
@@ -601,8 +637,10 @@ pub fn install(
601
637
602
638
for ( krate, result) in install_results {
603
639
match result {
604
- Ok ( ( ) ) => {
605
- succeeded. push ( krate) ;
640
+ Ok ( installed) => {
641
+ if installed {
642
+ succeeded. push ( krate) ;
643
+ }
606
644
}
607
645
Err ( e) => {
608
646
crate :: display_error ( & e, & mut config. shell ( ) ) ;
0 commit comments