Support for multiple repositories is near completion (See issue #24).

Only the metrics module is lacking support. While the rest should work,
please note that it is completely untested as of now and probably
has some rough edges.
This commit is contained in:
Adam Waldenberg 2015-10-31 05:10:00 +01:00
parent 46b21db196
commit 98615ccbfc
5 changed files with 45 additions and 41 deletions

View File

@ -148,6 +148,17 @@ class Blame(object):
for i in range(0, NUM_THREADS):
__thread_lock__.acquire()
# We also have to release them for future use.
for i in range(0, NUM_THREADS):
__thread_lock__.release()
def __add__(self, other):
if other == None:
return self
self.blames.update(other.blames)
return self
@staticmethod
def is_revision(string):
revision = re.search("([0-9a-f]{40})", string)
@ -180,12 +191,3 @@ class Blame(object):
summed_blames[i[0][0]].comments += i[1].comments
return summed_blames
__blame__ = None
def get(hard, useweeks, changes):
global __blame__
if __blame__ == None:
__blame__ = Blame(hard, useweeks, changes)
return __blame__

View File

@ -23,6 +23,7 @@ import atexit
import getopt
import os
import sys
from .blame import Blame
from .changes import Changes
from .config import GitConfig
from . import (basedir, clone, extensions, filtering, format, help, interval,
@ -58,13 +59,16 @@ class Runner(object):
terminal.skip_escapes(not sys.stdout.isatty())
terminal.set_stdout_encoding()
previous_directory = os.getcwd()
changes = None
summed_blames = None
summed_changes = None
for repo in repos:
os.chdir(previous_directory)
os.chdir(repo)
absolute_path = basedir.get_basedir_git()
changes = Changes(self.hard) + changes
changes = Changes(self.hard)
summed_blames = Blame(self.hard, self.useweeks, changes) + summed_blames
summed_changes = changes + summed_changes
if sys.stdout.isatty() and format.is_interactive_format():
terminal.clear_row()
@ -75,16 +79,16 @@ class Runner(object):
outputable.output(ChangesOutput(changes))
if changes.get_commits():
outputable.output(BlameOutput(changes, self.hard, self.useweeks))
outputable.output(BlameOutput(summed_changes, summed_blames))
if self.timeline:
outputable.output(TimelineOutput(changes, self.useweeks))
outputable.output(TimelineOutput(summed_changes, self.useweeks))
if self.include_metrics:
outputable.output(MetricsOutput())
if self.responsibilities:
outputable.output(ResponsibilitiesOutput(changes, self.hard, self.useweeks))
outputable.output(ResponsibilitiesOutput(summed_changes, summed_blames))
outputable.output(FilteringOutput())

View File

@ -23,21 +23,20 @@ import json
import sys
import textwrap
from ..localization import N_
from .. import blame, format, gravatar, terminal
from .. import format, gravatar, terminal
from ..blame import Blame
from .outputable import Outputable
BLAME_INFO_TEXT = N_("Below are the number of rows from each author that have survived and are still "
"intact in the current revision")
class BlameOutput(Outputable):
def __init__(self, changes, hard, useweeks):
def __init__(self, changes, blame):
if format.is_interactive_format():
print("")
self.changes = changes
self.hard = hard
self.useweeks = useweeks
blame.get(self.hard, self.useweeks, self.changes)
self.blame = blame
Outputable.__init__(self)
def output_html(self):
@ -47,7 +46,7 @@ class BlameOutput(Outputable):
_("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments"))
blame_xml += "<tbody>"
chart_data = ""
blames = sorted(blame.__blame__.get_summed_blames().items())
blames = sorted(self.blame.get_summed_blames().items())
total_blames = 0
for i in blames:
@ -64,7 +63,7 @@ class BlameOutput(Outputable):
blame_xml += "<td>" + entry[0] + "</td>"
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
blame_xml += "<td>" + ("{0:.1f}".format(blame.Blame.get_stability(entry[0], entry[1].rows, self.changes)) + "</td>")
blame_xml += "<td>" + ("{0:.1f}".format(Blame.get_stability(entry[0], entry[1].rows, self.changes)) + "</td>")
blame_xml += "<td>" + "{0:.1f}".format(float(entry[1].skew) / entry[1].rows) + "</td>"
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
blame_xml += "<td style=\"display: none\">" + work_percentage + "</td>"
@ -99,13 +98,13 @@ class BlameOutput(Outputable):
message_xml = "\t\t\t\"message\": \"" + _(BLAME_INFO_TEXT) + "\",\n"
blame_xml = ""
for i in sorted(blame.__blame__.get_summed_blames().items()):
for i in sorted(self.blame.get_summed_blames().items()):
author_email = self.changes.get_latest_email_by_author(i[0])
name_xml = "\t\t\t\t\"name\": \"" + i[0] + "\",\n"
gravatar_xml = "\t\t\t\t\"gravatar\": \"" + gravatar.get_url(author_email) + "\",\n"
rows_xml = "\t\t\t\t\"rows\": " + str(i[1].rows) + ",\n"
stability_xml = ("\t\t\t\t\"stability\": " + "{0:.1f}".format(blame.Blame.get_stability(i[0], i[1].rows,
stability_xml = ("\t\t\t\t\"stability\": " + "{0:.1f}".format(Blame.get_stability(i[0], i[1].rows,
self.changes)) + ",\n")
age_xml = ("\t\t\t\t\"age\": " + "{0:.1f}".format(float(i[1].skew) / i[1].rows) + ",\n")
percentage_in_comments_xml = ("\t\t\t\t\"percentage-in-comments\": " + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
@ -125,10 +124,10 @@ class BlameOutput(Outputable):
terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Rows"), 10) + terminal.rjust(_("Stability"), 15) +
terminal.rjust(_("Age"), 13) + terminal.rjust(_("% in comments"), 20))
for i in sorted(blame.__blame__.get_summed_blames().items()):
for i in sorted(self.blame.get_summed_blames().items()):
print(terminal.ljust(i[0], 20)[0:20 - terminal.get_excess_column_count(i[0])], end=" ")
print(str(i[1].rows).rjust(10), end=" ")
print("{0:.1f}".format(blame.Blame.get_stability(i[0], i[1].rows, self.changes)).rjust(14), end=" ")
print("{0:.1f}".format(Blame.get_stability(i[0], i[1].rows, self.changes)).rjust(14), end=" ")
print("{0:.1f}".format(float(i[1].skew) / i[1].rows).rjust(12), end=" ")
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(19))
@ -136,13 +135,13 @@ class BlameOutput(Outputable):
message_xml = "\t\t<message>" + _(BLAME_INFO_TEXT) + "</message>\n"
blame_xml = ""
for i in sorted(blame.__blame__.get_summed_blames().items()):
for i in sorted(self.blame.get_summed_blames().items()):
author_email = self.changes.get_latest_email_by_author(i[0])
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(author_email) + "</gravatar>\n"
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
stability_xml = ("\t\t\t\t<stability>" + "{0:.1f}".format(blame.Blame.get_stability(i[0], i[1].rows,
stability_xml = ("\t\t\t\t<stability>" + "{0:.1f}".format(Blame.get_stability(i[0], i[1].rows,
self.changes)) + "</stability>\n")
age_xml = ("\t\t\t\t<age>" + "{0:.1f}".format(float(i[1].skew) / i[1].rows) + "</age>\n")
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +

View File

@ -21,7 +21,7 @@ from __future__ import print_function
from __future__ import unicode_literals
import textwrap
from ..localization import N_
from .. import blame, format, gravatar, terminal
from .. import format, gravatar, terminal
from .. import responsibilities as resp
from .outputable import Outputable
@ -31,18 +31,17 @@ RESPONSIBILITIES_INFO_TEXT = N_("The following responsibilities, by author, were
MOSTLY_RESPONSIBLE_FOR_TEXT = N_("is mostly responsible for")
class ResponsibilitiesOutput(Outputable):
def __init__(self, changes, hard, useweeks):
def __init__(self, changes, blame):
self.changes = changes
self.hard = hard
self.useweeks = useweeks
self.blame = blame
Outputable.__init__(self)
def output_text(self):
print("\n" + textwrap.fill(_(RESPONSIBILITIES_INFO_TEXT) + ":", width=terminal.get_size()[0]))
for i in sorted(set(i[0] for i in blame.get(self.hard, self.useweeks, self.changes).blames)):
for i in sorted(set(i[0] for i in self.blame.blames)):
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.changes,
self.hard, self.useweeks, i)), reverse=True)
self.blame, i)), reverse=True)
if responsibilities:
print("\n" + i, _(MOSTLY_RESPONSIBLE_FOR_TEXT) + ":")
@ -60,9 +59,9 @@ class ResponsibilitiesOutput(Outputable):
resp_xml = "<div><div class=\"box\" id=\"responsibilities\">"
resp_xml += "<p>" + _(RESPONSIBILITIES_INFO_TEXT) + ".</p>"
for i in sorted(set(i[0] for i in blame.get(self.hard, self.useweeks, self.changes).blames)):
for i in sorted(set(i[0] for i in self.blame.blames)):
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.changes,
self.hard, self.useweeks, i)), reverse=True)
self.blame, i)), reverse=True)
if responsibilities:
resp_xml += "<div>"
@ -87,9 +86,9 @@ class ResponsibilitiesOutput(Outputable):
message_xml = "\t\t\t\"message\": \"" + _(RESPONSIBILITIES_INFO_TEXT) + "\",\n"
resp_xml = ""
for i in sorted(set(i[0] for i in blame.get(self.hard, self.useweeks, self.changes).blames)):
for i in sorted(set(i[0] for i in self.blame.blames)):
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.changes,
self.hard, self.useweeks, i)), reverse=True)
self.blame, i)), reverse=True)
if responsibilities:
author_email = self.changes.get_latest_email_by_author(i)
@ -118,9 +117,9 @@ class ResponsibilitiesOutput(Outputable):
message_xml = "\t\t<message>" + _(RESPONSIBILITIES_INFO_TEXT) + "</message>\n"
resp_xml = ""
for i in sorted(set(i[0] for i in blame.get(self.hard, self.useweeks, self.changes).blames)):
for i in sorted(set(i[0] for i in self.blame.blames)):
responsibilities = sorted(((i[1], i[0]) for i in resp.Responsibilities.get(self.changes,
self.hard, self.useweeks, i)), reverse=True)
self.blame, i)), reverse=True)
if responsibilities:
author_email = self.changes.get_latest_email_by_author(i)

View File

@ -26,10 +26,10 @@ class ResponsibiltyEntry(object):
class Responsibilities(object):
@staticmethod
def get(changes, hard, useweeks, author_name):
def get(changes, blame, author_name):
author_blames = {}
for i in blame.get(hard, useweeks, changes).blames.items():
for i in blame.blames.items():
if author_name == i[0][0]:
total_rows = i[1].rows - i[1].comments
if total_rows > 0: