Skip to content

Commit

Permalink
Auto merge of #9645 - ehuss:git-package-wt_deleted, r=alexcrichton
Browse files Browse the repository at this point in the history
Handle git deleted files with dirty worktree.

When listing git files for things like `cargo package`, it was including unstaged deleted files. This is because the file is still in the index, so it was included in the list.  `cargo package --allow-dirty` would then fail with a confusing "file not found" error.

This fixes it by keeping a set of deleted files, and skipping those. This allows `cargo package --allow-dirty` to work.

Closes #9580
  • Loading branch information
bors committed Jul 2, 2021
2 parents b0e2cc5 + 97a1350 commit b747054
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
34 changes: 26 additions & 8 deletions src/cargo/sources/path.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::fmt::{self, Debug, Formatter};
use std::fs;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -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::<CargoResult<_>>()?;

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
Expand Down
34 changes: 34 additions & 0 deletions tests/testsuite/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

0 comments on commit b747054

Please sign in to comment.