/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/plugins/stats/cmds.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
"""A Simple bzr plugin to generate statistics about the history."""
17
17
 
18
 
from __future__ import absolute_import
 
18
import operator
19
19
 
20
20
from ... import (
21
21
    branch,
59
59
            info[2][username] = info[2].setdefault(username, 0) + 1
60
60
    res = [(len(revs), revs, emails, fnames)
61
61
           for revs, emails, fnames in committer_to_info.values()]
62
 
    res.sort(reverse=True)
 
62
 
 
63
    def key_fn(item):
 
64
        return item[0], list(item[2].keys())
 
65
    res.sort(reverse=True, key=key_fn)
63
66
    return res
64
67
 
65
68
 
95
98
            # email
96
99
            for user in usernames:
97
100
                if not user:
98
 
                    continue # The mysterious ('', '') user
 
101
                    continue  # The mysterious ('', '') user
99
102
                # When mapping, use case-insensitive names
100
103
                low_user = user.lower()
101
104
                user_id = username_to_id.get(low_user)
131
134
    combo_to_best_combo = {}
132
135
    for cur_id, combos in id_to_combos.items():
133
136
        best_combo = sorted(combos,
134
 
                            key=lambda x:combo_count[x],
 
137
                            key=lambda x: combo_count[x],
135
138
                            reverse=True)[0]
136
139
        for combo in combos:
137
140
            combo_to_best_combo[combo] = best_combo
141
144
def get_revisions_and_committers(a_repo, revids):
142
145
    """Get the Revision information, and the best-match for committer."""
143
146
 
144
 
    email_users = {} # user@email.com => User Name
 
147
    email_users = {}  # user@email.com => User Name
145
148
    combo_count = {}
146
 
    pb = ui.ui_factory.nested_progress_bar()
147
 
    try:
 
149
    with ui.ui_factory.nested_progress_bar() as pb:
148
150
        trace.note('getting revisions')
149
 
        revisions = a_repo.iter_revisions(revids)
 
151
        revisions = list(a_repo.iter_revisions(revids))
150
152
        for count, (revid, rev) in enumerate(revisions):
151
153
            pb.update('checking', count, len(revids))
152
154
            for author in rev.get_apparent_authors():
156
158
                email_users.setdefault(email, set()).add(username)
157
159
                combo = (username, email)
158
160
                combo_count[combo] = combo_count.setdefault(combo, 0) + 1
159
 
    finally:
160
 
        pb.finished()
161
 
    return revisions, collapse_email_and_users(email_users, combo_count)
 
161
    return ((rev for (revid, rev) in revisions),
 
162
            collapse_email_and_users(email_users, combo_count))
162
163
 
163
164
 
164
165
def get_info(a_repo, revision):
165
166
    """Get all of the information for a particular revision"""
166
 
    pb = ui.ui_factory.nested_progress_bar()
167
 
    a_repo.lock_read()
168
 
    try:
 
167
    with ui.ui_factory.nested_progress_bar() as pb, a_repo.lock_read():
169
168
        trace.note('getting ancestry')
170
169
        graph = a_repo.get_graph()
171
170
        ancestry = [
172
171
            r for (r, ps) in graph.iter_ancestry([revision])
173
172
            if ps is not None and r != NULL_REVISION]
174
 
        revs, canonical_committer = get_revisions_and_committers(a_repo, ancestry)
175
 
    finally:
176
 
        a_repo.unlock()
177
 
        pb.finished()
 
173
        revs, canonical_committer = get_revisions_and_committers(
 
174
            a_repo, ancestry)
178
175
 
179
176
    return collapse_by_person(revs, canonical_committer)
180
177
 
184
181
 
185
182
    This lets us figure out what has actually changed between 2 revisions.
186
183
    """
187
 
    pb = ui.ui_factory.nested_progress_bar()
188
 
    a_repo.lock_read()
189
 
    try:
 
184
    with ui.ui_factory.nested_progress_bar() as pb, a_repo.lock_read():
190
185
        graph = a_repo.get_graph()
191
186
        trace.note('getting ancestry diff')
192
187
        ancestry = graph.find_difference(start_rev, end_rev)[1]
193
 
        revs, canonical_committer = get_revisions_and_committers(a_repo, ancestry)
194
 
    finally:
195
 
        a_repo.unlock()
196
 
        pb.finished()
 
188
        revs, canonical_committer = get_revisions_and_committers(
 
189
            a_repo, ancestry)
197
190
 
198
191
    return collapse_by_person(revs, canonical_committer)
199
192
 
204
197
    for count, revs, emails, fullnames in info:
205
198
        # Get the most common email name
206
199
        sorted_emails = sorted(((count, email)
207
 
                               for email, count in emails.items()),
 
200
                                for email, count in emails.items()),
208
201
                               reverse=True)
209
202
        sorted_fullnames = sorted(((count, fullname)
210
 
                                  for fullname, count in fullnames.items()),
 
203
                                   for fullname, count in fullnames.items()),
211
204
                                  reverse=True)
212
205
        if sorted_fullnames[0][1] == '' and sorted_emails[0][1] == '':
213
206
            to_file.write('%4d %s\n'
238
231
            for name, count in sorted(classes.items(), key=classify_key):
239
232
                if name is None:
240
233
                    name = "Unknown"
241
 
                to_file.write("     %4.0f%% %s\n" % ((float(count) / total) * 100.0, name))
 
234
                to_file.write("     %4.0f%% %s\n" %
 
235
                              ((float(count) / total) * 100.0, name))
242
236
 
243
237
 
244
238
class cmd_committer_statistics(commands.Command):
246
240
 
247
241
    aliases = ['stats', 'committer-stats']
248
242
    takes_args = ['location?']
249
 
    takes_options = ['revision', 
250
 
            option.Option('show-class', help="Show the class of contributions.")]
 
243
    takes_options = ['revision',
 
244
                     option.Option('show-class', help="Show the class of contributions.")]
251
245
 
252
246
    encoding_type = 'replace'
253
247
 
288
282
 
289
283
    encoding_type = 'replace'
290
284
 
 
285
    hidden = True
 
286
 
291
287
    def run(self, location='.'):
292
288
        try:
293
289
            wt = workingtree.WorkingTree.open_containing(location)[0]
314
310
def gather_class_stats(repository, revs):
315
311
    ret = {}
316
312
    total = 0
317
 
    pb = ui.ui_factory.nested_progress_bar()
318
 
    try:
 
313
    with ui.ui_factory.nested_progress_bar() as pb:
319
314
        with repository.lock_read():
320
315
            i = 0
321
316
            for delta in repository.get_deltas_for_revisions(revs):
322
317
                pb.update("classifying commits", i, len(revs))
323
318
                for c in classify_delta(delta):
324
 
                    if not c in ret:
 
319
                    if c not in ret:
325
320
                        ret[c] = 0
326
321
                    ret[c] += 1
327
322
                    total += 1
328
323
                i += 1
329
 
    finally:
330
 
        pb.finished()
331
324
    return ret, total
332
325
 
333
326
 
338
331
 
339
332
def display_credits(credits, to_file):
340
333
    (coders, documenters, artists, translators) = credits
 
334
 
341
335
    def print_section(name, lst):
342
336
        if len(lst) == 0:
343
337
            return
367
361
        ancestry = [r for (r, ps) in graph.iter_ancestry([revid])
368
362
                    if ps is not None and r != NULL_REVISION]
369
363
        revs = repository.get_revisions(ancestry)
370
 
        pb = ui.ui_factory.nested_progress_bar()
371
 
        try:
 
364
        with ui.ui_factory.nested_progress_bar() as pb:
372
365
            iterator = zip(revs, repository.get_deltas_for_revisions(revs))
373
366
            for i, (rev, delta) in enumerate(iterator):
374
367
                pb.update("analysing revisions", i, len(revs))
377
370
                    continue
378
371
                for c in set(classify_delta(delta)):
379
372
                    for author in rev.get_apparent_authors():
380
 
                        if not author in ret[c]:
 
373
                        if author not in ret[c]:
381
374
                            ret[c][author] = 0
382
375
                        ret[c][author] += 1
383
 
        finally:
384
 
            pb.finished()
 
376
 
385
377
    def sort_class(name):
386
378
        return [author
387
 
            for author, _  in sorted(ret[name].items(), key=classify_key)]
 
379
                for author, _ in sorted(ret[name].items(), key=classify_key)]
388
380
    return (sort_class("code"), sort_class("documentation"), sort_class("art"), sort_class("translation"))
389
381
 
390
382