#! /usr/bin/env python3.3 """Code to look up a Git commit's corresponding Perforce user.""" import logging import p4gf_config LOG = logging.getLogger(__name__) class G2PUser: """A class that knows how to find Perforce users that correspond to a Git commit's author/pusher/owner. """ def __init__( self, * , ctx , usermap ): self.ctx = ctx self.usermap = usermap # dict of pair ("email_addr", "git_user") # to Usermap.lookup() result tuple. # Saves us repeated trips to the usermap # and its O(n) scan. self.usermap_cache = {} def get_acp(self, fecommit): """Return a dict with values set to the Perforce user id for - author - committer - pusher Values set to None if no corresponding Perforce user id. Separate from and superset of _get_author_pusher_owner(). Called only for Git Swarm reviews because only Git Swarm reviews care about Git committer. """ return { 'author' : self._git_to_p4_user(fecommit, 'author') , 'committer' : self._git_to_p4_user(fecommit, 'committer') , 'pusher' : self.ctx.authenticated_p4user } def get_author_pusher_owner(self, commit): """Add to commit: p4 user id for: Git author, Git pusher and p4 change owner Retrieve the Perforce user performing the push, and the original author of the Git commit, if a known Perforce user, or unknown_git if that user is available. If the ignore-author-permissions config setting is false, or the change-owner is set to 'author', then the commit author must be a valid Perforce user. """ pusher = self.ctx.authenticated_p4user if self.ctx.owner_is_author: author = self._git_to_p4_user(commit, 'author') change_owner = author elif self.ctx.foruser: author = self.ctx.foruser change_owner = self.ctx.foruser else: author = pusher change_owner = pusher commit['author_p4user'] = author commit['pusher_p4user'] = pusher commit['owner'] = change_owner def _git_to_p4_user(self, fecommit, fecommit_key): """Return the Perforce user that corresponds to a given Git commit key 'author' or 'committer'. """ auth_src_cfg = self.ctx.repo_config.get(p4gf_config.SECTION_AUTHENTICATION, p4gf_config.KEY_AUTHOR_SOURCE) if auth_src_cfg is None: # The default is to use the email address in its entirety. author_source = [p4gf_config.VALUE_GIT_EMAIL] else: # Otherwise the sources are comma-separated and in order of # precedence -- first match wins. author_source = [s.strip() for s in auth_src_cfg.split(',')] user = None email_addr = fecommit[fecommit_key]['email'].strip('<>') git_user = fecommit[fecommit_key]['user'] (cached, result) = self._get_usermap_cache(email_addr, git_user) if cached: return result for source in author_source: if source == p4gf_config.VALUE_GIT_EMAIL: LOG.debug2("_git_to_p4_user(GIT_EMAIL) for email {} user {}" .format(email_addr, user)) user = self.usermap.lookup_by_email_with_subdomains(email_addr) elif source == p4gf_config.VALUE_GIT_EMAIL_ACCT: email_acct = email_addr.split('@', 1)[0] LOG.debug2("_git_to_p4_user(GIT_EMAIL_ACCT) for emailacct {}" " user {}".format(email_acct, user)) user = self.usermap.lookup_by_p4user(email_acct) elif source == p4gf_config.VALUE_GIT_USER: LOG.debug2("_git_to_p4_user(GIT_USER) for email {} gituser {}" .format(email_addr, git_user)) user = self.usermap.lookup_by_p4user(git_user) else: LOG.warning('ignoring unknown author-source value {}'.format(source)) if user is not None: LOG.debug2("_git_to_p4_user() for email {} found user {}".format(email_addr, user)) break if user is None: user = self.usermap.lookup_unknown_git() if (user is None) or (not self.usermap.p4user_exists(user[0])): result = None else: result = user[0] self._set_usermap_cache(email_addr, git_user, result) return result def _get_usermap_cache(self, email_addr, git_user): """If we've already looked up and found a Perforce user for this Git user, return that. Don't keep looking things up over and over. None is a valid cache hit, so return a 2-tuple with ("got a hit?", "result") """ key = (email_addr, git_user) if key in self.usermap_cache: return (True, self.usermap_cache.get(key)) else: return (False, None) def _set_usermap_cache(self, email_addr, git_user, result): """Cache the result for this usermap lookup so we never have to look for it again. """ key = (email_addr, git_user) self.usermap_cache[key] = result