summaryrefslogtreecommitdiffstats
path: root/third_party/python/fluent.migrate/fluent/migrate/blame.py
blob: 2ae23d0ebea26ee8cb9462871d43dc81a130baea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import argparse
import json
import os

from compare_locales.parser import getParser, Junk
from compare_locales.parser.fluent import FluentEntity
from compare_locales import mozpath
import hglib
from hglib.util import b, cmdbuilder


class Blame:
    def __init__(self, client):
        self.client = client
        self.users = []
        self.blame = {}

    def attribution(self, file_paths):
        args = cmdbuilder(
            b('annotate'), *[b(p) for p in file_paths], template='json',
            date=True, user=True, cwd=self.client.root())
        blame_json = self.client.rawcommand(args)
        file_blames = json.loads(blame_json)

        for file_blame in file_blames:
            self.handleFile(file_blame)

        return {'authors': self.users,
                'blame': self.blame}

    def handleFile(self, file_blame):
        path = mozpath.normsep(file_blame['path'])

        try:
            parser = getParser(path)
        except UserWarning:
            return

        self.blame[path] = {}

        self.readFile(parser, path)
        entities = parser.parse()
        for e in entities:
            if isinstance(e, Junk):
                continue
            if e.val_span:
                key_vals = [(e.key, e.val_span)]
            else:
                key_vals = []
            if isinstance(e, FluentEntity):
                key_vals += [
                    (f'{e.key}.{attr.key}', attr.val_span)
                    for attr in e.attributes
                ]
            for key, (val_start, val_end) in key_vals:
                entity_lines = file_blame['lines'][
                    (e.ctx.linecol(val_start)[0] - 1):e.ctx.linecol(val_end)[0]
                ]
                # ignore timezone
                entity_lines.sort(key=lambda blame: -blame['date'][0])
                line_blame = entity_lines[0]
                user = line_blame['user']
                timestamp = line_blame['date'][0]  # ignore timezone
                if user not in self.users:
                    self.users.append(user)
                userid = self.users.index(user)
                self.blame[path][key] = [userid, timestamp]

    def readFile(self, parser, path):
        parser.readFile(os.path.join(self.client.root().decode('utf-8'), path))


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('repo_path')
    parser.add_argument('file_path', nargs='+')
    args = parser.parse_args()
    blame = Blame(hglib.open(args.repo_path))
    attrib = blame.attribution(args.file_path)
    print(json.dumps(attrib, indent=4, separators=(',', ': ')))