Skip to content

Commit a4f048b

Browse files
committed
assure repositories are always walked into to avoid .git folders.
With a traditional walk, `.git` will be picked up, and so will be ignored directories. This commit also doesn't give submodules special treatment - instead it just tries to open directories as repositories, or walks them if that fails.
1 parent be78818 commit a4f048b

File tree

2 files changed

+22
-36
lines changed

2 files changed

+22
-36
lines changed

src/cargo/sources/path.rs

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::util::{internal, CargoResult, GlobalContext};
1313
use anyhow::Context as _;
1414
use cargo_util::paths;
1515
use filetime::FileTime;
16-
use gix::bstr::{ByteSlice, ByteVec};
16+
use gix::bstr::ByteVec;
1717
use ignore::gitignore::GitignoreBuilder;
1818
use tracing::{trace, warn};
1919
use walkdir::WalkDir;
@@ -295,7 +295,7 @@ impl<'gctx> PathSource<'gctx> {
295295
}
296296
};
297297
let manifest_path = gix::path::join_bstr_unix_pathsep(
298-
gix::path::into_bstr(repo_relative_path),
298+
gix::path::to_unix_separators_on_windows(gix::path::into_bstr(repo_relative_path)),
299299
"Cargo.toml",
300300
);
301301
if index.entry_index_by_path(&manifest_path).is_ok() {
@@ -424,15 +424,8 @@ impl<'gctx> PathSource<'gctx> {
424424
// symlink points to a directory.
425425
let is_dir = is_dir.unwrap_or_else(|| file_path.is_dir());
426426
if is_dir {
427-
warn!(" found submodule {}", file_path.display());
428-
let rel = file_path.strip_prefix(root)?;
429-
let rel = rel.to_str().ok_or_else(|| {
430-
anyhow::format_err!("invalid utf-8 filename: {}", rel.display())
431-
})?;
432-
// Git submodules are currently only named through `/` path
433-
// separators, explicitly not `\` which windows uses. Who knew?
434-
let rel = rel.replace(r"\", "/");
435-
match repo.find_submodule(&rel).and_then(|s| s.open()) {
427+
warn!(" found directory {}", file_path.display());
428+
match git2::Repository::open(&file_path) {
436429
Ok(repo) => {
437430
let files = self.list_files_git(pkg, &repo, filter)?;
438431
ret.extend(files.into_iter());
@@ -531,7 +524,7 @@ impl<'gctx> PathSource<'gctx> {
531524
vec![include, exclude]
532525
};
533526

534-
let mut delegate = Delegate::new(self, pkg, pkg_path, repo, root, filter)?;
527+
let mut delegate = Delegate::new(self, pkg, pkg_path, root, filter)?;
535528
repo.dirwalk(
536529
&index,
537530
pathspec,
@@ -568,7 +561,6 @@ impl<'gctx> PathSource<'gctx> {
568561
pkg_path: &'a Path,
569562
parent: &'a PathSource<'gctx>,
570563
paths: Vec<PathBuf>,
571-
submodules_by_rela_path: Vec<(gix::bstr::BString, gix::Submodule<'a>)>,
572564
subpackages_found: Vec<PathBuf>,
573565
filter: &'a dyn Fn(&Path, bool) -> bool,
574566
err: Option<anyhow::Error>,
@@ -595,27 +587,15 @@ impl<'gctx> PathSource<'gctx> {
595587
parent: &'a PathSource<'gctx>,
596588
pkg: &'a Package,
597589
pkg_path: &'a Path,
598-
repo: &'a gix::Repository,
599590
root: &'a Path,
600591
filter: &'a dyn Fn(&Path, bool) -> bool,
601592
) -> CargoResult<Self> {
602-
let submodules_by_rela_path: Vec<_> = repo
603-
.submodules()?
604-
.into_iter()
605-
.flatten()
606-
.map(|sm| {
607-
sm.path()
608-
.map(|path| path.into_owned())
609-
.map(|path| (path, sm))
610-
})
611-
.collect::<Result<_, _>>()?;
612593
Ok(Self {
613594
root,
614595
pkg,
615596
pkg_path,
616597
parent,
617598
filter,
618-
submodules_by_rela_path,
619599
paths: vec![],
620600
subpackages_found: vec![],
621601
err: None,
@@ -661,19 +641,24 @@ impl<'gctx> PathSource<'gctx> {
661641
return Ok(());
662642
}
663643

664-
let is_dir = entry.disk_kind.map_or(false, |kind| kind.is_dir());
665-
if entry.disk_kind == Some(gix::dir::entry::Kind::Repository) {
666-
match self
667-
.submodules_by_rela_path
668-
.binary_search_by(|(sm_path, _)| {
669-
sm_path.as_bstr().cmp(entry.rela_path.as_ref())
670-
})
671-
.map(|idx| self.submodules_by_rela_path[idx].1.open())
672-
{
673-
Ok(Ok(Some(sm_repo))) => {
644+
let is_dir = entry.disk_kind.map_or(false, |kind| {
645+
if kind == gix::dir::entry::Kind::Symlink {
646+
// Symlinks must be checked to see if they point to a directory
647+
// we should traverse.
648+
file_path.is_dir()
649+
} else {
650+
kind.is_dir()
651+
}
652+
});
653+
if is_dir {
654+
// This could be a submodule, or a sub-repository. In any case, we prefer to walk
655+
// it with git-support to leverage ignored files and to avoid pulling in entire
656+
// .git repositories.
657+
match gix::open_opts(&file_path, gix::open::Options::isolated()) {
658+
Ok(sub_repo) => {
674659
let files =
675660
self.parent
676-
.list_files_gix(self.pkg, &sm_repo, self.filter)?;
661+
.list_files_gix(self.pkg, &sub_repo, self.filter)?;
677662
self.paths.extend(files);
678663
}
679664
_ => {

tests/testsuite/package.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ fn package_symlink_to_submodule() {
689689
project
690690
.cargo("package --no-verify -v")
691691
.with_stderr_contains("[ARCHIVING] submodule/Makefile")
692+
.with_stderr_does_not_contain("[ARCHIVING] submodule-link/.git/config")
692693
.run();
693694
}
694695

0 commit comments

Comments
 (0)