Function git_discover::is_git
source · Expand description
What constitutes a valid git repository, returning the guessed repository kind purely based on the presence of files. Note that the git-config ultimately decides what’s bare.
Returns the Kind
of git directory that was passed, possibly alongside the supporting private worktree git dir.
Note that .git
files are followed to a valid git directory, which then requires…
- …a valid head
- …an objects directory
- …a refs directory
Examples found in repository?
src/upwards/mod.rs (line 112)
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
pub fn discover_opts(
directory: impl AsRef<Path>,
Options {
required_trust,
ceiling_dirs,
match_ceiling_dir_or_error,
cross_fs,
current_dir,
}: Options<'_>,
) -> Result<(crate::repository::Path, Trust), Error> {
// Normalize the path so that `Path::parent()` _actually_ gives
// us the parent directory. (`Path::parent` just strips off the last
// path component, which means it will not do what you expect when
// working with paths paths that contain '..'.)
let cwd = current_dir
.map(|cwd| Ok(Cow::Borrowed(cwd)))
.unwrap_or_else(|| std::env::current_dir().map(Cow::Owned))?;
let directory = directory.as_ref();
let dir = git_path::normalize(directory, cwd.as_ref()).ok_or_else(|| Error::InvalidInput {
directory: directory.into(),
})?;
let dir_metadata = dir.metadata().map_err(|_| Error::InaccessibleDirectory {
path: dir.to_path_buf(),
})?;
if !dir_metadata.is_dir() {
return Err(Error::InaccessibleDirectory { path: dir.into_owned() });
}
let mut dir_made_absolute = !directory.is_absolute()
&& cwd
.as_ref()
.strip_prefix(dir.as_ref())
.or_else(|_| dir.as_ref().strip_prefix(cwd.as_ref()))
.is_ok();
let filter_by_trust = |x: &Path| -> Result<Option<Trust>, Error> {
let trust = Trust::from_path_ownership(x).map_err(|err| Error::CheckTrust { path: x.into(), err })?;
Ok((trust >= required_trust).then(|| (trust)))
};
let max_height = if !ceiling_dirs.is_empty() {
let max_height = find_ceiling_height(&dir, &ceiling_dirs, cwd.as_ref());
if max_height.is_none() && match_ceiling_dir_or_error {
return Err(Error::NoMatchingCeilingDir);
}
max_height
} else {
None
};
#[cfg(unix)]
let initial_device = device_id(&dir_metadata);
let mut cursor = dir.clone().into_owned();
let mut current_height = 0;
'outer: loop {
if max_height.map_or(false, |x| current_height > x) {
return Err(Error::NoGitRepositoryWithinCeiling {
path: dir.into_owned(),
ceiling_height: current_height,
});
}
current_height += 1;
#[cfg(unix)]
if current_height != 0 && !cross_fs {
let metadata = if cursor.as_os_str().is_empty() {
Path::new(".")
} else {
cursor.as_ref()
}
.metadata()
.map_err(|_| Error::InaccessibleDirectory { path: cursor.clone() })?;
if device_id(&metadata) != initial_device {
return Err(Error::NoGitRepositoryWithinFs {
path: dir.into_owned(),
limit: cursor.clone(),
});
}
}
for append_dot_git in &[false, true] {
if *append_dot_git {
cursor.push(DOT_GIT_DIR);
}
if let Ok(kind) = is_git(&cursor) {
match filter_by_trust(&cursor)? {
Some(trust) => {
// TODO: test this more, it definitely doesn't always find the shortest path to a directory
let path = if dir_made_absolute {
shorten_path_with_cwd(cursor, cwd.as_ref())
} else {
cursor
};
break 'outer Ok((
crate::repository::Path::from_dot_git_dir(path, kind, cwd).ok_or_else(|| {
Error::InvalidInput {
directory: directory.into(),
}
})?,
trust,
));
}
None => {
break 'outer Err(Error::NoTrustedGitRepository {
path: dir.into_owned(),
candidate: cursor,
required: required_trust,
})
}
}
}
if *append_dot_git {
cursor.pop();
}
}
if cursor.parent().map_or(false, |p| p.as_os_str().is_empty()) {
cursor = cwd.to_path_buf();
dir_made_absolute = true;
}
if !cursor.pop() {
if dir_made_absolute
|| matches!(
cursor.components().next(),
Some(std::path::Component::RootDir) | Some(std::path::Component::Prefix(_))
)
{
break Err(Error::NoGitRepository { path: dir.into_owned() });
} else {
dir_made_absolute = true;
debug_assert!(!cursor.as_os_str().is_empty());
// TODO: realpath or normalize? No test runs into this.
cursor = git_path::normalize(&cursor, cwd.as_ref())
.ok_or_else(|| Error::InvalidInput {
directory: cursor.clone(),
})?
.into_owned();
}
}
}
}