summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/revision/spec/parse/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/revision/spec/parse/error.rs')
-rw-r--r--vendor/gix/src/revision/spec/parse/error.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/vendor/gix/src/revision/spec/parse/error.rs b/vendor/gix/src/revision/spec/parse/error.rs
new file mode 100644
index 000000000..3af4697b0
--- /dev/null
+++ b/vendor/gix/src/revision/spec/parse/error.rs
@@ -0,0 +1,130 @@
+use std::collections::HashSet;
+
+use gix_hash::ObjectId;
+
+use super::Error;
+use crate::{bstr, bstr::BString, ext::ObjectIdExt, Repository};
+
+/// Additional information about candidates that caused ambiguity.
+#[derive(Debug)]
+pub enum CandidateInfo {
+ /// An error occurred when looking up the object in the database.
+ FindError {
+ /// The reported error.
+ source: crate::object::find::existing::Error,
+ },
+ /// The candidate is an object of the given `kind`.
+ Object {
+ /// The kind of the object.
+ kind: gix_object::Kind,
+ },
+ /// The candidate is a tag.
+ Tag {
+ /// The name of the tag.
+ name: BString,
+ },
+ /// The candidate is a commit.
+ Commit {
+ /// The date of the commit.
+ date: gix_date::Time,
+ /// The subject line.
+ title: BString,
+ },
+}
+
+impl std::fmt::Display for CandidateInfo {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CandidateInfo::FindError { source } => write!(f, "lookup error: {source}"),
+ CandidateInfo::Tag { name } => write!(f, "tag {name:?}"),
+ CandidateInfo::Object { kind } => std::fmt::Display::fmt(kind, f),
+ CandidateInfo::Commit { date, title } => {
+ write!(f, "commit {} {title:?}", date.format(gix_date::time::format::SHORT))
+ }
+ }
+ }
+}
+
+impl Error {
+ pub(crate) fn ambiguous(candidates: HashSet<ObjectId>, prefix: gix_hash::Prefix, repo: &Repository) -> Self {
+ #[derive(PartialOrd, Ord, Eq, PartialEq, Copy, Clone)]
+ enum Order {
+ Tag,
+ Commit,
+ Tree,
+ Blob,
+ Invalid,
+ }
+ let candidates = {
+ let mut c: Vec<_> = candidates
+ .into_iter()
+ .map(|oid| {
+ let obj = repo.find_object(oid);
+ let order = match &obj {
+ Err(_) => Order::Invalid,
+ Ok(obj) => match obj.kind {
+ gix_object::Kind::Tag => Order::Tag,
+ gix_object::Kind::Commit => Order::Commit,
+ gix_object::Kind::Tree => Order::Tree,
+ gix_object::Kind::Blob => Order::Blob,
+ },
+ };
+ (oid, obj, order)
+ })
+ .collect();
+ c.sort_by(|lhs, rhs| lhs.2.cmp(&rhs.2).then_with(|| lhs.0.cmp(&rhs.0)));
+ c
+ };
+ Error::AmbiguousPrefix {
+ prefix,
+ info: candidates
+ .into_iter()
+ .map(|(oid, find_result, _)| {
+ let info = match find_result {
+ Ok(obj) => match obj.kind {
+ gix_object::Kind::Tree | gix_object::Kind::Blob => CandidateInfo::Object { kind: obj.kind },
+ gix_object::Kind::Tag => {
+ let tag = obj.to_tag_ref();
+ CandidateInfo::Tag { name: tag.name.into() }
+ }
+ gix_object::Kind::Commit => {
+ use bstr::ByteSlice;
+ let commit = obj.to_commit_ref();
+ CandidateInfo::Commit {
+ date: commit.committer().time,
+ title: commit.message().title.trim().into(),
+ }
+ }
+ },
+ Err(err) => CandidateInfo::FindError { source: err },
+ };
+ (oid.attach(repo).shorten().unwrap_or_else(|_| oid.into()), info)
+ })
+ .collect(),
+ }
+ }
+
+ pub(crate) fn from_errors(errors: Vec<Self>) -> Self {
+ assert!(!errors.is_empty());
+ match errors.len() {
+ 0 => unreachable!(
+ "BUG: cannot create something from nothing, must have recorded some errors to call from_errors()"
+ ),
+ 1 => errors.into_iter().next().expect("one"),
+ _ => {
+ let mut it = errors.into_iter().rev();
+ let mut recent = Error::Multi {
+ current: Box::new(it.next().expect("at least one error")),
+ next: None,
+ };
+ for err in it {
+ recent = Error::Multi {
+ current: Box::new(err),
+ next: Some(Box::new(recent)),
+ }
+ }
+ recent
+ }
+ }
+ }
+}