#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RebaseErrorKind {
InvalidRevision { revision: String },
DirtyWorkingTree,
ConcurrentOperation { operation: String },
RepositoryCorrupt { details: String },
EnvironmentFailure { reason: String },
HookRejection { hook_name: String },
ContentConflict { files: Vec<String> },
PatchApplicationFailed { reason: String },
InteractiveStop { command: String },
EmptyCommit,
AutostashFailed { reason: String },
CommitCreationFailed { reason: String },
ReferenceUpdateFailed { reason: String },
#[cfg(any(test, feature = "test-utils"))]
ValidationFailed { reason: String },
#[cfg(any(test, feature = "test-utils"))]
ProcessTerminated { reason: String },
#[cfg(any(test, feature = "test-utils"))]
InconsistentState { details: String },
Unknown { details: String },
}
impl RebaseErrorKind {
#[must_use]
pub fn description(&self) -> String {
describe_rebase_error_kind(self)
}
}
fn describe_invalid_revision(revision: &str) -> String {
format!("Invalid or unresolvable revision: '{revision}'")
}
fn describe_dirty_working_tree() -> String {
"Working tree has uncommitted changes".to_string()
}
fn describe_concurrent_operation(operation: &str) -> String {
format!("Concurrent Git operation in progress: {operation}")
}
fn describe_repository_corrupt(details: &str) -> String {
format!("Repository integrity issue: {details}")
}
fn describe_environment_failure(reason: &str) -> String {
format!("Environment or configuration failure: {reason}")
}
fn describe_hook_rejection(hook_name: &str) -> String {
format!("Hook '{hook_name}' rejected the operation")
}
fn describe_content_conflict(file_count: usize) -> String {
format!("Merge conflicts in {file_count} file(s)",)
}
fn describe_patch_application_failed(reason: &str) -> String {
format!("Patch application failed: {reason}")
}
fn describe_interactive_stop(command: &str) -> String {
format!("Interactive rebase stopped at command: {command}")
}
fn describe_empty_commit() -> String {
"Empty or redundant commit".to_string()
}
fn describe_autostash_failed(reason: &str) -> String {
format!("Autostash failed: {reason}")
}
fn describe_commit_creation_failed(reason: &str) -> String {
format!("Commit creation failed: {reason}")
}
fn describe_reference_update_failed(reason: &str) -> String {
format!("Reference update failed: {reason}")
}
#[cfg(any(test, feature = "test-utils"))]
fn describe_validation_failed(reason: &str) -> String {
format!("Post-rebase validation failed: {reason}")
}
#[cfg(any(test, feature = "test-utils"))]
fn describe_process_terminated(reason: &str) -> String {
format!("Rebase process terminated: {reason}")
}
#[cfg(any(test, feature = "test-utils"))]
fn describe_inconsistent_state(details: &str) -> String {
format!("Inconsistent rebase state: {details}")
}
fn describe_unknown(details: &str) -> String {
format!("Unknown rebase error: {details}")
}
fn describe_rebase_error_kind(kind: &RebaseErrorKind) -> String {
match kind {
RebaseErrorKind::InvalidRevision { revision } => describe_invalid_revision(revision),
RebaseErrorKind::DirtyWorkingTree => describe_dirty_working_tree(),
RebaseErrorKind::ConcurrentOperation { operation } => {
describe_concurrent_operation(operation)
}
RebaseErrorKind::RepositoryCorrupt { details } => describe_repository_corrupt(details),
RebaseErrorKind::EnvironmentFailure { reason } => describe_environment_failure(reason),
RebaseErrorKind::HookRejection { hook_name } => describe_hook_rejection(hook_name),
RebaseErrorKind::ContentConflict { files } => describe_content_conflict(files.len()),
RebaseErrorKind::PatchApplicationFailed { reason } => {
describe_patch_application_failed(reason)
}
RebaseErrorKind::InteractiveStop { command } => describe_interactive_stop(command),
RebaseErrorKind::EmptyCommit => describe_empty_commit(),
RebaseErrorKind::AutostashFailed { reason } => describe_autostash_failed(reason),
RebaseErrorKind::CommitCreationFailed { reason } => describe_commit_creation_failed(reason),
RebaseErrorKind::ReferenceUpdateFailed { reason } => {
describe_reference_update_failed(reason)
}
#[cfg(any(test, feature = "test-utils"))]
RebaseErrorKind::ValidationFailed { reason } => describe_validation_failed(reason),
#[cfg(any(test, feature = "test-utils"))]
RebaseErrorKind::ProcessTerminated { reason } => describe_process_terminated(reason),
#[cfg(any(test, feature = "test-utils"))]
RebaseErrorKind::InconsistentState { details } => describe_inconsistent_state(details),
RebaseErrorKind::Unknown { details } => describe_unknown(details),
}
}
impl RebaseErrorKind {
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn is_recoverable(&self) -> bool {
match self {
Self::ConcurrentOperation { .. } => true,
#[cfg(any(test, feature = "test-utils"))]
Self::ProcessTerminated { .. } | Self::InconsistentState { .. } => true,
Self::ContentConflict { .. } => true,
Self::InvalidRevision { .. }
| Self::DirtyWorkingTree
| Self::RepositoryCorrupt { .. }
| Self::EnvironmentFailure { .. }
| Self::HookRejection { .. }
| Self::PatchApplicationFailed { .. }
| Self::InteractiveStop { .. }
| Self::EmptyCommit
| Self::AutostashFailed { .. }
| Self::CommitCreationFailed { .. }
| Self::ReferenceUpdateFailed { .. } => false,
#[cfg(any(test, feature = "test-utils"))]
Self::ValidationFailed { .. } => false,
Self::Unknown { .. } => false,
}
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn category(&self) -> u8 {
match self {
Self::InvalidRevision { .. }
| Self::DirtyWorkingTree
| Self::ConcurrentOperation { .. }
| Self::RepositoryCorrupt { .. }
| Self::EnvironmentFailure { .. }
| Self::HookRejection { .. } => 1,
Self::ContentConflict { .. }
| Self::PatchApplicationFailed { .. }
| Self::InteractiveStop { .. }
| Self::EmptyCommit
| Self::AutostashFailed { .. }
| Self::CommitCreationFailed { .. }
| Self::ReferenceUpdateFailed { .. } => 2,
#[cfg(any(test, feature = "test-utils"))]
Self::ValidationFailed { .. } => 3,
#[cfg(any(test, feature = "test-utils"))]
Self::ProcessTerminated { .. } | Self::InconsistentState { .. } => 4,
Self::Unknown { .. } => 5,
}
}
}
impl std::fmt::Display for RebaseErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.description())
}
}
impl std::error::Error for RebaseErrorKind {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RebaseResult {
Success,
Conflicts(Vec<String>),
NoOp { reason: String },
Failed(RebaseErrorKind),
}
impl RebaseResult {
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn is_success(&self) -> bool {
matches!(self, Self::Success)
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn has_conflicts(&self) -> bool {
matches!(self, Self::Conflicts(_))
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn is_noop(&self) -> bool {
matches!(self, Self::NoOp { .. })
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn is_failed(&self) -> bool {
matches!(self, Self::Failed(_))
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub fn conflict_files(&self) -> Option<&[String]> {
match self {
Self::Conflicts(files) | Self::Failed(RebaseErrorKind::ContentConflict { files }) => {
Some(files)
}
_ => None,
}
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub const fn error_kind(&self) -> Option<&RebaseErrorKind> {
match self {
Self::Failed(kind) => Some(kind),
_ => None,
}
}
#[cfg(any(test, feature = "test-utils"))]
#[must_use]
pub fn noop_reason(&self) -> Option<&str> {
match self {
Self::NoOp { reason } => Some(reason),
_ => None,
}
}
}