Skip to content

Commit

Permalink
Make "cargo uninstall" uninstall the cwd bins
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Aug 23, 2018
1 parent c0ec76f commit 8921abd
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 19 deletions.
63 changes: 44 additions & 19 deletions src/cargo/ops/cargo_install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,27 +171,16 @@ fn install_one(
&mut |git| git.read_packages(),
)?
} else if source_id.is_path() {
let path = source_id
.url()
.to_file_path()
.map_err(|()| format_err!("path sources must have a valid path"))?;
let mut src = PathSource::new(&path, source_id, config);
let mut src = path_source(source_id, config)?;
src.update().chain_err(|| {
format_err!(
"`{}` is not a crate root; specify a crate to \
install from crates.io, or use --path or --git to \
specify an alternate source",
path.display()
src.path().display()
)
})?;
select_pkg(
PathSource::new(&path, source_id, config),
krate,
vers,
config,
is_first_install,
&mut |path| path.read_packages(),
)?
select_pkg(src, krate, vers, config, false, &mut |path| path.read_packages())?
} else {
select_pkg(
map.load(source_id)?,
Expand Down Expand Up @@ -418,6 +407,14 @@ fn install_one(
Ok(())
}

fn path_source<'a>(source_id: &SourceId, config: &'a Config) -> CargoResult<PathSource<'a>> {
let path = source_id
.url()
.to_file_path()
.map_err(|()| format_err!("path sources must have a valid path"))?;
Ok(PathSource::new(&path, source_id, config))
}

fn select_pkg<'a, T>(
mut source: T,
name: Option<&str>,
Expand Down Expand Up @@ -719,6 +716,9 @@ pub fn uninstall(
let scheduled_error = if specs.len() == 1 {
uninstall_one(&root, specs[0], bins, config)?;
false
} else if specs.len() == 0 {
uninstall_cwd(&root, bins, config)?;
false
} else {
let mut succeeded = vec![];
let mut failed = vec![];
Expand Down Expand Up @@ -768,13 +768,38 @@ pub fn uninstall_one(
config: &Config,
) -> CargoResult<()> {
let crate_metadata = metadata(config, root)?;
let mut metadata = read_crate_list(&crate_metadata)?;
let metadata = read_crate_list(&crate_metadata)?;
let pkgid = PackageIdSpec::query_str(spec, metadata.v1.keys())?.clone();
uninstall_pkgid(crate_metadata, metadata, &pkgid, bins, config)
}

fn uninstall_cwd(
root: &Filesystem,
bins: &[String],
config: &Config,
) -> CargoResult<()> {
let crate_metadata = metadata(config, root)?;
let metadata = read_crate_list(&crate_metadata)?;
let source_id = SourceId::for_path(config.cwd())?;
let src = path_source(&source_id, config)?;
let (pkg, _source) =
select_pkg(src, None, None, config, true, &mut |path| path.read_packages())?;
let pkgid = pkg.package_id();
uninstall_pkgid(crate_metadata, metadata, pkgid, bins, config)
}

fn uninstall_pkgid(
crate_metadata: FileLock,
mut metadata: CrateListingV1,
pkgid: &PackageId,
bins: &[String],
config: &Config,
) -> CargoResult<()> {
let mut to_remove = Vec::new();
{
let result = PackageIdSpec::query_str(spec, metadata.v1.keys())?.clone();
let mut installed = match metadata.v1.entry(result.clone()) {
let mut installed = match metadata.v1.entry(pkgid.clone()) {
Entry::Occupied(e) => e,
Entry::Vacant(..) => panic!("entry not found: {}", result),
Entry::Vacant(..) => bail!("package `{}` is not installed", pkgid),
};
let dst = crate_metadata.parent().join("bin");
for bin in installed.get() {
Expand All @@ -799,7 +824,7 @@ pub fn uninstall_one(

for bin in bins.iter() {
if !installed.get().contains(bin) {
bail!("binary `{}` not installed as part of `{}`", bin, result)
bail!("binary `{}` not installed as part of `{}`", bin, pkgid)
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,10 @@ impl<'cfg> PathSource<'cfg> {
trace!("last modified file {}: {}", self.path.display(), max);
Ok((max, max_path))
}

pub fn path(&self) -> &Path {
&self.path
}
}

impl<'cfg> Debug for PathSource<'cfg> {
Expand Down
53 changes: 53 additions & 0 deletions tests/testsuite/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,59 @@ fn installs_from_cwd_with_2018_warnings() {
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
}

#[test]
fn uninstall_cwd() {
let p = project().file("src/main.rs", "fn main() {}").build();
assert_that(
p.cargo("install --path ."),
execs().with_stderr(&format!("\
[INSTALLING] foo v0.0.1 ({url})
[COMPILING] foo v0.0.1 ({url})
[FINISHED] release [optimized] target(s) in [..]
[INSTALLING] {home}/bin/foo[EXE]
warning: be sure to add `{home}/bin` to your PATH to be able to run the installed binaries",
home = cargo_home().display(),
url = p.url(),
)),
);
assert_that(cargo_home(), has_installed_exe("foo"));

assert_that(
p.cargo("uninstall"),
execs().with_stdout("").with_stderr(&format!("\
[REMOVING] {home}/bin/foo[EXE]",
home = cargo_home().display()
)),
);
assert_that(cargo_home(), is_not(has_installed_exe("foo")));
}

#[test]
fn uninstall_cwd_not_installed() {
let p = project().file("src/main.rs", "fn main() {}").build();
assert_that(
p.cargo("uninstall"),
execs().with_status(101).with_stdout("").with_stderr(format!("\
error: package `foo v0.0.1 ({url})` is not installed",
url = p.url(),
)),
);
}

#[test]
fn uninstall_cwd_no_project() {
assert_that(
cargo_process("uninstall"),
execs().with_status(101).with_stdout("").with_stderr(format!("\
[ERROR] failed to read `{root}/Cargo.toml`
Caused by:
No such file or directory (os error 2)",
root = paths::root().display(),
)),
);
}

#[test]
fn do_not_rebuilds_on_local_install() {
let p = project()
Expand Down

0 comments on commit 8921abd

Please sign in to comment.