use std::fmt;
use std::str::FromStr;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum MaintenanceTask {
Gc,
CommitGraph,
Prefetch,
LooseObjects,
IncrementalRepack,
PackRefs,
}
impl fmt::Display for MaintenanceTask {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(match self {
Self::Gc => "gc",
Self::CommitGraph => "commit-graph",
Self::Prefetch => "prefetch",
Self::LooseObjects => "loose-objects",
Self::IncrementalRepack => "incremental-repack",
Self::PackRefs => "pack-refs",
})
}
}
impl FromStr for MaintenanceTask {
type Err = TaskSelectionError;
fn from_str(name: &str) -> Result<Self, Self::Err> {
match name {
"gc" => Ok(Self::Gc),
"commit-graph" => Ok(Self::CommitGraph),
"prefetch" => Ok(Self::Prefetch),
"loose-objects" => Ok(Self::LooseObjects),
"incremental-repack" => Ok(Self::IncrementalRepack),
"pack-refs" => Ok(Self::PackRefs),
_ => Err(TaskSelectionError::Unsupported(name.into())),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct TaskSelection {
tasks: Vec<MaintenanceTask>,
}
impl TaskSelection {
pub fn explicit(tasks: &[MaintenanceTask]) -> Result<Self, TaskSelectionError> {
if tasks.is_empty() {
return Err(TaskSelectionError::DefaultTasks);
}
let mut selected = Vec::with_capacity(6);
for &task in tasks {
if selected.contains(&task) {
return Err(TaskSelectionError::Duplicate(task));
}
selected.push(task);
}
if let Some(position) = selected
.iter()
.position(|task| *task == MaintenanceTask::PackRefs)
{
selected.remove(position);
selected.insert(0, MaintenanceTask::PackRefs);
}
Ok(Self { tasks: selected })
}
pub fn tasks(&self) -> &[MaintenanceTask] {
&self.tasks
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TaskSelectionError {
#[error("maintenance requires explicit task selection")]
DefaultTasks,
#[error("maintenance task '{0}' was selected more than once")]
Duplicate(MaintenanceTask),
#[error("unsupported maintenance task '{0}'")]
Unsupported(Box<str>),
}