diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/gix/src/repository/identity.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix/src/repository/identity.rs')
-rw-r--r-- | vendor/gix/src/repository/identity.rs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/vendor/gix/src/repository/identity.rs b/vendor/gix/src/repository/identity.rs new file mode 100644 index 000000000..61a4b4a98 --- /dev/null +++ b/vendor/gix/src/repository/identity.rs @@ -0,0 +1,175 @@ +use std::time::SystemTime; + +use crate::{ + bstr::BString, + config, + config::tree::{gitoxide, keys, Author, Committer, Key, User}, +}; + +/// Identity handling. +/// +/// # Deviation +/// +/// There is no notion of a default user like in git, and instead failing to provide a user +/// is fatal. That way, we enforce correctness and force application developers to take care +/// of this issue which can be done in various ways, for instance by setting +/// `gitoxide.committer.nameFallback` and similar. +impl crate::Repository { + /// Return the committer as configured by this repository, which is determined by… + /// + /// * …the git configuration `committer.name|email`… + /// * …the `GIT_COMMITTER_(NAME|EMAIL|DATE)` environment variables… + /// * …the configuration for `user.name|email` as fallback… + /// + /// …and in that order, or `None` if no committer name or email was configured, or `Some(Err(…))` + /// if the committer date could not be parsed. + /// + /// # Note + /// + /// The values are cached when the repository is instantiated. + pub fn committer(&self) -> Option<Result<gix_actor::SignatureRef<'_>, config::time::Error>> { + let p = self.config.personas(); + + Ok(gix_actor::SignatureRef { + name: p.committer.name.as_ref().or(p.user.name.as_ref()).map(|v| v.as_ref())?, + email: p + .committer + .email + .as_ref() + .or(p.user.email.as_ref()) + .map(|v| v.as_ref())?, + time: match extract_time_or_default(p.committer.time.as_ref(), &gitoxide::Commit::COMMITTER_DATE) { + Ok(t) => t, + Err(err) => return Some(Err(err)), + }, + }) + .into() + } + + /// Return the author as configured by this repository, which is determined by… + /// + /// * …the git configuration `author.name|email`… + /// * …the `GIT_AUTHOR_(NAME|EMAIL|DATE)` environment variables… + /// * …the configuration for `user.name|email` as fallback… + /// + /// …and in that order, or `None` if there was nothing configured. + /// + /// # Note + /// + /// The values are cached when the repository is instantiated. + pub fn author(&self) -> Option<Result<gix_actor::SignatureRef<'_>, config::time::Error>> { + let p = self.config.personas(); + + Ok(gix_actor::SignatureRef { + name: p.author.name.as_ref().or(p.user.name.as_ref()).map(|v| v.as_ref())?, + email: p.author.email.as_ref().or(p.user.email.as_ref()).map(|v| v.as_ref())?, + time: match extract_time_or_default(p.author.time.as_ref(), &gitoxide::Commit::AUTHOR_DATE) { + Ok(t) => t, + Err(err) => return Some(Err(err)), + }, + }) + .into() + } +} + +fn extract_time_or_default( + time: Option<&Result<gix_actor::Time, gix_date::parse::Error>>, + config_key: &'static keys::Time, +) -> Result<gix_actor::Time, config::time::Error> { + match time { + Some(Ok(t)) => Ok(*t), + None => Ok(gix_date::Time::now_local_or_utc()), + Some(Err(err)) => Err(config::time::Error::from(config_key).with_source(err.clone())), + } +} + +#[derive(Debug, Clone)] +pub(crate) struct Entity { + pub name: Option<BString>, + pub email: Option<BString>, + /// A time parsed from an environment variable, handling potential errors is delayed. + pub time: Option<Result<gix_actor::Time, gix_date::parse::Error>>, +} + +#[derive(Debug, Clone)] +pub(crate) struct Personas { + user: Entity, + committer: Entity, + author: Entity, +} + +impl Personas { + pub fn from_config_and_env(config: &gix_config::File<'_>) -> Self { + fn entity_in_section( + config: &gix_config::File<'_>, + name_key: &keys::Any, + email_key: &keys::Any, + fallback: Option<(&keys::Any, &keys::Any)>, + ) -> (Option<BString>, Option<BString>) { + let fallback = fallback.and_then(|(name_key, email_key)| { + debug_assert_eq!(name_key.section.name(), email_key.section.name()); + config + .section("gitoxide", Some(name_key.section.name().into())) + .ok() + .map(|section| (section, name_key, email_key)) + }); + ( + config + .string(name_key.section.name(), None, name_key.name) + .or_else(|| fallback.as_ref().and_then(|(s, name_key, _)| s.value(name_key.name))) + .map(|v| v.into_owned()), + config + .string(email_key.section.name(), None, email_key.name) + .or_else(|| fallback.as_ref().and_then(|(s, _, email_key)| s.value(email_key.name))) + .map(|v| v.into_owned()), + ) + } + let now = SystemTime::now(); + let parse_date = |key: &str, date: &keys::Time| -> Option<Result<gix_date::Time, gix_date::parse::Error>> { + debug_assert_eq!( + key, + date.logical_name(), + "BUG: drift of expected name and actual name of the key (we hardcode it to save an allocation)" + ); + config + .string_by_key(key) + .map(|time| date.try_into_time(time, now.into())) + }; + + let fallback = ( + &gitoxide::Committer::NAME_FALLBACK, + &gitoxide::Committer::EMAIL_FALLBACK, + ); + let (committer_name, committer_email) = + entity_in_section(config, &Committer::NAME, &Committer::EMAIL, Some(fallback)); + let fallback = (&gitoxide::Author::NAME_FALLBACK, &gitoxide::Author::EMAIL_FALLBACK); + let (author_name, author_email) = entity_in_section(config, &Author::NAME, &Author::EMAIL, Some(fallback)); + let (user_name, mut user_email) = entity_in_section(config, &User::NAME, &User::EMAIL, None); + + let committer_date = parse_date("gitoxide.commit.committerDate", &gitoxide::Commit::COMMITTER_DATE); + let author_date = parse_date("gitoxide.commit.authorDate", &gitoxide::Commit::AUTHOR_DATE); + + user_email = user_email.or_else(|| { + config + .string_by_key(gitoxide::User::EMAIL_FALLBACK.logical_name().as_str()) + .map(|v| v.into_owned()) + }); + Personas { + user: Entity { + name: user_name, + email: user_email, + time: None, + }, + committer: Entity { + name: committer_name, + email: committer_email, + time: committer_date, + }, + author: Entity { + name: author_name, + email: author_email, + time: author_date, + }, + } + } +} |