use std::fmt; use std::path::PathBuf; use crate::rpcgit::cmd_error::CmdError; #[derive(Debug)] pub enum BabyError { Custom(String), Command(CmdError), Io { path: PathBuf, source: std::io::Error, }, Spawn { prog: String, source: std::io::Error, stderr: String, }, InvalidRange, PathEscapesRepository, RevisionEmpty, PathNotFound { revision: String, path: PathBuf, }, OutOfRange { actual_lines: u64, revision: String, path: PathBuf, }, IgnoreRevsNotBlob { revision: String, }, Parse { line_number: u64, message: String, }, RevisionNotFound(String), RevisionInvalid(String), NotATree { revision: String, path: PathBuf, }, CommitParse { line_number: u64, message: String, }, InvalidTimestamp(String), BranchNotFound(String), BranchAlreadyExists(String), RefNotFound(String), TagNotFound(String), TagAlreadyExists(String), InvalidRefName(String), InvalidBranchName(String), InvalidTagName(String), RefUpdateRejected(String), AmbiguousRef { query: String, candidates: Vec, }, TagVerifyFailed { name: String, reason: String, }, MergeBaseNotFound(String), ResolutionError { reason: String, }, BlobNotFound { oid: String, }, LFSPointerInvalid { oid: String, reason: String, }, ConfigGetFailed { key: String, stderr: String, }, ConfigSetFailed { key: String, stderr: String, }, ArchiveFailed(String), SubModuleParse { line: u64, reason: String, }, RemoteNotFound(String), RemoteAlreadyExists(String), InvalidRemoteUrl(String), FastImportFailed(String), NotARepository(String), GcFailed(String), InvalidGitArg(String), Unimplemented(&'static str), PayloadTooLarge { cap_bytes: u64, actual_bytes: u64, }, Cache { op: &'static str, source: String, }, } impl fmt::Display for BabyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Custom(msg) => write!(f, "{}", msg), Self::Command(err) => write!(f, "{}", err), Self::Io { path, source } => { write!(f, "io error at `{}`: {}", path.display(), source) } Self::Spawn { prog, source, stderr, } => write!( f, "`{}` failed: {} (stderr: {})", prog, source, stderr.trim() ), Self::InvalidRange => { write!(f, "invalid line range; expected 'A,B' with A <= B") } Self::PathEscapesRepository => write!( f, "blame path escapes repository (must be relative and contain no '..' components)" ), Self::RevisionEmpty => write!(f, "revision must not be empty"), Self::PathNotFound { revision, path } => write!( f, "path `{}` does not exist at revision `{}`", path.display(), revision ), Self::OutOfRange { actual_lines, revision, path, } => write!( f, "path `{}` at revision `{}` has only {} line(s), below the requested range", path.display(), revision, actual_lines ), Self::IgnoreRevsNotBlob { revision } => write!( f, "ignore-revs file at revision `{}` is not a blob", revision ), Self::Parse { line_number, message, } => write!( f, "malformed git blame output at line {}: {}", line_number, message ), Self::RevisionNotFound(rev) => { write!(f, "revision `{}` does not exist", rev) } Self::RevisionInvalid(rev) => { write!(f, "revision `{}` is malformed or ambiguous", rev) } Self::NotATree { revision, path } => write!( f, "`{}` at revision `{}` is not a tree", path.display(), revision ), Self::CommitParse { line_number, message, } => write!( f, "malformed commit porcelain at line {}: {}", line_number, message ), Self::InvalidTimestamp(input) => { write!(f, "invalid git timestamp: `{}`", input) } Self::BranchNotFound(name) => write!(f, "branch `{}` does not exist", name), Self::BranchAlreadyExists(name) => write!(f, "branch `{}` already exists", name), Self::RefNotFound(name) => write!(f, "ref `{}` does not exist", name), Self::TagNotFound(name) => write!(f, "tag `{}` does not exist", name), Self::TagAlreadyExists(name) => write!(f, "tag `{}` already exists", name), Self::InvalidRefName(name) => write!(f, "invalid ref name `{}`", name), Self::InvalidBranchName(name) => write!(f, "invalid branch name `{}`", name), Self::InvalidTagName(name) => write!(f, "invalid tag name `{}`", name), Self::RefUpdateRejected(reason) => { write!(f, "ref update rejected by git: {}", reason.trim()) } Self::AmbiguousRef { query, candidates } => write!( f, "ref `{}` is ambiguous; candidates: {}", query, candidates.join(", ") ), Self::TagVerifyFailed { name, reason } => { write!( f, "tag `{}` signature verification failed: {}", name, reason ) } Self::MergeBaseNotFound(spec) => { write!(f, "no merge-base exists for `{}`", spec) } Self::ResolutionError { reason } => { write!(f, "conflict resolution error: {}", reason) } Self::BlobNotFound { oid } => write!(f, "blob `{}` does not exist", oid), Self::LFSPointerInvalid { oid, reason } => { write!(f, "blob `{}` is not a valid LFS pointer: {}", oid, reason) } Self::ConfigGetFailed { key, stderr } => { write!(f, "git config get for `{}` failed: {}", key, stderr.trim()) } Self::ConfigSetFailed { key, stderr } => { write!(f, "git config set for `{}` failed: {}", key, stderr.trim()) } Self::ArchiveFailed(reason) => write!(f, "git archive failed: {}", reason.trim()), Self::SubModuleParse { line, reason } => { write!(f, "malformed .gitmodules at line {}: {}", line, reason) } Self::RemoteNotFound(name) => write!(f, "remote `{}` does not exist", name), Self::RemoteAlreadyExists(name) => { write!(f, "remote `{}` already exists", name) } Self::InvalidRemoteUrl(url) => write!(f, "invalid remote url `{}`", url), Self::FastImportFailed(reason) => { write!(f, "git fast-import failed: {}", reason.trim()) } Self::NotARepository(path) => write!(f, "`{}` is not a git repository", path), Self::GcFailed(reason) => write!(f, "git gc failed: {}", reason.trim()), Self::InvalidGitArg(msg) => write!(f, "invalid git argument: {}", msg), Self::Unimplemented(what) => write!(f, "not yet implemented: {}", what), Self::PayloadTooLarge { cap_bytes, actual_bytes, } => write!( f, "output exceeds cap: {} bytes > {} bytes cap", actual_bytes, cap_bytes ), Self::Cache { op, source } => { write!(f, "cache error during `{}`: {}", op, source) } } } } impl std::error::Error for BabyError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::Command(err) => Some(err), Self::Io { source, .. } => Some(source), Self::Spawn { source, .. } => Some(source), Self::Cache { .. } => None, Self::AmbiguousRef { .. } | Self::TagVerifyFailed { .. } => None, _ => None, } } } impl From for BabyError { fn from(err: CmdError) -> Self { Self::Command(err) } } impl From for BabyError { fn from(source: std::io::Error) -> Self { Self::Io { path: PathBuf::new(), source, } } }