##// END OF EJS Templates
errors: stop passing non-strings to Abort's constructor...
errors: stop passing non-strings to Abort's constructor The next patch will change `Abort`'s constructor and `__bytes__` functions and they will start assuming that the first argument is the messages as `bytes`. Differential Revision: https://phab.mercurial-scm.org/D9178

File last commit:

r46229:d1759b2e default
r46273:a736ab68 default
Show More
churn.py
258 lines | 7.5 KiB | text/x-python | PythonLexer
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 # churn.py - create a graph of revisions count grouped by template
Patrick Mezard
Make churn an official extension
r6348 #
# Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
Patrick Mezard
Make churn an official extension
r6348 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
add blank line after copyright notices and after header
r8228
Dirkjan Ochtman
extensions: change descriptions for extensions providing a few commands
r8934 '''command to display statistics about repository history'''
Patrick Mezard
Make churn an official extension
r6348
Augie Fackler
churn: use integer division consistently...
r40277 from __future__ import absolute_import, division
Gregory Szorc
churn: use absolute_import
r28094
import datetime
import os
import time
Martin Geisler
i18n, churn: mark string for translation
r7051 from mercurial.i18n import _
Gregory Szorc
py3: manually import pycompat.open into files that need it...
r43355 from mercurial.pycompat import open
Gregory Szorc
churn: use absolute_import
r28094 from mercurial import (
cmdutil,
encoding,
Yuya Nishihara
cmdutil: drop aliases for logcmdutil functions (API)...
r35906 logcmdutil,
Gregory Szorc
churn: use absolute_import
r28094 patch,
Pulkit Goyal
py3: handle keyword arguments in hgext/churn.py...
r34975 pycompat,
Yuya Nishihara
registrar: move cmdutil.command to registrar module (API)...
r32337 registrar,
Gregory Szorc
churn: use absolute_import
r28094 )
Patrick Mezard
Make churn an official extension
r6348
Gregory Szorc
churn: declare command using decorator
r21245 cmdtable = {}
Yuya Nishihara
registrar: move cmdutil.command to registrar module (API)...
r32337 command = registrar.command(cmdtable)
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Augie Fackler
hgext: mark all first-party extensions as such
r16743
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
cmdutil: make walkchangerevs() call prepare with matcher instead of filenames...
r46225 def changedlines(ui, repo, ctx1, ctx2, fmatch):
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 added, removed = 0, 0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 diff = b''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
for l in diff.split(b'\n'):
if l.startswith(b"+") and not l.startswith(b"+++ "):
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 added += 1
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif l.startswith(b"-") and not l.startswith(b"--- "):
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 removed += 1
return (added, removed)
Patrick Mezard
Make churn an official extension
r6348
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 def countrate(ui, repo, amap, *pats, **opts):
"""Calculate stats"""
Pulkit Goyal
py3: handle keyword arguments in hgext/churn.py...
r34975 opts = pycompat.byteskwargs(opts)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'dateformat'):
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 def getkey(ctx):
t, tz = ctx.date()
date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
Augie Fackler
churn: fix stack traces on Python 3...
r40276 return encoding.strtolocal(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 date.strftime(encoding.strfromlocal(opts[b'dateformat']))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 tmpl = opts.get(b'oldtemplate') or opts.get(b'template')
Yuya Nishihara
cmdutil: drop aliases for logcmdutil functions (API)...
r35906 tmpl = logcmdutil.maketemplater(ui, repo, tmpl)
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 def getkey(ctx):
ui.pushbuffer()
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 tmpl.show(ctx)
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 return ui.popbuffer()
Augie Fackler
formatting: blacken the codebase...
r43346 progress = ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'analyzing'), unit=_(b'revisions'), total=len(repo)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 rate = {}
Yuya Nishihara
cmdutil: make walkchangerevs() call prepare with matcher instead of filenames...
r46225 def prep(ctx, fmatch):
Matt Mackall
walkchangerevs: yield contexts
r9654 rev = ctx.rev()
Alexander Solovyov
churn: strip key earlier to avoid false negative seach in aliases
r14040 key = getkey(ctx).strip()
Augie Fackler
formatting: blacken the codebase...
r43346 key = amap.get(key, key) # alias remap
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'changesets'):
Alexander Solovyov
churn: fix changeset count (broken by 9b127e888640)
r9670 rate[key] = (rate.get(key, (0,))[0] + 1, 0)
Alexander Solovyov
churn and stats commands merged
r7070 else:
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 parents = ctx.parents()
if len(parents) > 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.note(_(b'revision %d is a merge, ignoring...\n') % (rev,))
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 return
Patrick Mezard
Make churn an official extension
r6348
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 ctx1 = parents[0]
Yuya Nishihara
cmdutil: make walkchangerevs() call prepare with matcher instead of filenames...
r46225 lines = changedlines(ui, repo, ctx1, ctx, fmatch)
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
Patrick Mezard
Make churn an official extension
r6348
Martin von Zweigbergk
churn: use progess helper...
r38420 progress.increment()
Patrick Mezard
Make churn an official extension
r6348
Yuya Nishihara
cmdutil: rewrite walkchangerevs() by using logcmdutil functions...
r46227 wopts = logcmdutil.walkopts(
pats=pats,
opts=opts,
revspec=opts[b'rev'],
Yuya Nishihara
churn: leverage logcmdutil to filter revisions by --date
r46229 date=opts[b'date'],
Yuya Nishihara
cmdutil: rewrite walkchangerevs() by using logcmdutil functions...
r46227 include_pats=opts[b'include'],
exclude_pats=opts[b'exclude'],
)
revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
for ctx in cmdutil.walkchangerevs(repo, revs, makefilematcher, prep):
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 continue
Martin von Zweigbergk
churn: use progess helper...
r38420 progress.complete()
Patrick Mezard
Make churn an official extension
r6348
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 return rate
Augie Fackler
formatting: blacken the codebase...
r43346 @command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'churn',
Augie Fackler
formatting: blacken the codebase...
r43346 [
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'r',
b'rev',
Augie Fackler
formatting: blacken the codebase...
r43346 [],
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'count rate for the specified revision or revset'),
_(b'REV'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'd',
b'date',
b'',
_(b'count rate for revisions matching date spec'),
_(b'DATE'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b't',
b'oldtemplate',
b'',
_(b'template to group changesets (DEPRECATED)'),
_(b'TEMPLATE'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'T',
b'template',
b'{author|email}',
_(b'template to group changesets'),
_(b'TEMPLATE'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'f',
b'dateformat',
b'',
_(b'strftime-compatible format for grouping by date'),
_(b'FORMAT'),
Augie Fackler
formatting: blacken the codebase...
r43346 ),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'c', b'changesets', False, _(b'count rate by number of changesets')),
(b's', b'sort', False, _(b'sort by key (default: sort by count)')),
(b'', b'diffstat', False, _(b'display added/removed lines separately')),
(b'', b'aliases', b'', _(b'file with email aliases'), _(b'FILE')),
Augie Fackler
formatting: blacken the codebase...
r43346 ]
+ cmdutil.walkopts,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]"),
rdamazio@google.com
help: assigning categories to existing commands...
r40329 helpcategory=command.CATEGORY_MAINTENANCE,
Augie Fackler
formatting: blacken the codebase...
r43346 inferrepo=True,
)
Alexander Solovyov
churn and stats commands merged
r7070 def churn(ui, repo, *pats, **opts):
Cédric Duval
churn: improve description...
r8823 '''histogram of changes to the repository
Patrick Mezard
Make churn an official extension
r6348
Cédric Duval
churn: improve description...
r8823 This command will display a histogram representing the number
of changed lines or revisions, grouped according to the given
template. The default template will group changes by author.
The --dateformat option may be used to group the results by
date instead.
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065
Cédric Duval
churn: improve description...
r8823 Statistics are based on the number of changed lines, or
alternatively the number of matching revisions if the
--changesets option is specified.
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065
Martin Geisler
churn: use reST syntax for literal blocks
r9205 Examples::
Dirkjan Ochtman
convert comments to docstrings in a bunch of extensions
r6666
Alexander Solovyov
churn and stats commands merged
r7070 # display count of changed lines for every committer
Matt Harbison
churn: use the non-deprecated template option in the examples
r32229 hg churn -T "{author|email}"
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065
# display daily activity graph
FUJIWARA Katsunori
doc: use double quotation mark to quote arguments in examples for Windows users...
r19959 hg churn -f "%H" -s -c
Dirkjan Ochtman
convert comments to docstrings in a bunch of extensions
r6666
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 # display activity of developers by month
FUJIWARA Katsunori
doc: use double quotation mark to quote arguments in examples for Windows users...
r19959 hg churn -f "%Y-%m" -s -c
Patrick Mezard
Make churn an official extension
r6348
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 # display count of lines changed in every year
FUJIWARA Katsunori
doc: use double quotation mark to quote arguments in examples for Windows users...
r19959 hg churn -f "%Y" -s
Alexander Solovyov
churn and stats commands merged
r7070
"Stephane"
churn: add an usage example in docstring
r46047 # display count of lines changed in a time range
hg churn -d "2020-04 to 2020-09"
Cédric Duval
churn: improve description...
r8823 It is possible to map alternate email addresses to a main address
Martin Geisler
churn: wrap docstrings at 70 characters
r9254 by providing a file using the following format::
Dirkjan Ochtman
kill trailing whitespace
r8843
Alexander Solovyov
churn: support spaces in aliases (issue2222)
r11264 <alias email> = <actual email>
Martin Geisler
churn: use .hgchurn in repo root as default map file
r8254
Martin Geisler
churn: wrap docstrings at 70 characters
r9254 Such a file may be specified with the --aliases option, otherwise
a .hgchurn file will be looked for in the working directory root.
Matthew Turk
churn: split email aliases from the right...
r19464 Aliases will be split from the rightmost "=".
Martin Geisler
churn: use .hgchurn in repo root as default map file
r8254 '''
Augie Fackler
formatting: blacken the codebase...
r43346
Patrick Mezard
Make churn an official extension
r6348 def pad(s, l):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return s + b" " * (l - encoding.colwidth(s))
Patrick Mezard
Make churn an official extension
r6348
amap = {}
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 aliases = opts.get('aliases')
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not aliases and os.path.exists(repo.wjoin(b'.hgchurn')):
aliases = repo.wjoin(b'.hgchurn')
Patrick Mezard
Make churn an official extension
r6348 if aliases:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for l in open(aliases, b"rb"):
Martin Geisler
churn: do not crash on malformed lines in alias file
r12069 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 alias, actual = l.rsplit(b'=' in l and b'=' or None, 1)
Martin Geisler
churn: do not crash on malformed lines in alias file
r12069 amap[alias.strip()] = actual.strip()
except ValueError:
l = l.strip()
if l:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"skipping malformed alias: %s\n") % l)
Ronny Pfannschmidt
churn: do not crash on empty lines in alias file
r12068 continue
Patrick Mezard
Make churn an official extension
r6348
Pulkit Goyal
py3: convert dict.items() to list explicitly...
r36410 rate = list(countrate(ui, repo, amap, *pats, **opts).items())
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065 if not rate:
Patrick Mezard
Make churn an official extension
r6348 return
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 if opts.get('sort'):
Mads Kiilerich
churn: sort users with same churn by name...
r18369 rate.sort()
else:
rate.sort(key=lambda x: (-sum(x[1]), x))
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065
Nicolas Dumazet
churn: issue833 was reintroduced in 9bc46d069a76, correct it and add a test
r9388 # Be careful not to have a zero maxcount (issue833)
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 maxcount = float(max(sum(v) for k, v in rate)) or 1.0
Nicolas Dumazet
churn: use genexps now that we dropped 2.3 compatibility
r9390 maxname = max(len(k) for k, v in rate)
Patrick Mezard
Make churn an official extension
r6348
Augie Fackler
termwidth: move to ui.ui from util
r12689 ttywidth = ui.termwidth()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b"assuming %i character terminal\n" % ttywidth)
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 width = ttywidth - maxname - 2 - 2 - 2
Alexander Solovyov
churn: generalisation, now it is possible to see statistics grouped by custom template
r7065
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 if opts.get('diffstat'):
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 width -= 15
Augie Fackler
formatting: blacken the codebase...
r43346
Renato Cunha
churn: remove tuple parameter unpacking (deprecated in py3k)
r11501 def format(name, diffstat):
added, removed = diffstat
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"%s %15s %s%s\n" % (
Augie Fackler
formatting: blacken the codebase...
r43346 pad(name, maxname),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'+%d/-%d' % (added, removed),
ui.label(b'+' * charnum(added), b'diffstat.inserted'),
ui.label(b'-' * charnum(removed), b'diffstat.deleted'),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 else:
width -= 6
Augie Fackler
formatting: blacken the codebase...
r43346
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669 def format(name, count):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b"%s %6d %s\n" % (
Augie Fackler
formatting: blacken the codebase...
r43346 pad(name, maxname),
sum(count),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'*' * charnum(sum(count)),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669
def charnum(count):
Augie Fackler
churn: remove redundant round()...
r40300 return int(count * width // maxcount)
Alexander Solovyov
churn: ability to display added/removed lines separately
r9669
for name, count in rate:
Steve Borho
Backed out changeset: e1dde7363601
r11310 ui.write(format(name, count))