use std::io;
use camino::{Utf8Path, Utf8PathBuf};
use cap_std::{
ambient_authority,
fs_utf8::{Dir, Metadata},
};
use super::conflict::RepositoryOperationState;
const IN_PROGRESS: [&str; 5] = [
"MERGE_HEAD",
"rebase-merge",
"rebase-apply",
"CHERRY_PICK_HEAD",
"REVERT_HEAD",
];
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConflictGuard {
Unguarded,
Guarded(Utf8PathBuf),
}
impl ConflictGuard {
#[must_use]
pub const fn unguarded() -> Self { Self::Unguarded }
#[must_use]
pub fn guarded(git_dir: impl Into<Utf8PathBuf>) -> Self { Self::Guarded(git_dir.into()) }
pub fn operation_state(&self) -> Result<RepositoryOperationState, RepositoryStateError> {
let Self::Guarded(git_dir) = self else {
return Ok(RepositoryOperationState::Idle);
};
operation_in_progress(git_dir)
}
}
pub fn operation_in_progress(
git_dir: &Utf8Path,
) -> Result<RepositoryOperationState, RepositoryStateError> {
let directory = Dir::open_ambient_dir(git_dir, ambient_authority()).map_err(|source| {
RepositoryStateError {
git_dir: git_dir.to_owned(),
source,
}
})?;
let opened = directory
.dir_metadata()
.map_err(|source| RepositoryStateError {
git_dir: git_dir.to_owned(),
source,
})?;
opened_directory(git_dir, &opened)?;
for name in IN_PROGRESS {
let present =
marker_present(directory.symlink_metadata(name).map(|_| ())).map_err(|source| {
RepositoryStateError {
git_dir: git_dir.to_owned(),
source,
}
})?;
if present {
return Ok(RepositoryOperationState::InProgress);
}
}
Ok(RepositoryOperationState::Idle)
}
pub(super) fn opened_directory(
git_dir: &Utf8Path,
metadata: &Metadata,
) -> Result<(), RepositoryStateError> {
if metadata.is_dir() {
return Ok(());
}
Err(RepositoryStateError {
git_dir: git_dir.to_owned(),
source: io::Error::new(
io::ErrorKind::NotADirectory,
format!("`{git_dir}` is not a directory"),
),
})
}
pub(super) fn marker_present(test: io::Result<()>) -> Result<bool, io::Error> {
match test {
Ok(()) => Ok(true),
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
Err(error) => Err(error),
}
}
#[derive(Debug, thiserror::Error)]
#[error("reading the state of the Git directory `{git_dir}`")]
pub struct RepositoryStateError {
pub git_dir: Utf8PathBuf,
#[source]
pub source: io::Error,
}