1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::{Error, Id, Result, bstr::ByteSlice, config::tree::Mailmap};
use gix_error::ErrorExt;
impl crate::Repository {
/// Similar to [`open_mailmap_into()`][crate::Repository::open_mailmap_into()], but ignores all errors and returns at worst
/// an empty mailmap, e.g. if there is no mailmap or if there were errors loading them.
///
/// This represents typical usage within git, which also works with what's there without considering a populated mailmap
/// a reason to abort an operation, considering it optional.
pub fn open_mailmap(&self) -> gix_mailmap::Snapshot {
let mut out = gix_mailmap::Snapshot::default();
self.open_mailmap_into(&mut out).ok();
out
}
/// Try to merge mailmaps from the following locations into `target`:
///
/// - read the `.mailmap` file without following symlinks from the working tree, if present
/// - OR read `HEAD:.mailmap` if this repository is bare (i.e. has no working tree), if the `mailmap.blob` is not set.
/// - read the mailmap as configured in `mailmap.blob`, if set.
/// - read the file as configured by `mailmap.file`, following symlinks, if set.
///
/// Only the first error will be reported, and as many source mailmaps will be merged into `target` as possible.
/// Parsing errors will be ignored.
pub fn open_mailmap_into(&self, target: &mut gix_mailmap::Snapshot) -> Result<()> {
let mut err = None::<Error>;
let mut buf = Vec::new();
let mut blob_id = self.config.resolved.string(Mailmap::BLOB).and_then(|spec| {
self.rev_parse_single(spec.as_bstr())
.map_err(|e| {
err.get_or_insert(
e.and_raise(gix_error::message("The configured mailmap.blob could not be parsed"))
.into(),
)
})
.map(Id::detach)
.ok()
});
match self.workdir() {
None => {
blob_id = blob_id.or_else(|| {
self.head().ok().and_then(|mut head| {
let commit = head.peel_to_commit().ok()?;
let tree = commit.tree().ok()?;
tree.find_entry(".mailmap").map(|e| e.object_id())
})
});
}
Some(root) => {
if let Ok(mut file) = gix_features::fs::open_options_no_follow()
.read(true)
.open(root.join(".mailmap"))
.map_err(|e| {
if e.kind() != std::io::ErrorKind::NotFound {
err.get_or_insert(
e.and_raise(gix_error::message(
"The mailmap file declared in `mailmap.file` could not be read",
))
.into(),
);
}
})
{
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| {
err.get_or_insert(
e.and_raise(gix_error::message(
"The mailmap file declared in `mailmap.file` could not be read",
))
.into(),
)
})
.ok();
target.merge(gix_mailmap::parse_ignore_errors(&buf));
}
}
}
if let Some(blob) = blob_id.and_then(|id| {
self.find_object(id)
.map_err(|e| {
err.get_or_insert(
e.and_raise(gix_error::message("Could not find object configured in `mailmap.blob`"))
.into(),
)
})
.ok()
}) {
target.merge(gix_mailmap::parse_ignore_errors(&blob.data));
}
let configured_path = self
.config_snapshot()
.trusted_path(Mailmap::FILE)
.map_err(|e| err.get_or_insert(Error::from_error(e)))
.ok()
.flatten();
if let Some(mut file) = configured_path.and_then(|path| {
std::fs::File::open(path)
.map_err(|e| {
err.get_or_insert(
e.and_raise(gix_error::message(
"The mailmap file declared in `mailmap.file` could not be read",
))
.into(),
)
})
.ok()
}) {
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| {
err.get_or_insert(
e.and_raise(gix_error::message(
"The mailmap file declared in `mailmap.file` could not be read",
))
.into(),
)
})
.ok();
target.merge(gix_mailmap::parse_ignore_errors(&buf));
}
err.map_or(Ok(()), Err)
}
}