@@ -7,11 +7,14 @@ use std::path::{Path, PathBuf};
77use std:: process:: Stdio ;
88use std:: str;
99
10+ use cargo_test_support:: basic_manifest;
11+ use cargo_test_support:: paths:: CargoPathExt ;
1012use cargo_test_support:: registry:: Package ;
1113use cargo_test_support:: tools:: echo_subcommand;
1214use cargo_test_support:: {
1315 basic_bin_manifest, cargo_exe, cargo_process, paths, project, project_in_home,
1416} ;
17+ use cargo_util:: paths:: join_paths;
1518
1619fn path ( ) -> Vec < PathBuf > {
1720 env:: split_paths ( & env:: var_os ( "PATH" ) . unwrap_or_default ( ) ) . collect ( )
@@ -341,6 +344,83 @@ fn cargo_subcommand_env() {
341344 . run ( ) ;
342345}
343346
347+ #[ cargo_test]
348+ fn cargo_cmd_bins_vs_explicit_path ( ) {
349+ // Set up `cargo-foo` binary in two places: inside `$HOME/.cargo/bin` and outside of it
350+ //
351+ // Return paths to both places
352+ fn set_up_cargo_foo ( ) -> ( PathBuf , PathBuf ) {
353+ let p = project ( )
354+ . at ( "cargo-foo" )
355+ . file ( "Cargo.toml" , & basic_manifest ( "cargo-foo" , "1.0.0" ) )
356+ . file (
357+ "src/bin/cargo-foo.rs" ,
358+ r#"fn main() { println!("INSIDE"); }"# ,
359+ )
360+ . file (
361+ "src/bin/cargo-foo2.rs" ,
362+ r#"fn main() { println!("OUTSIDE"); }"# ,
363+ )
364+ . build ( ) ;
365+ p. cargo ( "build" ) . run ( ) ;
366+ let cargo_bin_dir = paths:: home ( ) . join ( ".cargo/bin" ) ;
367+ cargo_bin_dir. mkdir_p ( ) ;
368+ let root_bin_dir = paths:: root ( ) . join ( "bin" ) ;
369+ root_bin_dir. mkdir_p ( ) ;
370+ let exe_name = format ! ( "cargo-foo{}" , env:: consts:: EXE_SUFFIX ) ;
371+ fs:: rename ( p. bin ( "cargo-foo" ) , cargo_bin_dir. join ( & exe_name) ) . unwrap ( ) ;
372+ fs:: rename ( p. bin ( "cargo-foo2" ) , root_bin_dir. join ( & exe_name) ) . unwrap ( ) ;
373+
374+ ( root_bin_dir, cargo_bin_dir)
375+ }
376+
377+ let ( outside_dir, inside_dir) = set_up_cargo_foo ( ) ;
378+
379+ // If `$CARGO_HOME/bin` is not in a path, prefer it over anything in `$PATH`.
380+ //
381+ // This is the historical behavior we don't want to break.
382+ cargo_process ( "foo" ) . with_stdout_contains ( "INSIDE" ) . run ( ) ;
383+
384+ // When `$CARGO_HOME/bin` is in the `$PATH`
385+ // use only `$PATH` so the user-defined ordering is respected.
386+ {
387+ cargo_process ( "foo" )
388+ . env (
389+ "PATH" ,
390+ join_paths ( & [ & inside_dir, & outside_dir] , "PATH" ) . unwrap ( ) ,
391+ )
392+ . with_stdout_contains ( "INSIDE" )
393+ . run ( ) ;
394+
395+ cargo_process ( "foo" )
396+ // Note: trailing slash
397+ . env (
398+ "PATH" ,
399+ join_paths ( & [ inside_dir. join ( "" ) , outside_dir. join ( "" ) ] , "PATH" ) . unwrap ( ) ,
400+ )
401+ . with_stdout_contains ( "INSIDE" )
402+ . run ( ) ;
403+
404+ cargo_process ( "foo" )
405+ . env (
406+ "PATH" ,
407+ join_paths ( & [ & outside_dir, & inside_dir] , "PATH" ) . unwrap ( ) ,
408+ )
409+ . with_stdout_contains ( "OUTSIDE" )
410+ . run ( ) ;
411+
412+ cargo_process ( "foo" )
413+ // Note: trailing slash
414+ . env (
415+ "PATH" ,
416+ join_paths ( & [ outside_dir. join ( "" ) , inside_dir. join ( "" ) ] , "PATH" ) . unwrap ( ) ,
417+ )
418+ . with_stdout_contains ( "OUTSIDE" )
419+ . run ( ) ;
420+ }
421+ }
422+
423+ #[ test]
344424#[ cargo_test]
345425fn cargo_subcommand_args ( ) {
346426 let p = echo_subcommand ( ) ;
0 commit comments