Rev 18: Add credits command, test classify code by default, add comments to classify code. in file:///data/jelmer/bzr-stats/trunk/
Jelmer Vernooij
jelmer at samba.org
Sat Jun 28 21:08:00 BST 2008
At file:///data/jelmer/bzr-stats/trunk/
------------------------------------------------------------
revno: 18
revision-id: jelmer at samba.org-20080628200745-a3zl9e16u38789dd
parent: jelmer at samba.org-20080628190844-wvhafwcu0za9mg2v
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: trunk
timestamp: Sat 2008-06-28 22:07:45 +0200
message:
Add credits command, test classify code by default, add comments to classify code.
modified:
__init__.py __init__.py-20060629132721-mkbaty0vfk4y3v59-1
classify.py classify.py-20080628185133-8xhhatnjpbn0efxq-1
=== modified file '__init__.py'
--- a/__init__.py 2008-06-28 19:08:44 +0000
+++ b/__init__.py 2008-06-28 20:07:45 +0000
@@ -9,10 +9,13 @@
commands,
config,
errors,
+ option,
tsort,
ui,
workingtree,
)
+from bzrlib.plugins.stats.classify import classify_delta
+from itertools import izip
""")
from bzrlib import lazy_regex
@@ -268,13 +271,118 @@
commands.register_command(cmd_ancestor_growth)
+def gather_class_stats(repository, revs):
+ ret = {}
+ total = 0
+ pb = ui.ui_factory.nested_progress_bar()
+ try:
+ repository.lock_read()
+ try:
+ i = 0
+ for delta in repository.get_deltas_for_revisions(revs):
+ pb.update("classifying commits", i, len(revs))
+ for c in classify_delta(delta):
+ if not c in ret:
+ ret[c] = 0
+ ret[c] += 1
+ total += 1
+ i += 1
+ finally:
+ repository.unlock()
+ finally:
+ pb.finished()
+ return ret, total
+
+
+def display_credits(credits):
+ (coders, documenters, artists, translators) = credits
+ def print_section(name, lst):
+ if len(lst) == 0:
+ return
+ print "%s:" % name
+ for name in lst:
+ print "%s" % name
+ print ""
+ print_section("Code", coders)
+ print_section("Documentation", documenters)
+ print_section("Art", artists)
+ print_section("Translations", translators)
+
+
+def find_credits(repository, revid):
+ """Find the credits of the contributors to a revision.
+
+ :return: tuple with (authors, documenters, artists, translators)
+ """
+ ret = {"documentation": {},
+ "code": {},
+ "art": {},
+ "translation": {},
+ None: {}
+ }
+ repository.lock_read()
+ try:
+ ancestry = filter(lambda x: x is not None, repository.get_ancestry(revid))
+ pb = ui.ui_factory.nested_progress_bar()
+ try:
+ revs = repository.get_revisions(ancestry)
+ for rev,delta in izip(revs, repository.get_deltas_for_revisions(revs)):
+ # Don't count merges
+ if len(rev.parent_ids) > 1:
+ continue
+ for c in set(classify_delta(delta)):
+ author = rev.get_apparent_author()
+ if not author in ret[c]:
+ ret[c][author] = 0
+ ret[c][author] += 1
+ finally:
+ pb.finished()
+ finally:
+ repository.unlock()
+ def sort_class(name):
+ return map(lambda (x,y): x, sorted(ret[name].items(), lambda x,y: cmp((x[1], x[0]), (y[1], y[0]))))
+ return (sort_class("code"), sort_class("documentation"), sort_class("art"), sort_class("translation"))
+
+
+class cmd_credits(commands.Command):
+ """Determine credits for LOCATION."""
+
+ takes_args = ['location?']
+ takes_options = ['revision']
+
+ encoding_type = 'replace'
+
+ def run(self, location='.', revision=None):
+ try:
+ wt = workingtree.WorkingTree.open_containing(location)[0]
+ except errors.NoWorkingTree:
+ a_branch = branch.Branch.open(location)
+ last_rev = a_branch.last_revision()
+ else:
+ a_branch = wt.branch
+ last_rev = wt.last_revision()
+
+ if revision is not None:
+ last_rev = revision[0].in_history(a_branch).rev_id
+
+ a_branch.lock_read()
+ try:
+ credits = find_credits(a_branch.repository, last_rev)
+ display_credits(credits)
+ finally:
+ a_branch.unlock()
+
+
+commands.register_command(cmd_credits)
+
+
def test_suite():
from unittest import TestSuite
from bzrlib.tests import TestLoader
import test_stats
suite = TestSuite()
loader = TestLoader()
- testmod_names = ['test_stats']
+ testmod_names = ['test_stats', 'test_classify']
suite.addTest(loader.loadTestsFromModuleNames(['%s.%s' % (__name__, i) for i in testmod_names]))
return suite
=== modified file 'classify.py'
--- a/classify.py 2008-06-28 18:54:37 +0000
+++ b/classify.py 2008-06-28 20:07:45 +0000
@@ -1,6 +1,8 @@
"""Classify a commit based on the types of files it changed."""
from bzrlib import urlutils
+from bzrlib.trace import mutter
+
def classify_filename(name):
"""Classify a file based on its name.
@@ -9,25 +11,37 @@
:return: One of code, documentation, translation or art.
None if determining the file type failed.
"""
- # FIXME: Use mime types?
+ # FIXME: Use mime types? Ohcount?
basename = urlutils.basename(name)
try:
extension = basename.split(".")[1]
- if extension in ("c", "py", "cpp", "rb"):
+ if extension in ("c", "h", "py", "cpp", "rb", "ac"):
return "code"
- if extension in ("html", "xml", "txt", "rst"):
+ if extension in ("html", "xml", "txt", "rst", "TODO"):
return "documentation"
if extension in ("po"):
return "translation"
if extension in ("svg", "png", "jpg"):
return "art"
except IndexError:
- if basename in ("README", "NEWS", "TODO"):
+ if basename in ("README", "NEWS", "TODO",
+ "AUTHORS", "COPYING"):
return "documentation"
+ if basename in ("Makefile"):
+ return "code"
+ mutter("don't know how to classify %s", name)
return None
+
def classify_delta(delta):
+ """Determine what sort of changes a delta contains.
+
+ :param delta: A TreeDelta to inspect
+ :return: List with classes found (see classify_filename)
+ """
+ # TODO: This is inaccurate, since it doesn't look at the
+ # number of lines changed in a file.
types = []
for d in delta.added + delta.modified:
types.append(classify_filename(d[0]))
More information about the bazaar-commits
mailing list