diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs index 8702fd99a39..902b1ac5cd2 100644 --- a/src/bin/cargo/commands/install.rs +++ b/src/bin/cargo/commands/install.rs @@ -24,6 +24,13 @@ pub fn cli() -> App { )) .arg_jobs() .arg(opt("force", "Force overwriting existing crates or binaries").short("f")) + .arg( + opt( + "ensure", + "Simply leaves it as-is when you already have a suitable version", + ) + .short("e"), + ) .arg_features() .arg(opt("debug", "Build in debug mode instead of release mode")) .arg_targets_bins_examples( @@ -128,6 +135,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { version, &compile_opts, args.is_present("force"), + args.is_present("ensure"), )?; } Ok(()) diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 4e1036abb52..a994a5e1c48 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -42,6 +42,7 @@ pub fn install( vers: Option<&str>, opts: &ops::CompileOptions<'_>, force: bool, + ensure: bool, ) -> CargoResult<()> { let root = resolve_root(root, opts.config)?; let map = SourceConfigMap::new(opts.config)?; @@ -56,6 +57,7 @@ pub fn install( vers, opts, force, + ensure, true, )?; (true, false) @@ -75,6 +77,7 @@ pub fn install( vers, opts, force, + ensure, first, ) { Ok(()) => succeeded.push(krate), @@ -137,6 +140,7 @@ fn install_one( vers: Option<&str>, opts: &ops::CompileOptions<'_>, force: bool, + ensure: bool, is_first_install: bool, ) -> CargoResult<()> { let config = opts.config; @@ -248,7 +252,7 @@ fn install_one( let metadata = metadata(config, root)?; let list = read_crate_list(&metadata)?; let dst = metadata.parent().join("bin"); - check_overwrites(&dst, pkg, &opts.filter, &list, force)?; + check_overwrites(&dst, pkg, &opts.filter, &list, force, ensure)?; } let exec: Arc = Arc::new(DefaultExecutor); @@ -287,7 +291,7 @@ fn install_one( let metadata = metadata(config, root)?; let mut list = read_crate_list(&metadata)?; let dst = metadata.parent().join("bin"); - let duplicates = check_overwrites(&dst, pkg, &opts.filter, &list, force)?; + let duplicates = check_overwrites(&dst, pkg, &opts.filter, &list, force, ensure)?; fs::create_dir_all(&dst)?; @@ -411,6 +415,7 @@ fn check_overwrites( filter: &ops::CompileFilter, prev: &CrateListingV1, force: bool, + ensure: bool, ) -> CargoResult>> { // If explicit --bin or --example flags were passed then those'll // get checked during cargo_compile, we only care about the "build @@ -433,6 +438,12 @@ fn check_overwrites( } } msg.push_str("Add --force to overwrite"); + + if ensure { + eprintln!("{}", msg); + std::process::exit(0) + }; + Err(failure::format_err!("{}", msg)) } diff --git a/tests/testsuite/install.rs b/tests/testsuite/install.rs index b7955461f68..9302fda44de 100644 --- a/tests/testsuite/install.rs +++ b/tests/testsuite/install.rs @@ -504,6 +504,27 @@ foo v0.2.0 ([..]): .run(); } +#[test] +fn install_ensure() { + let p = project() + .file("src/bin/foo-bin1.rs", "fn main() {}") + .file("src/bin/foo-bin2.rs", "fn main() {}") + .build(); + + cargo_process("install --ensure --path").arg(p.root()).run(); + cargo_process("install --ensure --path") + .arg(p.root()) + .with_stderr( + "\ +[INSTALLING] foo v0.0.1 [..] +binary `foo-bin1[..]` already exists in destination as part of `foo v0.0.1 ([..])` +binary `foo-bin2[..]` already exists in destination as part of `foo v0.0.1 ([..])` +Add --force to overwrite +", + ) + .run(); +} + #[test] fn install_force_partial_overlap() { let p = project()