blob: 1b1bad3bc37d79abb8ab1b26d57d7131b4a44c2c [file] [log] [blame]
use crate::config::tree::{Key, Mailmap};
use crate::Id;
impl crate::Repository {
// TODO: tests
/// 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
}
// TODO: tests
/// 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<(), crate::mailmap::load::Error> {
let mut err = None::<crate::mailmap::load::Error>;
let mut buf = Vec::new();
let mut blob_id = self
.config
.resolved
.string("mailmap", None, Mailmap::BLOB.name)
.and_then(|spec| {
self.rev_parse_single(spec.as_ref())
.map_err(|e| err.get_or_insert(e.into()))
.map(Id::detach)
.ok()
});
match self.work_dir() {
None => {
blob_id = blob_id.or_else(|| {
self.head().ok().and_then(|mut head| {
let commit = head.peel_to_commit_in_place().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.into());
}
})
{
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| err.get_or_insert(e.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.into())).ok()) {
target.merge(gix_mailmap::parse_ignore_errors(&blob.data));
}
let configured_path = self
.config_snapshot()
.trusted_path(Mailmap::FILE.logical_name().as_str())
.and_then(|res| res.map_err(|e| err.get_or_insert(e.into())).ok());
if let Some(mut file) =
configured_path.and_then(|path| std::fs::File::open(path).map_err(|e| err.get_or_insert(e.into())).ok())
{
buf.clear();
std::io::copy(&mut file, &mut buf)
.map_err(|e| err.get_or_insert(e.into()))
.ok();
target.merge(gix_mailmap::parse_ignore_errors(&buf));
}
err.map_or(Ok(()), Err)
}
}