Skip to content

Add --reinstall argument to the install option #4981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/bin/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct Options {
flag_root: Option<String>,
flag_list: bool,
flag_force: bool,
flag_reinstall: bool,
flag_frozen: bool,
flag_locked: bool,

Expand Down Expand Up @@ -55,6 +56,7 @@ Specifying what crate to install:
Build and install options:
-h, --help Print this message
-j N, --jobs N Number of parallel jobs, defaults to # of CPUs
-r, --reinstall Reinstall the package
-f, --force Force overwriting existing crates or binaries
--features FEATURES Space-separated list of features to activate
--all-features Build all available features
Expand Down Expand Up @@ -93,8 +95,9 @@ one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.
enables overwriting existing binaries. Thus you can install new crate with
overwriting old one with `cargo install --force <crate>`. However, if you want
just to reinstall the crate, you `cargo install --reinstall <crate>`.

As a special convenience, omitting the <crate> specification entirely will
install the crate in the current directory. That is, `install` is equivalent to
Expand Down Expand Up @@ -169,7 +172,7 @@ pub fn execute(options: Options, config: &mut Config) -> CliResult {
if options.flag_list {
ops::install_list(root, config)?;
} else {
ops::install(root, krates, &source, vers, &compile_opts, options.flag_force)?;
ops::install(root, krates, &source, vers, &compile_opts, options.flag_force, options.flag_reinstall)?;
}
Ok(())
}
24 changes: 17 additions & 7 deletions src/cargo/ops/cargo_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use util::{Config, internal};
use util::{Filesystem, FileLock};
use util::errors::{CargoResult, CargoResultExt};

type Duplicates = BTreeMap<String, Option<PackageId>>;

