Skip to content

Commit 71ea2e5

Browse files
committed
fix(package): detect dirtiness for symlinks to submodule
If a there is a symlink into a git repository/submodule, when checking its git status with the wrong outer repo, we'll get an NotFound error, as the object doesn't belong to the outer repository. This kind of error blocked the entire `cargo package` operation. This fix additionally discovers the nearest Git repository, and then checks status with that, assuming the repo is the parent of the source file of the symlink. This is a best effort solution, so if the check fails we ignore.
1 parent d760263 commit 71ea2e5

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

src/cargo/ops/cargo_package/vcs.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,28 @@ fn dirty_files_outside_pkg_root(
274274
dirty_files.insert(workdir.join(rel_path));
275275
}
276276
Err(e) => {
277+
if e.code() == git2::ErrorCode::NotFound {
278+
// Object not found means this file might be inside a subrepo/submodule.
279+
// Let's check its status from that repo.
280+
let abs_path = workdir.join(&rel_path);
281+
if let Ok(repo) = git2::Repository::discover(&abs_path) {
282+
let is_dirty = if repo.workdir() == Some(workdir) {
283+
false
284+
} else if let Ok(path) =
285+
paths::strip_prefix_canonical(&abs_path, repo.workdir().unwrap())
286+
{
287+
repo.status_file(&path) != Ok(git2::Status::CURRENT)
288+
} else {
289+
false
290+
};
291+
if is_dirty {
292+
dirty_files.insert(abs_path);
293+
}
294+
}
295+
}
296+
277297
// Dirtiness check for symlinks is mostly informational.
278-
// And changes in submodule would fail git-status as well (see #15384).
279-
// To avoid adding complicated logic to handle that,
298+
// To avoid adding more complicated logic,
280299
// for now we ignore the status check failure.
281300
debug!(
282301
"failed to get status from file `{}` in git repo at `{}`: {e}",

tests/testsuite/package.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1463,13 +1463,16 @@ fn dirty_file_outside_pkg_root_inside_submodule() {
14631463
p.symlink("submodule/file.txt", "isengard/src/file.txt");
14641464
git::add(&repo);
14651465
git::commit(&repo);
1466-
// This dirtyness should be detected in the future.
14671466
p.change_file("submodule/file.txt", "changed");
14681467

14691468
p.cargo("package --workspace --no-verify")
1469+
.with_status(101)
14701470
.with_stderr_data(str![[r#"
1471-
[PACKAGING] isengard v0.0.0 ([ROOT]/foo/isengard)
1472-
[PACKAGED] 6 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
1471+
[ERROR] 1 files in the working directory contain changes that were not yet committed into git:
1472+
1473+
submodule/file.txt
1474+
1475+
to proceed despite this and include the uncommitted changes, pass the `--allow-dirty` flag
14731476
14741477
"#]])
14751478
.run();

0 commit comments

Comments
 (0)