gix/revision/spec/parse/
error.rs1use std::collections::HashSet;
2
3use gix_hash::ObjectId;
4
5use super::Error;
6use crate::{bstr, bstr::BString, ext::ObjectIdExt, Repository};
7
8#[derive(Debug)]
10pub enum CandidateInfo {
11 FindError {
13 source: crate::object::find::existing::Error,
15 },
16 Object {
18 kind: gix_object::Kind,
20 },
21 Tag {
23 name: BString,
25 },
26 Commit {
28 date: String,
30 title: BString,
32 },
33}
34
35impl std::fmt::Display for CandidateInfo {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 CandidateInfo::FindError { source } => write!(f, "lookup error: {source}"),
39 CandidateInfo::Tag { name } => write!(f, "tag {name:?}"),
40 CandidateInfo::Object { kind } => std::fmt::Display::fmt(kind, f),
41 CandidateInfo::Commit { date, title } => {
42 write!(
43 f,
44 "commit {} {title:?}",
45 gix_date::parse_header(date)
46 .unwrap_or_default()
47 .format(gix_date::time::format::SHORT)
48 )
49 }
50 }
51 }
52}
53
54impl Error {
55 pub(crate) fn ambiguous(candidates: HashSet<ObjectId>, prefix: gix_hash::Prefix, repo: &Repository) -> Self {
56 #[derive(PartialOrd, Ord, Eq, PartialEq, Copy, Clone)]
57 enum Order {
58 Tag,
59 Commit,
60 Tree,
61 Blob,
62 Invalid,
63 }
64 let candidates = {
65 let mut c: Vec<_> = candidates
66 .into_iter()
67 .map(|oid| {
68 let obj = repo.find_object(oid);
69 let order = match &obj {
70 Err(_) => Order::Invalid,
71 Ok(obj) => match obj.kind {
72 gix_object::Kind::Tag => Order::Tag,
73 gix_object::Kind::Commit => Order::Commit,
74 gix_object::Kind::Tree => Order::Tree,
75 gix_object::Kind::Blob => Order::Blob,
76 },
77 };
78 (oid, obj, order)
79 })
80 .collect();
81 c.sort_by(|lhs, rhs| lhs.2.cmp(&rhs.2).then_with(|| lhs.0.cmp(&rhs.0)));
82 c
83 };
84 Error::AmbiguousPrefix {
85 prefix,
86 info: candidates
87 .into_iter()
88 .map(|(oid, find_result, _)| {
89 let info = match find_result {
90 Ok(obj) => match obj.kind {
91 gix_object::Kind::Tree | gix_object::Kind::Blob => CandidateInfo::Object { kind: obj.kind },
92 gix_object::Kind::Tag => {
93 let tag = obj.to_tag_ref();
94 CandidateInfo::Tag { name: tag.name.into() }
95 }
96 gix_object::Kind::Commit => {
97 use bstr::ByteSlice;
98 let commit = obj.to_commit_ref();
99 CandidateInfo::Commit {
100 date: commit.committer().time.trim().into(),
101 title: commit.message().title.trim().into(),
102 }
103 }
104 },
105 Err(err) => CandidateInfo::FindError { source: err },
106 };
107 (oid.attach(repo).shorten().unwrap_or_else(|_| oid.into()), info)
108 })
109 .collect(),
110 }
111 }
112
113 pub(crate) fn from_errors(errors: Vec<Self>) -> Self {
114 match errors.len() {
115 0 => unreachable!(
116 "BUG: cannot create something from nothing, must have recorded some errors to call from_errors()"
117 ),
118 1 => errors.into_iter().next().expect("one"),
119 _ => {
120 let mut it = errors.into_iter().rev();
121 let mut recent = Error::Multi {
122 current: Box::new(it.next().expect("at least one error")),
123 next: None,
124 };
125 for err in it {
126 recent = Error::Multi {
127 current: Box::new(err),
128 next: Some(Box::new(recent)),
129 }
130 }
131 recent
132 }
133 }
134 }
135}