#[derive(Deserialize, Serialize)]
#[serde(untagged)]
enum CrateListing {
Expand Down Expand Up @@ -57,13 +59,14 @@ pub fn install(root: Option<&str>,
source_id: &SourceId,
vers: Option<&str>,
opts: &ops::CompileOptions,
force: bool) -> CargoResult<()> {
force: bool,
reinstall: bool) -> CargoResult<()> {
let root = resolve_root(root, opts.config)?;
let map = SourceConfigMap::new(opts.config)?;

let (installed_anything, scheduled_error) = if krates.len() <= 1 {
install_one(&root, &map, krates.into_iter().next(), source_id, vers, opts,
force, true)?;
force, reinstall, true)?;
(true, false)
} else {
let mut succeeded = vec![];
Expand All @@ -73,7 +76,7 @@ pub fn install(root: Option<&str>,
let root = root.clone();
let map = map.clone();
match install_one(&root, &map, Some(krate), source_id, vers,
opts, force, first) {
opts, force, reinstall, first) {
Ok(()) => succeeded.push(krate),
Err(e) => {
::handle_error(e, &mut opts.config.shell());
Expand Down Expand Up @@ -127,6 +130,7 @@ fn install_one(root: &Filesystem,
vers: Option<&str>,
opts: &ops::CompileOptions,
force: bool,
reinstall: bool,
is_first_install: bool) -> CargoResult<()> {

let config = opts.config;
Expand Down Expand Up @@ -179,7 +183,11 @@ fn install_one(root: &Filesystem,
};
let pkg = ws.current()?;

config.shell().status("Installing", pkg)?;
if reinstall {
uninstall_one(root.to_owned(), pkg.name(), &Vec::default(), config)?;
}

config.shell().status("Checking", pkg)?;

// Preflight checks to check up front whether we'll overwrite something.
// We have to check this again afterwards, but may as well avoid building
Expand All @@ -191,6 +199,8 @@ fn install_one(root: &Filesystem,
check_overwrites(&dst, pkg, &opts.filter, &list, force)?;
}

config.shell().status("Installing", pkg)?;

let compile = ops::compile_ws(&ws,
Some(source),
opts,
Expand Down Expand Up @@ -452,7 +462,7 @@ fn check_overwrites(dst: &Path,
pkg: &Package,
filter: &ops::CompileFilter,
prev: &CrateListingV1,
force: bool) -> CargoResult<BTreeMap<String, Option<PackageId>>> {
force: bool) -> CargoResult<Duplicates> {
// If explicit --bin or --example flags were passed then those'll
// get checked during cargo_compile, we only care about the "build
// everything" case here
Expand Down Expand Up @@ -480,7 +490,7 @@ fn check_overwrites(dst: &Path,
fn find_duplicates(dst: &Path,
pkg: &Package,
filter: &ops::CompileFilter,
prev: &CrateListingV1) -> BTreeMap<String, Option<PackageId>> {
prev: &CrateListingV1) -> Duplicates {
let check = |name: String| {
// Need to provide type, works around Rust Issue #93349
let name = format!("{}{}", name, env::consts::EXE_SUFFIX);
Expand Down Expand Up @@ -513,7 +523,7 @@ fn find_duplicates(dst: &Path,

all_bins.iter().chain(all_examples.iter())
.filter_map(|t| check(t.clone()))
.collect::<BTreeMap<String, Option<PackageId>>>()
.collect::<Duplicates>()
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/cargotest/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,7 @@ fn substitute_macros(input: &str) -> String {
("[UPLOADING]", " Uploading"),
("[VERIFYING]", " Verifying"),
("[ARCHIVING]", " Archiving"),
("[CHECKING]", " Checking"),
("[INSTALLING]", " Installing"),
("[REPLACING]", " Replacing"),
("[UNPACKING]", " Unpacking"),
Expand Down
9 changes: 6 additions & 3 deletions tests/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ fn simple_install() {

assert_that(cargo_process().arg("install").arg("bar"),
execs().with_status(0).with_stderr(
" Installing bar v0.1.0
" Checking bar v0.1.0
Installing bar v0.1.0
Compiling foo v0.1.0
Compiling bar v0.1.0
Finished release [optimized] target(s) in [..] secs
Expand Down Expand Up @@ -191,7 +192,8 @@ fn simple_install_fail() {

assert_that(cargo_process().arg("install").arg("bar"),
execs().with_status(101).with_stderr(
" Installing bar v0.1.0
" Checking bar v0.1.0
Installing bar v0.1.0
error: failed to compile `bar v0.1.0`, intermediate artifacts can be found at `[..]`

Caused by:
Expand Down Expand Up @@ -240,7 +242,8 @@ fn install_without_feature_dep() {

assert_that(cargo_process().arg("install").arg("bar"),
execs().with_status(0).with_stderr(
" Installing bar v0.1.0
" Checking bar v0.1.0
Installing bar v0.1.0
Compiling foo v0.1.0
Compiling bar v0.1.0
Finished release [optimized] target(s) in [..] secs
Expand Down
65 changes: 61 additions & 4 deletions tests/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ fn simple() {
execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `[..]`
[DOWNLOADING] foo v0.0.1 (registry [..])
[CHECKING] foo v0.0.1
[INSTALLING] foo v0.0.1
[COMPILING] foo v0.0.1
[FINISHED] release [optimized] target(s) in [..]
Expand All @@ -63,11 +64,13 @@ fn multiple_pkgs() {
execs().with_status(101).with_stderr(&format!("\
[UPDATING] registry `[..]`
[DOWNLOADING] foo v0.0.1 (registry `file://[..]`)
[CHECKING] foo v0.0.1
[INSTALLING] foo v0.0.1
[COMPILING] foo v0.0.1
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo[..]
[DOWNLOADING] bar v0.0.2 (registry `file://[..]`)
[CHECKING] bar v0.0.2
[INSTALLING] bar v0.0.2
[COMPILING] bar v0.0.2
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -102,6 +105,7 @@ fn pick_max_version() {
execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `[..]`
[DOWNLOADING] foo v0.0.2 (registry [..])
[CHECKING] foo v0.0.2
[INSTALLING] foo v0.0.2
[COMPILING] foo v0.0.2
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -212,7 +216,7 @@ fn install_path() {
assert_that(cargo_home(), has_installed_exe("foo"));
assert_that(cargo_process("install").arg("--path").arg(".").cwd(p.root()),
execs().with_status(101).with_stderr("\
[INSTALLING] foo v0.1.0 [..]
[CHECKING] foo v0.1.0 [..]
[ERROR] binary `foo[..]` already exists in destination as part of `foo v0.1.0 [..]`
Add --force to overwrite
"));
Expand Down Expand Up @@ -378,7 +382,7 @@ fn no_binaries() {

assert_that(cargo_process("install").arg("--path").arg(p.root()).arg("foo"),
execs().with_status(101).with_stderr("\
[INSTALLING] foo [..]
[CHECKING] foo [..]
[ERROR] specified package has no binaries
"));
}
Expand Down Expand Up @@ -419,13 +423,60 @@ fn install_twice() {
execs().with_status(0));
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(101).with_stderr("\
[INSTALLING] foo v0.1.0 [..]
[CHECKING] foo v0.1.0 ([..])
[ERROR] binary `foo-bin1[..]` already exists in destination as part of `foo v0.1.0 ([..])`
binary `foo-bin2[..]` already exists in destination as part of `foo v0.1.0 ([..])`
Add --force to overwrite
"));
}

#[test]
fn install_reinstall() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.1.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();

assert_that(cargo_process("install").arg("--path").arg("--reinstall").arg(p.root()),
execs().with_status(101));

assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0));

let p = project("foo2")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.2.0"
authors = []
"#)
.file("src/main.rs", "fn main() {}")
.build();

assert_that(cargo_process("install").arg("--reinstall").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr(&format!("\
[REMOVING] [..]
[CHECKING] foo v0.2.0 ([..])
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}[..]bin[..]foo[..]
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
",
home = cargo_home().display())));

assert_that(cargo_process("install").arg("--list"),
execs().with_status(0).with_stdout("\
foo v0.2.0 ([..]):
foo[..]
"));
}

#[test]
fn install_force() {
let p = project("foo")
Expand Down Expand Up @@ -453,6 +504,7 @@ fn install_force() {

assert_that(cargo_process("install").arg("--force").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr(&format!("\
[CHECKING] foo v0.2.0 ([..])
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -497,6 +549,7 @@ fn install_force_partial_overlap() {

assert_that(cargo_process("install").arg("--force").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr(&format!("\
[CHECKING] foo v0.2.0 ([..])
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -549,6 +602,7 @@ fn install_force_bin() {
.arg("--path")
.arg(p.root()),
execs().with_status(0).with_stderr(&format!("\
[CHECKING] foo v0.2.0 ([..])
[INSTALLING] foo v0.2.0 ([..])
[COMPILING] foo v0.2.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -606,6 +660,7 @@ fn git_repo() {
assert_that(cargo_process("install").arg("--locked").arg("--git").arg(p.url().to_string()),
execs().with_status(0).with_stderr(&format!("\
[UPDATING] git repository `[..]`
[CHECKING] foo v0.1.0 ([..])
[INSTALLING] foo v0.1.0 ([..])
[COMPILING] foo v0.1.0 ([..])
[FINISHED] release [optimized] target(s) in [..]
Expand Down Expand Up @@ -776,7 +831,9 @@ fn do_not_rebuilds_on_local_install() {
assert_that(p.cargo("build").arg("--release"),
execs().with_status(0));
assert_that(cargo_process("install").arg("--path").arg(p.root()),
execs().with_status(0).with_stderr("[INSTALLING] [..]
execs().with_status(0).with_stderr("\
[CHECKING] [..]
[INSTALLING] [..]
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] [..]
warning: be sure to add `[..]` to your PATH to be able to run the installed binaries
Expand Down
5 changes: 5 additions & 0 deletions tests/required-features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ fn install_default_features() {

assert_that(p.cargo("install").arg("--no-default-features"),
execs().with_status(101).with_stderr(format!("\
[CHECKING] foo v0.0.1 ([..])
[INSTALLING] foo v0.0.1 ([..])
[FINISHED] release [optimized] target(s) in [..]
[ERROR] no binaries are available for install using the selected features
Expand All @@ -566,6 +567,7 @@ fn install_default_features() {

assert_that(p.cargo("install").arg("--bin=foo").arg("--no-default-features"),
execs().with_status(101).with_stderr(format!("\
[CHECKING] foo v0.0.1 ([..])
[INSTALLING] foo v0.0.1 ([..])
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be found at \
`[..]target`
Expand All @@ -584,6 +586,7 @@ Consider enabling them by passing e.g. `--features=\"a\"`

assert_that(p.cargo("install").arg("--example=foo").arg("--no-default-features"),
execs().with_status(101).with_stderr(format!("\
[CHECKING] foo v0.0.1 ([..])
[INSTALLING] foo v0.0.1 ([..])
[ERROR] failed to compile `foo v0.0.1 ([..])`, intermediate artifacts can be found at \
`[..]target`
Expand Down Expand Up @@ -666,6 +669,7 @@ fn install_multiple_required_features() {

assert_that(p.cargo("install").arg("--no-default-features"),
execs().with_status(101).with_stderr("\
[CHECKING] foo v0.0.1 ([..])
[INSTALLING] foo v0.0.1 ([..])
[FINISHED] release [optimized] target(s) in [..]
[ERROR] no binaries are available for install using the selected features
Expand Down Expand Up @@ -871,6 +875,7 @@ Consider enabling them by passing e.g. `--features=\"bar/a\"`
// install
assert_that(p.cargo("install"),
execs().with_status(101).with_stderr(format!("\
[CHECKING] foo v0.0.1 ([..])
[INSTALLING] foo v0.0.1 ([..])
[FINISHED] release [optimized] target(s) in [..]
[ERROR] no binaries are available for install using the selected features
Expand Down