summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/repository/identity.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix/src/repository/identity.rs')
-rw-r--r--vendor/gix/src/repository/identity.rs175
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,
+ },
+ }
+ }
+}