Skip to content

Commit ae23762

Browse files
authored
Merge pull request #2352 from GitoxideLabs/gix-error
`gix-error` punch-through
2 parents 30e1989 + 3bac149 commit ae23762

File tree

71 files changed

+3069
-1188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+3069
-1188
lines changed

Cargo.lock

Lines changed: 15 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ members = [
236236
"gix-trace",
237237
"gix-commitgraph",
238238
"gix-chunk",
239+
"gix-error",
239240
"gix-quote",
240241
"gix-object",
241242
"gix-glob",

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ is usable to some extent.
141141
* [gix-dir](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-dir)
142142
* [gix-merge](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-merge)
143143
* [gix-shallow](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-shallow)
144+
* [gix-error](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-error)
144145
* `gitoxide-core`
145146
* **very early** _(possibly without any documentation and many rough edges)_
146147
* [gix-blame](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-blame)

crate-status.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,12 @@ A mechanism to associate metadata with any object, and keep revisions of it usin
572572
- note that it's less critical to support it as `gitoxide` allows access but prevents untrusted configuration to become effective.
573573

574574
### gix-date
575-
* [ ] parse git dates
576-
* [ ] serialize `Time`
575+
* [x] parse git dates
576+
* [x] serialize `Time`
577+
578+
### gix-error
579+
580+
A basic crate for comon error types and utilities, changed as needed to replace `thiserror`.
577581

578582
### gix-credentials
579583
* [x] launch git credentials helpers with a given action

gitoxide-core/src/repository/diff.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,21 @@ fn resolve_revspec(
125125
let result = repo.rev_parse(revspec.as_bstr());
126126

127127
match result {
128-
Err(gix::revision::spec::parse::Error::FindReference(gix::refs::file::find::existing::Error::NotFound {
129-
name,
130-
})) => {
131-
let root = repo.workdir().map(ToOwned::to_owned);
132-
let name = gix::path::os_string_into_bstring(name.into())?;
133-
134-
Ok((ObjectId::null(gix::hash::Kind::Sha1), root, name))
128+
Err(err) => {
129+
// When the revspec is just a name, the delegate tries to resolve a reference which fails.
130+
// We extract the error from the tree to learn the name, and treat it as file.
131+
let not_found = err
132+
.iter_frames()
133+
.find_map(|f| f.downcast::<gix::refs::file::find::existing::Error>());
134+
if let Some(gix::refs::file::find::existing::Error::NotFound { name }) = not_found {
135+
let root = repo.workdir().map(ToOwned::to_owned);
136+
let name = gix::path::os_string_into_bstring(name.into())?;
137+
138+
Ok((ObjectId::null(gix::hash::Kind::Sha1), root, name))
139+
} else {
140+
Err(err.into())
141+
}
135142
}
136-
Err(err) => Err(err.into()),
137143
Ok(resolved_revspec) => {
138144
let blob_id = resolved_revspec
139145
.single()

gitoxide-core/src/repository/revision/explain.rs

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ use gix::{
99
Delegate,
1010
},
1111
},
12+
Exn,
1213
};
1314

1415
pub fn explain(spec: std::ffi::OsString, mut out: impl std::io::Write) -> anyhow::Result<()> {
1516
let mut explain = Explain::new(&mut out);
1617
let spec = gix::path::os_str_into_bstr(&spec)?;
17-
gix::revision::plumbing::spec::parse(spec, &mut explain)?;
18+
gix::revision::plumbing::spec::parse(spec, &mut explain).map_err(gix::Error::from)?;
1819
if let Some(err) = explain.err {
1920
bail!(err);
2021
}
@@ -41,9 +42,10 @@ impl<'a> Explain<'a> {
4142
err: None,
4243
}
4344
}
44-
fn prefix(&mut self) -> Option<()> {
45+
fn prefix(&mut self) -> Result<(), Exn> {
4546
self.call += 1;
46-
write!(self.out, "{:02}. ", self.call).ok()
47+
write!(self.out, "{:02}. ", self.call).ok();
48+
Ok(())
4749
}
4850
fn revision_name(&self) -> BString {
4951
self.ref_name.clone().unwrap_or_else(|| {
@@ -56,13 +58,18 @@ impl<'a> Explain<'a> {
5658
}
5759

5860
impl delegate::Revision for Explain<'_> {
59-
fn find_ref(&mut self, name: &BStr) -> Option<()> {
61+
fn find_ref(&mut self, name: &BStr) -> Result<(), Exn> {
6062
self.prefix()?;
6163
self.ref_name = Some(name.into());
62-
writeln!(self.out, "Lookup the '{name}' reference").ok()
64+
writeln!(self.out, "Lookup the '{name}' reference").ok();
65+
Ok(())
6366
}
6467

65-
fn disambiguate_prefix(&mut self, prefix: gix::hash::Prefix, hint: Option<delegate::PrefixHint<'_>>) -> Option<()> {
68+
fn disambiguate_prefix(
69+
&mut self,
70+
prefix: gix::hash::Prefix,
71+
hint: Option<delegate::PrefixHint<'_>>,
72+
) -> Result<(), Exn> {
6673
self.prefix()?;
6774
self.oid_prefix = Some(prefix);
6875
writeln!(
@@ -76,10 +83,11 @@ impl delegate::Revision for Explain<'_> {
7683
format!("commit {generation} generations in future of reference {ref_name:?}"),
7784
}
7885
)
79-
.ok()
86+
.ok();
87+
Ok(())
8088
}
8189

82-
fn reflog(&mut self, query: ReflogLookup) -> Option<()> {
90+
fn reflog(&mut self, query: ReflogLookup) -> Result<(), Exn> {
8391
self.prefix()?;
8492
self.has_implicit_anchor = true;
8593
let ref_name: &BStr = self.ref_name.as_ref().map_or_else(|| "HEAD".into(), AsRef::as_ref);
@@ -92,16 +100,18 @@ impl delegate::Revision for Explain<'_> {
92100
ref_name
93101
)
94102
.ok(),
95-
}
103+
};
104+
Ok(())
96105
}
97106

98-
fn nth_checked_out_branch(&mut self, branch_no: usize) -> Option<()> {
107+
fn nth_checked_out_branch(&mut self, branch_no: usize) -> Result<(), Exn> {
99108
self.prefix()?;
100109
self.has_implicit_anchor = true;
101-
writeln!(self.out, "Find the {branch_no}th checked-out branch of 'HEAD'").ok()
110+
writeln!(self.out, "Find the {branch_no}th checked-out branch of 'HEAD'").ok();
111+
Ok(())
102112
}
103113

104-
fn sibling_branch(&mut self, kind: SiblingBranch) -> Option<()> {
114+
fn sibling_branch(&mut self, kind: SiblingBranch) -> Result<(), Exn> {
105115
self.prefix()?;
106116
self.has_implicit_anchor = true;
107117
let ref_info = match self.ref_name.as_ref() {
@@ -117,12 +127,13 @@ impl delegate::Revision for Explain<'_> {
117127
},
118128
ref_info
119129
)
120-
.ok()
130+
.ok();
131+
Ok(())
121132
}
122133
}
123134

124135
impl delegate::Navigate for Explain<'_> {
125-
fn traverse(&mut self, kind: Traversal) -> Option<()> {
136+
fn traverse(&mut self, kind: Traversal) -> Result<(), Exn> {
126137
self.prefix()?;
127138
let name = self.revision_name();
128139
writeln!(
@@ -133,10 +144,11 @@ impl delegate::Navigate for Explain<'_> {
133144
Traversal::NthParent(no) => format!("Select the {no}. parent of revision named '{name}'"),
134145
}
135146
)
136-
.ok()
147+
.ok();
148+
Ok(())
137149
}
138150

139-
fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
151+
fn peel_until(&mut self, kind: PeelTo<'_>) -> Result<(), Exn> {
140152
self.prefix()?;
141153
writeln!(
142154
self.out,
@@ -148,10 +160,11 @@ impl delegate::Navigate for Explain<'_> {
148160
PeelTo::Path(path) => format!("Lookup the object at '{path}' from the current tree-ish"),
149161
}
150162
)
151-
.ok()
163+
.ok();
164+
Ok(())
152165
}
153166

154-
fn find(&mut self, regex: &BStr, negated: bool) -> Option<()> {
167+
fn find(&mut self, regex: &BStr, negated: bool) -> Result<(), Exn> {
155168
self.prefix()?;
156169
self.has_implicit_anchor = true;
157170
let negate_text = if negated { "does not match" } else { "matches" };
@@ -172,10 +185,11 @@ impl delegate::Navigate for Explain<'_> {
172185
),
173186
}
174187
)
175-
.ok()
188+
.ok();
189+
Ok(())
176190
}
177191

178-
fn index_lookup(&mut self, path: &BStr, stage: u8) -> Option<()> {
192+
fn index_lookup(&mut self, path: &BStr, stage: u8) -> Result<(), Exn> {
179193
self.prefix()?;
180194
self.has_implicit_anchor = true;
181195
writeln!(
@@ -190,12 +204,13 @@ impl delegate::Navigate for Explain<'_> {
190204
_ => unreachable!("BUG: parser assures of that"),
191205
}
192206
)
193-
.ok()
207+
.ok();
208+
Ok(())
194209
}
195210
}
196211

197212
impl delegate::Kind for Explain<'_> {
198-
fn kind(&mut self, kind: spec::Kind) -> Option<()> {
213+
fn kind(&mut self, kind: spec::Kind) -> Result<(), Exn> {
199214
self.prefix()?;
200215
self.call = 0;
201216
writeln!(
@@ -211,14 +226,16 @@ impl delegate::Kind for Explain<'_> {
211226
unreachable!("BUG: 'single' mode is implied but cannot be set explicitly"),
212227
}
213228
)
214-
.ok()
229+
.ok();
230+
Ok(())
215231
}
216232
}
217233

218234
impl Delegate for Explain<'_> {
219-
fn done(&mut self) {
235+
fn done(&mut self) -> Result<(), Exn> {
220236
if !self.has_implicit_anchor && self.ref_name.is_none() && self.oid_prefix.is_none() {
221237
self.err = Some("Incomplete specification lacks its anchor, like a reference or object name".into());
222238
}
239+
Ok(())
223240
}
224241
}

gix-actor/src/signature/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod _ref {
1515
}
1616

1717
/// Try to parse the timestamp and create an owned instance from this shared one.
18-
pub fn to_owned(&self) -> Result<Signature, gix_date::parse::Error> {
18+
pub fn to_owned(&self) -> Result<Signature, gix_date::Error> {
1919
Ok(Signature {
2020
name: self.name.to_owned(),
2121
email: self.email.to_owned(),
@@ -58,7 +58,7 @@ mod _ref {
5858

5959
/// Parse the `time` field for access to the passed time since unix epoch, and the time offset.
6060
/// The format is expected to be [raw](gix_date::parse_header()).
61-
pub fn time(&self) -> Result<gix_date::Time, gix_date::parse::Error> {
61+
pub fn time(&self) -> Result<gix_date::Time, gix_date::Error> {
6262
self.time.parse()
6363
}
6464
}

gix-blame/tests/blame.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,9 @@ fn since() -> gix_testtools::Result {
413413
gix_blame::Options {
414414
diff_algorithm: gix_diff::blob::Algorithm::Histogram,
415415
ranges: BlameRanges::default(),
416-
since: Some(gix_date::parse("2025-01-31", None)?),
416+
since: Some(
417+
gix_date::parse("2025-01-31", None).expect("TODO: should be able to to retrieve inner from Exn"),
418+
),
417419
rewrites: Some(gix_diff::Rewrites::default()),
418420
debug_track_path: false,
419421
},

gix-date/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ doctest = false
1919
serde = ["dep:serde", "bstr/serde"]
2020

2121
[dependencies]
22+
gix-error = { version = "0.0.0", path = "../gix-error" }
2223
bstr = { version = "1.12.0", default-features = false, features = ["std"] }
2324
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
2425
itoa = "1.0.17"
2526
jiff = "0.2.17"
26-
thiserror = "2.0.17"
2727
# TODO: used for quick and easy `TimeBacking: std::io::Write` implementation, but could make that `Copy`
2828
# and remove this dep with custom impl
2929
smallvec = { version = "1.15.1", features = ["write"] }

gix-date/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ pub mod time;
1515
pub mod parse;
1616
pub use parse::function::{parse, parse_header};
1717

18+
pub use gix_error::ParseError as Error;
19+
1820
/// A timestamp with timezone.
1921
#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
2022
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]

0 commit comments

Comments
 (0)