Skip to content

Commit

Permalink
change!: Provide more details when classifying submodule directories. (
Browse files Browse the repository at this point in the history
…#482)

That way we can avoid feeding `.git` files to `git-repository::open()`
and avoid work duplication, which ultimately allows to open submodules
directories of all kinds.
  • Loading branch information
Byron committed Aug 17, 2022
1 parent 7ab3279 commit 1b0ef18
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 13 deletions.
8 changes: 6 additions & 2 deletions git-discover/src/is.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn git(git_dir: impl AsRef<Path>) -> Result<crate::repository::Kind, crate::
#[derive(Eq, PartialEq)]
enum Kind {
MaybeRepo,
Submodule,
LinkedWorkTreeDir,
WorkTreeGitDir { work_dir: std::path::PathBuf },
}
Expand Down Expand Up @@ -59,7 +60,7 @@ pub fn git(git_dir: impl AsRef<Path>) -> Result<crate::repository::Kind, crate::
None => (
Cow::Owned(private_git_dir.clone()),
Cow::Owned(private_git_dir),
Kind::MaybeRepo,
Kind::Submodule,
),
}
}
Expand Down Expand Up @@ -124,6 +125,9 @@ pub fn git(git_dir: impl AsRef<Path>) -> Result<crate::repository::Kind, crate::
linked_git_dir: Some(dot_git.into_owned()),
},
Kind::WorkTreeGitDir { work_dir } => crate::repository::Kind::WorkTreeGitDir { work_dir },
Kind::Submodule => crate::repository::Kind::Submodule {
git_dir: dot_git.into_owned(),
},
Kind::MaybeRepo => {
if bare(git_dir) {
crate::repository::Kind::Bare
Expand All @@ -140,7 +144,7 @@ pub fn git(git_dir: impl AsRef<Path>) -> Result<crate::repository::Kind, crate::
})
&& last_comp == Some(OsStr::new("modules"))
{
crate::repository::Kind::Bare
crate::repository::Kind::SubmoduleGitDir
} else {
crate::repository::Kind::WorkTree { linked_git_dir: None }
}
Expand Down
25 changes: 20 additions & 5 deletions git-discover/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::path::PathBuf;
/// A repository path which either points to a work tree or the `.git` repository itself.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Path {
/// The currently checked out linked worktree along with its connected and existing git directory.
/// The currently checked out linked worktree along with its connected and existing git directory, or the worktree checkout of a
/// submodule.
LinkedWorkTree {
/// The base of the work tree.
work_dir: PathBuf,
Expand All @@ -14,7 +15,8 @@ pub enum Path {
WorkTree(PathBuf),
/// The git repository itself, typically bare and without known worktree.
///
/// Note that it might still have linked work-trees which can be accessed later, weather bare or not.
/// Note that it might still have linked work-trees which can be accessed later, weather bare or not, or it might be a
/// submodule git directory in the `.git/modules/**/<name>` directory of the parent repository.
Repository(PathBuf),
}

Expand Down Expand Up @@ -44,7 +46,7 @@ mod path {
/// Instantiate a new path from `dir` which is expected to be the `.git` directory, with `kind` indicating
/// whether it's a bare repository or not.
pub fn from_dot_git_dir(dir: impl Into<PathBuf>, kind: Kind) -> Self {
fn absolutize_on_trailing_parent(dir: PathBuf) -> PathBuf {
fn absolutize_on_trailing_dot_dot(dir: PathBuf) -> PathBuf {
if !matches!(dir.components().rev().next(), Some(std::path::Component::ParentDir)) {
dir
} else {
Expand All @@ -54,14 +56,19 @@ mod path {

let dir = dir.into();
match kind {
Kind::Submodule { git_dir } => Path::LinkedWorkTree {
git_dir: git_path::absolutize(git_dir, std::env::current_dir().ok()).into_owned(),
work_dir: without_dot_git_dir(absolutize_on_trailing_dot_dot(dir)),
},
Kind::SubmoduleGitDir => Path::Repository(dir),
Kind::WorkTreeGitDir { work_dir } => Path::LinkedWorkTree { git_dir: dir, work_dir },
Kind::WorkTree { linked_git_dir } => match linked_git_dir {
Some(git_dir) => Path::LinkedWorkTree {
git_dir,
work_dir: without_dot_git_dir(absolutize_on_trailing_parent(dir)),
work_dir: without_dot_git_dir(absolutize_on_trailing_dot_dot(dir)),
},
None => {
let mut dir = absolutize_on_trailing_parent(dir);
let mut dir = absolutize_on_trailing_dot_dot(dir);
dir.pop(); // ".git" suffix
let work_dir = dir.as_os_str().is_empty().then(|| PathBuf::from(".")).unwrap_or(dir);
Path::WorkTree(work_dir)
Expand Down Expand Up @@ -111,6 +118,14 @@ pub enum Kind {
/// Path to the worktree directory.
work_dir: PathBuf,
},
/// The directory is a `.git` dir file of a submodule worktree.
Submodule {
/// The git repository itself that is referenced by the `.git` dir file, typically in the `.git/modules/**/<name>` directory of the parent
/// repository.
git_dir: PathBuf,
},
/// The git directory in the `.git/modules/**/<name>` directory tree of the parent repository
SubmoduleGitDir,
}

impl Kind {
Expand Down
16 changes: 10 additions & 6 deletions git-discover/tests/upwards/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,22 +267,26 @@ mod submodules {
fn by_their_worktree_checkout() -> crate::Result {
let dir = git_testtools::scripted_fixture_repo_read_only("make_submodules.sh")?;
let parent = dir.join("with-submodules");
let modules = parent.join(".git").join("modules");
for module in ["m1", "dir/m1"] {
let submodule_m1_workdir = parent.join(module);
let submodule_m1_gitdir = modules.join(module);
let (path, _trust) = git_discover::upwards(&submodule_m1_workdir)?;
assert!(
matches!(path, git_discover::repository::Path::WorkTree(ref dir) if dir == &submodule_m1_workdir),
"{:?} should match {:?}",
matches!(path, git_discover::repository::Path::LinkedWorkTree{ref work_dir, ref git_dir} if work_dir == &submodule_m1_workdir && git_dir == &submodule_m1_gitdir),
"{:?} should match {:?} {:?}",
path,
submodule_m1_workdir
submodule_m1_workdir,
submodule_m1_gitdir
);

let (path, _trust) = git_discover::upwards(&submodule_m1_workdir.join("subdir"))?;
assert!(
matches!(path, git_discover::repository::Path::WorkTree(ref dir) if dir == &submodule_m1_workdir),
"{:?} should match {:?}",
matches!(path, git_discover::repository::Path::LinkedWorkTree{ref work_dir, ref git_dir} if work_dir == &submodule_m1_workdir && git_dir == &submodule_m1_gitdir),
"{:?} should match {:?} {:?}",
path,
submodule_m1_workdir
submodule_m1_workdir,
submodule_m1_gitdir
);
}
Ok(())
Expand Down

0 comments on commit 1b0ef18

Please sign in to comment.