def __call__(self, output, path, revision): # pylint:disable=W if not output: return None blame = Blame(revision, path) commit_info = defaultdict(dict) region_info = None for line in output.splitlines(): # Sample: ec3ed6... 2 1 7. match = REGION_START_COUNT_PATTERN.match(line) if match: if region_info: blame.AddRegion( Region( region_info.start, region_info.count, region_info.revision, commit_info[region_info.revision]['author_name'], commit_info[region_info.revision]['author_email'], commit_info[region_info.revision]['author_time'])) region_info = RegionInfo(start=int(match.group(2)), count=int(match.group(3)), revision=match.group(1)) elif region_info: # Sample: author [email protected]. if AUTHOR_NAME_PATTERN.match(line): commit_info[region_info.revision]['author_name'] = ( AUTHOR_NAME_PATTERN.match(line).group(1)) # Sample: author-mail <[email protected]@2eff-a529-9590-31e7-b00076f81>. elif AUTHOR_MAIL_PATTERN.match(line): commit_info[region_info.revision]['author_email'] = ( commit_util.NormalizeEmail( AUTHOR_MAIL_PATTERN.match(line).group(1).replace( '<', '').replace('>', ''))) # Sample: author-time 1311863160. elif AUTHOR_TIME_PATTERN.match(line): commit_info[region_info.revision]['author_time'] = ( AUTHOR_TIME_PATTERN.match(line).group(1)) # Sample: author-tz +0800. elif AUTHOR_TIMEZONE_PATTERN.match(line): time_zone = time_util.TimeZoneInfo( AUTHOR_TIMEZONE_PATTERN.match(line).group(1)) commit_info[region_info.revision]['author_time'] = ( time_zone.LocalToUTC( datetime.fromtimestamp( int(commit_info[region_info.revision] ['author_time'])))) if region_info: blame.AddRegion( Region(region_info.start, region_info.count, region_info.revision, commit_info[region_info.revision]['author_name'], commit_info[region_info.revision]['author_email'], commit_info[region_info.revision]['author_time'])) return blame if blame else None
def GetBlame(self, path, revision): """Returns blame of the file at ``path`` of the given revision.""" url = '%s/+blame/%s/%s' % (self.repo_url, revision, path) data = self._SendRequestForJsonResponse(url) if not data: return None blame = Blame(revision, path) for region in data['regions']: author_time = self._GetDateTimeFromString(region['author']['time'], '%Y-%m-%d %H:%M:%S') blame.AddRegion( Region(region['start'], region['count'], region['commit'], region['author']['name'], commit_util.NormalizeEmail(region['author']['email']), author_time)) return blame
def _ContributorFromDict(self, data): return Contributor(data['name'], commit_util.NormalizeEmail(data['email']), self._GetDateTimeFromString(data['time']))
def testNormalizeEmail(self): self.assertEqual( commit_util.NormalizeEmail( '[email protected]@bbb929c8-8fbe-4397-9dbb-9b2b20218538'), '*****@*****.**')
def __call__(self, output, repo_url): # pylint:disable=W """Parses output of 'git log --pretty=format:<format>. For example: Git changelog output is: commit 21a8979218c096f4a96b07b67c9531f5f09e28a3 tree 7d9a79c9b060c9a030abe20a8429d2b81ca1d4db parents 9640406d426a2d153b16e1d9ae7f9105268b36c9 author Test author-email [email protected] author-time 2016-10-24 22:21:45 committer Test committer-email [email protected] committer-time 2016-10-24 22:25:45 --Message start-- Commit messages... --Message end-- :100644 100644 25f95f c766f1 M src/a/delta/git_parsers.py Returns: Parsed ChangeLog object. """ if not output: return None is_message_line = False info = { 'author': {}, 'committer': {}, 'message': '', 'touched_files': [] } for line in output.splitlines(): if MESSAGE_START_PATTERN.match(line): is_message_line = True continue if MESSAGE_END_PATTERN.match(line): is_message_line = False # Remove the added '\n' at the end. info['message'] = info['message'][:-1] continue if is_message_line: info['message'] += line + '\n' elif COMMIT_HASH_PATTERN.match(line): info['revision'] = COMMIT_HASH_PATTERN.match(line).group(1) elif AUTHOR_NAME_PATTERN.match(line): info['author']['name'] = AUTHOR_NAME_PATTERN.match(line).group( 1) elif AUTHOR_MAIL_PATTERN.match(line): info['author']['email'] = commit_util.NormalizeEmail( AUTHOR_MAIL_PATTERN.match(line).group(1)) elif AUTHOR_TIME_PATTERN.match(line): info['author']['time'] = datetime.strptime( AUTHOR_TIME_PATTERN.match(line).group(1), DATETIME_FORMAT) elif COMMITTER_NAME_PATTERN.match(line): info['committer']['name'] = ( COMMITTER_NAME_PATTERN.match(line).group(1)) elif COMMITTER_MAIL_PATTERN.match(line): info['committer']['email'] = commit_util.NormalizeEmail( COMMITTER_MAIL_PATTERN.match(line).group(1)) elif COMMITTER_TIME_PATTERN.match(line): info['committer']['time'] = datetime.strptime( COMMITTER_TIME_PATTERN.match(line).group(1), DATETIME_FORMAT) elif (CHANGED_FILE_PATTERN1.match(line) or CHANGED_FILE_PATTERN2.match(line)): match = (CHANGED_FILE_PATTERN1.match(line) or CHANGED_FILE_PATTERN2.match(line)) # For modify, add, delete, the pattern is like: # :100644 100644 df565d 6593e M modules/audio_coding/BUILD.gn # For rename, copy, the pattern is like: # :100644 100644 3f2e 20a5 R078 path1 path2 info['touched_files'].append( GetFileChangeInfo( GetChangeType(match.group(5)), match.group(6), None if len(match.groups()) < 7 else match.group(7))) # If commit is not parsed, the changelog will be {'author': {}, 'committer': # {}, 'message': ''}, return None instead. if not 'revision' in info: return None change_info = commit_util.ExtractChangeInfo(info['message']) info['commit_position'] = change_info.get('commit_position') info['code_review_url'] = change_info.get('code_review_url') info['reverted_revision'] = commit_util.GetRevertedRevision( info['message']) info['commit_url'] = '%s/+/%s' % (repo_url, info['revision']) return ChangeLog.FromDict(info)