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
Esempio n. 2
0
    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
Esempio n. 3
0
 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)