diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index f8041be552a..64e0fdd73e1 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::fmt::{self, Debug, Formatter}; use std::fs; use std::path::{Path, PathBuf}; @@ -261,19 +262,36 @@ impl<'cfg> PathSource<'cfg> { opts.pathspec(suffix); } let statuses = repo.statuses(Some(&mut opts))?; - let untracked = statuses.iter().filter_map(|entry| match entry.status() { - // Don't include Cargo.lock if it is untracked. Packaging will - // generate a new one as needed. - git2::Status::WT_NEW if entry.path() != Some("Cargo.lock") => { - Some((join(root, entry.path_bytes()), None)) - } - _ => None, - }); + let mut skip_paths = HashSet::new(); + let untracked: Vec<_> = statuses + .iter() + .filter_map(|entry| { + match entry.status() { + // Don't include Cargo.lock if it is untracked. Packaging will + // generate a new one as needed. + git2::Status::WT_NEW if entry.path() != Some("Cargo.lock") => { + Some(Ok((join(root, entry.path_bytes()), None))) + } + git2::Status::WT_DELETED => { + let path = match join(root, entry.path_bytes()) { + Ok(p) => p, + Err(e) => return Some(Err(e)), + }; + skip_paths.insert(path); + None + } + _ => None, + } + }) + .collect::>()?; let mut subpackages_found = Vec::new(); for (file_path, is_dir) in index_files.chain(untracked) { let file_path = file_path?; + if skip_paths.contains(&file_path) { + continue; + } // Filter out files blatantly outside this package. This is helped a // bit above via the `pathspec` function call, but we need to filter diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index f217245729d..b9d1e06cec1 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -2071,3 +2071,37 @@ fn package_with_resolver_and_metadata() { p.cargo("package").run(); } + +#[cargo_test] +fn deleted_git_working_tree() { + // When deleting a file, but not staged, cargo should ignore the file. + let (p, repo) = git::new_repo("foo", |p| { + p.file("src/lib.rs", "").file("src/main.rs", "fn main() {}") + }); + p.root().join("src/lib.rs").rm_rf(); + p.cargo("package --allow-dirty --list") + .with_stdout( + "\ +Cargo.lock +Cargo.toml +Cargo.toml.orig +src/main.rs +", + ) + .run(); + p.cargo("package --allow-dirty").run(); + let mut index = t!(repo.index()); + t!(index.remove(Path::new("src/lib.rs"), 0)); + t!(index.write()); + p.cargo("package --allow-dirty --list") + .with_stdout( + "\ +Cargo.lock +Cargo.toml +Cargo.toml.orig +src/main.rs +", + ) + .run(); + p.cargo("package --allow-dirty").run(); +}