Skip to content

Commit 8fd53bc

Browse files
authored
Merge pull request #1732 from GitoxideLabs/reflog-parsing
fix reflog parsing
2 parents ad6b9b6 + 6abee88 commit 8fd53bc

File tree

2 files changed

+59
-20
lines changed

2 files changed

+59
-20
lines changed

gix-ref/src/store/file/log/line.rs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ impl<'a> From<LineRef<'a>> for Line {
7373

7474
///
7575
pub mod decode {
76+
use crate::{file::log::LineRef, parse::hex_hash};
7677
use gix_object::bstr::{BStr, ByteSlice};
7778
use winnow::{
7879
combinator::{alt, eof, fail, opt, preceded, rest, terminated},
@@ -81,8 +82,6 @@ pub mod decode {
8182
token::take_while,
8283
};
8384

84-
use crate::{file::log::LineRef, parse::hex_hash};
85-
8685
///
8786
mod error {
8887
use gix_object::bstr::{BString, ByteSlice};
@@ -135,34 +134,57 @@ pub mod decode {
135134
fn one<'a, E: ParserError<&'a [u8]> + AddContext<&'a [u8], StrContext>>(
136135
bytes: &mut &'a [u8],
137136
) -> PResult<LineRef<'a>, E> {
138-
(
139-
(
137+
let mut tokens = bytes.splitn(2, |b| *b == b'\t');
138+
if let (Some(mut first), Some(mut second)) = (tokens.next(), tokens.next()) {
139+
let (old, new, signature) = (
140140
terminated(hex_hash, b" ").context(StrContext::Expected("<old-hexsha>".into())),
141141
terminated(hex_hash, b" ").context(StrContext::Expected("<new-hexsha>".into())),
142142
gix_actor::signature::decode.context(StrContext::Expected("<name> <<email>> <timestamp>".into())),
143143
)
144144
.context(StrContext::Expected(
145145
"<old-hexsha> <new-hexsha> <name> <<email>> <timestamp> <tz>\\t<message>".into(),
146-
)),
147-
alt((
148-
preceded(
149-
b'\t',
150-
message.context(StrContext::Expected("<optional message>".into())),
151-
),
152-
b'\n'.value(Default::default()),
153-
eof.value(Default::default()),
154-
fail.context(StrContext::Expected(
155-
"log message must be separated from signature with whitespace".into(),
156-
)),
157-
)),
158-
)
159-
.map(|((old, new, signature), message)| LineRef {
146+
))
147+
.parse_next(&mut first)?;
148+
149+
// forward the buffer🤦‍♂️
150+
message.parse_next(bytes)?;
151+
let message = message(&mut second)?;
152+
Ok(LineRef {
160153
previous_oid: old,
161154
new_oid: new,
162155
signature,
163156
message,
164157
})
165-
.parse_next(bytes)
158+
} else {
159+
(
160+
(
161+
terminated(hex_hash, b" ").context(StrContext::Expected("<old-hexsha>".into())),
162+
terminated(hex_hash, b" ").context(StrContext::Expected("<new-hexsha>".into())),
163+
gix_actor::signature::decode.context(StrContext::Expected("<name> <<email>> <timestamp>".into())),
164+
)
165+
.context(StrContext::Expected(
166+
"<old-hexsha> <new-hexsha> <name> <<email>> <timestamp> <tz>\\t<message>".into(),
167+
)),
168+
alt((
169+
preceded(
170+
b'\t',
171+
message.context(StrContext::Expected("<optional message>".into())),
172+
),
173+
b'\n'.value(Default::default()),
174+
eof.value(Default::default()),
175+
fail.context(StrContext::Expected(
176+
"log message must be separated from signature with whitespace".into(),
177+
)),
178+
)),
179+
)
180+
.map(|((old, new, signature), message)| LineRef {
181+
previous_oid: old,
182+
new_oid: new,
183+
signature,
184+
message,
185+
})
186+
.parse_next(bytes)
187+
}
166188
}
167189

168190
#[cfg(test)]

gix-ref/tests/refs/file/log.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,23 @@ mod line {
2929
Ok(())
3030
}
3131
}
32+
33+
mod parse {
34+
use gix_ref::file::log;
35+
36+
#[test]
37+
fn angle_bracket_in_comment() -> crate::Result {
38+
let line = log::LineRef::from_bytes(b"7b114132d03c468a9cd97836901553658c9792de 306cdbab5457c323d1201aa8a59b3639f600a758 First Last <first.last@example.com> 1727013187 +0200\trebase (pick): Replace Into<Range<u32>> by From<LineRange>")?;
39+
assert_eq!(line.signature.name, "First Last");
40+
assert_eq!(line.signature.email, "first.last@example.com");
41+
assert_eq!(line.signature.time.seconds, 1727013187);
42+
assert_eq!(
43+
line.message,
44+
"rebase (pick): Replace Into<Range<u32>> by From<LineRange>"
45+
);
46+
Ok(())
47+
}
48+
}
3249
}
3350

3451
mod iter {
@@ -204,7 +221,7 @@ mod iter {
204221

205222
let mut iter = gix_ref::file::log::iter::forward(log_first_broken.as_bytes());
206223
let err = iter.next().expect("error is not none").expect_err("the line is broken");
207-
assert_eq!(err.to_string(), "In line 1: \"134385fbroken7062102c6a483440bfda2a03 committer <committer@example.com> 946771200 +0000\\tcommit\" did not match '<old-hexsha> <new-hexsha> <name> <<email>> <timestamp> <tz>\\t<message>'");
224+
assert_eq!(err.to_string(), "In line 1: \"0000000000000000000000000000000000000000 134385fbroken7062102c6a483440bfda2a03 committer <committer@example.com> 946771200 +0000\\tcommit\" did not match '<old-hexsha> <new-hexsha> <name> <<email>> <timestamp> <tz>\\t<message>'");
208225
assert!(iter.next().expect("a second line").is_ok(), "line parses ok");
209226
assert!(iter.next().is_none(), "iterator exhausted");
210227
}

0 commit comments

Comments
 (0)