use camino::{Utf8Path, Utf8PathBuf};
use crate::{
command::Cli,
driver::{Inputs, Mode},
select::{
ConflictGuard,
fs_probe::AmbientPathProbe,
git_failure::GitListError,
git_ls_files::GitLsFiles,
policy::{CandidatePath, ProbeFailure, select_files},
},
};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum GitInputsError {
#[error(transparent)]
Git(#[from] GitListError),
#[error(transparent)]
Probe(#[from] ProbeFailure),
}
impl GitInputsError {
#[must_use]
pub fn diagnostic(&self) -> String {
match self {
Self::Git(error) => error.diagnostic(),
Self::Probe(error) => error.to_string(),
}
}
}
pub struct GitSelection {
pub inputs: Inputs,
pub guard: ConflictGuard,
pub skipped_non_utf8: usize,
pub selection: SelectionStatistics,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SelectionStatistics {
pub candidates: usize,
pub selected: usize,
pub extension_count: usize,
}
impl GitSelection {
#[must_use]
pub fn skipped_warning(&self) -> Option<String> {
let skipped = self.skipped_non_utf8;
(skipped > 0).then(|| {
format!("mdtablefix: {skipped} file(s) not selected: their names are not valid UTF-8")
})
}
}
pub fn resolve(
cli: &Cli,
mode: Mode,
working_directory: &Utf8Path,
) -> Result<GitSelection, GitInputsError> {
let extensions = cli.extensions();
let listing = GitLsFiles::new(cli.includes_untracked()).list_candidates(working_directory)?;
let candidates: Vec<CandidatePath> = listing
.paths
.iter()
.map(|path| CandidatePath::new(path.to_string()))
.collect();
let selected = select_files(
&candidates,
&extensions,
&AmbientPathProbe::new(working_directory),
)?;
let selection = SelectionStatistics {
candidates: listing.paths.len(),
selected: selected.len(),
extension_count: extensions.iter().count(),
};
Ok(GitSelection {
inputs: Inputs::Files(
selected
.into_iter()
.map(|candidate| Utf8PathBuf::from(candidate.as_str()))
.collect(),
),
guard: guard(cli, mode, working_directory)?,
skipped_non_utf8: listing.skipped_non_utf8,
selection,
})
}
fn guard(
cli: &Cli,
mode: Mode,
working_directory: &Utf8Path,
) -> Result<ConflictGuard, GitListError> {
if mode != Mode::InPlace || cli.allows_conflicted() {
return Ok(ConflictGuard::unguarded());
}
let git_dir = GitLsFiles::new(cli.includes_untracked()).resolve_git_dir(working_directory)?;
Ok(ConflictGuard::guarded(git_dir))
}
pub fn working_directory() -> anyhow::Result<Utf8PathBuf> {
let directory = std::env::current_dir()?;
Utf8PathBuf::from_path_buf(directory).map_err(|directory| {
anyhow::anyhow!(
"converting the working directory {} to a UTF-8 path",
directory.display()
)
})
}
#[cfg(test)]
#[path = "git_inputs_tests.rs"]
mod tests;