Skip to content

Commit a384a25

Browse files
committed
feat: support for trimming of whitespace around name and email (#364)
It's separated from parsing to assure we can round-trip, but it's made easy to obtain trimmed results using new methods. This high-level git-repository will also trim by default now.
1 parent 600eb69 commit a384a25

File tree

7 files changed

+53
-8
lines changed

7 files changed

+53
-8
lines changed

git-actor/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ local-time-support = ["git-features/time"]
2222
git-features = { version = "^0.19.1", path = "../git-features", optional = true }
2323
quick-error = "2.0.0"
2424
btoi = "0.4.2"
25-
bstr = { version = "0.2.13", default-features = false, features = ["std"]}
25+
bstr = { version = "0.2.13", default-features = false, features = ["std", "unicode"]}
2626
nom = { version = "7", default-features = false, features = ["std"]}
2727
itoa = "1.0.1"
2828
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]}

git-actor/src/signature/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod _ref {
22
use crate::{signature::decode, Signature, SignatureRef};
3+
use bstr::ByteSlice;
34

45
impl<'a> SignatureRef<'a> {
56
/// Deserialize a signature from the given `data`.
@@ -18,6 +19,15 @@ mod _ref {
1819
time: self.time,
1920
}
2021
}
22+
23+
/// Trim whitespace surrounding the name and email and return a new signature.
24+
pub fn trim(&self) -> SignatureRef<'a> {
25+
SignatureRef {
26+
name: self.name.trim().as_bstr(),
27+
email: self.email.trim().as_bstr(),
28+
time: self.time,
29+
}
30+
}
2131
}
2232
}
2333

git-actor/tests/signature/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,20 @@ mod write_to {
5454
use bstr::ByteSlice;
5555
use git_actor::Signature;
5656

57+
#[test]
58+
fn trim() {
59+
let sig = git_actor::SignatureRef::from_bytes::<()>(b" \t hello there \t < \t email \t > 1 -0030").unwrap();
60+
let sig = sig.trim();
61+
assert_eq!(sig.name, "hello there");
62+
assert_eq!(sig.email, "email");
63+
}
64+
5765
#[test]
5866
fn round_trip() -> Result<(), Box<dyn std::error::Error>> {
5967
for input in &[
6068
&b"Sebastian Thiel <[email protected]> 1 -0030"[..],
6169
".. ☺️Sebastian 王知明 Thiel🙌 .. <[email protected]> 1528473343 +0230".as_bytes(),
62-
".. whitespace \t is explicitly allowed - unicode aware trimming must be done elsewhere <[email protected]> 1528473343 +0230"
70+
".. whitespace \t is explicitly allowed - unicode aware trimming must be done elsewhere <[email protected]> 1528473343 +0230"
6371
.as_bytes(),
6472
] {
6573
let signature: Signature = git_actor::SignatureRef::from_bytes::<()>(input)?.into();

git-object/src/commit/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ impl<'a> CommitRef<'a> {
4848
crate::commit::ExtraHeaders::new(self.extra_headers.iter().map(|(k, v)| (*k, v.as_ref())))
4949
}
5050

51+
/// Return the author, with whitespace trimmed.
52+
///
53+
/// This is different from the `author` field which may contain whitespace.
54+
pub fn author(&self) -> git_actor::SignatureRef<'a> {
55+
self.author.trim()
56+
}
57+
58+
/// Return the committer, with whitespace trimmed.
59+
///
60+
/// This is different from the `committer` field which may contain whitespace.
61+
pub fn committer(&self) -> git_actor::SignatureRef<'a> {
62+
self.committer.trim()
63+
}
64+
5165
/// Returns a partially parsed message from which more information can be derived.
5266
pub fn message(&self) -> MessageRef<'a> {
5367
MessageRef::from_bytes(self.message)

git-object/src/commit/ref_iter.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ impl<'a> CommitRefIter<'a> {
8888
}
8989

9090
/// Returns the author signature if there is no decoding error.
91+
///
92+
/// It may contain white space surrounding it, and is exactly as parsed.
9193
/// Errors are coerced into options, hiding whether there was an error or not. The caller knows if there was an error or not.
9294
pub fn author(mut self) -> Result<git_actor::SignatureRef<'a>, crate::decode::Error> {
9395
self.find_map(|t| match t {
@@ -99,6 +101,9 @@ impl<'a> CommitRefIter<'a> {
99101
}
100102

101103
/// Returns the message if there is no decoding error.
104+
///
105+
/// It may contain white space surrounding it, and is exactly as
106+
// parsed.
102107
/// Errors are coerced into options, hiding whether there was an error or not. The caller knows if there was an error or not.
103108
pub fn message(mut self) -> Result<&'a BStr, crate::decode::Error> {
104109
self.find_map(|t| match t {

git-object/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,13 @@ pub struct CommitRef<'a> {
7676
pub tree: &'a BStr,
7777
/// HEX hash of each parent commit. Empty for first commit in repository.
7878
pub parents: SmallVec<[&'a BStr; 2]>,
79-
/// Who wrote this commit.
79+
/// Who wrote this commit. Name and email might contain whitespace and are not trimmed to ensure round-tripping.
80+
///
81+
/// Use the [`author()`][CommitRef::author()] method to received a trimmed version of it.
8082
pub author: git_actor::SignatureRef<'a>,
81-
/// Who committed this commit.
83+
/// Who committed this commit. Name and email might contain whitespace and are not trimmed to ensure round-tripping.
84+
///
85+
/// Use the [`committer()`][CommitRef::committer()] method to received a trimmed version of it.
8286
///
8387
/// This may be different from the `author` in case the author couldn't write to the repository themselves and
8488
/// is commonly encountered with contributed commits.

git-repository/src/object/commit.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,18 @@ impl<'repo> Commit<'repo> {
7676
git_object::CommitRefIter::from_bytes(&self.data)
7777
}
7878

79-
/// Return the commits author.
79+
/// Return the commits author, with surrounding whitespace trimmed.
8080
pub fn author(&self) -> Result<git_actor::SignatureRef<'_>, git_object::decode::Error> {
81-
git_object::CommitRefIter::from_bytes(&self.data).author()
81+
git_object::CommitRefIter::from_bytes(&self.data)
82+
.author()
83+
.map(|s| s.trim())
8284
}
8385

84-
/// Return the commits committer.
86+
/// Return the commits committer. with surrounding whitespace trimmed.
8587
pub fn committer(&self) -> Result<git_actor::SignatureRef<'_>, git_object::decode::Error> {
86-
git_object::CommitRefIter::from_bytes(&self.data).committer()
88+
git_object::CommitRefIter::from_bytes(&self.data)
89+
.committer()
90+
.map(|s| s.trim())
8791
}
8892

8993
/// Decode this commits parent ids on the fly without allocating.

0 commit comments

Comments
 (0)