Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new "-M" option, so that -wM would produce both weekly and monthly #104

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions gitinspector/blame.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,18 @@

class BlameEntry(object):
rows = 0
skew = 0 # Used when calculating average code age.
skew_w = 0 # Used when calculating average code age.
skew_m = 0 # Used when calculating average code age.
comments = 0
useweeks = None

def __init__(self, useweeks):
self.useweeks = useweeks

def get_skew(self, forcemonths = False):
if not self.useweeks or forcemonths:
return self.skew_m
return self.skew_w

__thread_lock__ = threading.BoundedSemaphore(NUM_THREADS)
__blame_lock__ = threading.Lock()
Expand Down Expand Up @@ -79,14 +89,15 @@ def __handle_blamechunk_content__(self, content):
__blame_lock__.acquire() # Global lock used to protect calls from here...

if self.blames.get((author, self.filename), None) == None:
self.blames[(author, self.filename)] = BlameEntry()
self.blames[(author, self.filename)] = BlameEntry(self.useweeks)

self.blames[(author, self.filename)].comments += comments
self.blames[(author, self.filename)].rows += 1

if (self.blamechunk_time - self.changes.first_commit_date).days > 0:
self.blames[(author, self.filename)].skew += ((self.changes.last_commit_date - self.blamechunk_time).days /
(7.0 if self.useweeks else AVG_DAYS_PER_MONTH))
skew = (self.changes.last_commit_date - self.blamechunk_time).days;
self.blames[(author, self.filename)].skew_w += (skew / 7.0)
self.blames[(author, self.filename)].skew_m += (skew / AVG_DAYS_PER_MONTH)

__blame_lock__.release() # ...to here.

Expand Down Expand Up @@ -123,6 +134,7 @@ def run(self):
class Blame(object):
def __init__(self, repo, hard, useweeks, changes):
self.blames = {}
self.useweeks = useweeks
ls_tree_r = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1,
stdout=subprocess.PIPE).stdout
lines = ls_tree_r.readlines()
Expand Down Expand Up @@ -190,10 +202,11 @@ def get_summed_blames(self):
summed_blames = {}
for i in self.blames.items():
if summed_blames.get(i[0][0], None) == None:
summed_blames[i[0][0]] = BlameEntry()
summed_blames[i[0][0]] = BlameEntry(self.useweeks)

summed_blames[i[0][0]].rows += i[1].rows
summed_blames[i[0][0]].skew += i[1].skew
summed_blames[i[0][0]].skew_w += i[1].skew_w
summed_blames[i[0][0]].skew_m += i[1].skew_m
summed_blames[i[0][0]].comments += i[1].comments

return summed_blames
1 change: 1 addition & 0 deletions gitinspector/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def read(self):
self.run.metrics = self.__read_git_config_bool__("metrics")
self.run.responsibilities = self.__read_git_config_bool__("responsibilities")
self.run.useweeks = self.__read_git_config_bool__("weeks")
self.run.forcemonths = self.__read_git_config_bool__("forcemonths")

var = self.__read_git_config_string__("since")
if var[0]:
Expand Down
13 changes: 10 additions & 3 deletions gitinspector/gitinspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(self):
self.grading = False
self.timeline = False
self.useweeks = False
self.forcemonths = False

def process(self, repos):
localization.check_compatibility(version.__version__)
Expand Down Expand Up @@ -83,9 +84,11 @@ def process(self, repos):
outputable.output(ChangesOutput(summed_changes))

if changes.get_commits():
outputable.output(BlameOutput(summed_changes, summed_blames))
outputable.output(BlameOutput(summed_changes, summed_blames, self.forcemonths))

if self.timeline:
if self.useweeks and self.forcemonths:
outputable.output(TimelineOutput(summed_changes, False))
outputable.output(TimelineOutput(summed_changes, self.useweeks))

if self.include_metrics:
Expand Down Expand Up @@ -133,10 +136,10 @@ def main():
repos = []

try:
opts, args = optval.gnu_getopt(argv[1:], "f:F:hHlLmrTwx:", ["exclude=", "file-types=", "format=",
opts, args = optval.gnu_getopt(argv[1:], "f:F:hHlLmrTwMx:", ["exclude=", "file-types=", "format=",
"hard:true", "help", "list-file-types:true", "localize-output:true",
"metrics:true", "responsibilities:true", "since=", "grading:true",
"timeline:true", "until=", "version", "weeks:true"])
"timeline:true", "until=", "version", "weeks:true", "forcemonths:true"])
repos = __get_validated_git_repos__(set(args))

#We need the repos above to be set before we read the git config.
Expand Down Expand Up @@ -196,6 +199,10 @@ def main():
run.useweeks = True
elif o == "--weeks":
run.useweeks = optval.get_boolean_argument(a)
elif o == "-M":
run.forcemonths = True
elif o == "--forcemonths":
run.forcemonths = optval.get_boolean_argument(a)
elif o in("-x", "--exclude"):
if clear_x_on_next_pass:
clear_x_on_next_pass = False
Expand Down
60 changes: 46 additions & 14 deletions gitinspector/output/blameoutput.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,25 @@
"intact in the current revision")

class BlameOutput(Outputable):
def __init__(self, changes, blame):
def __init__(self, changes, blame, forcemonths):
if format.is_interactive_format():
print("")

self.changes = changes
self.blame = blame
self.forcemonths = forcemonths
Outputable.__init__(self)

def output_html(self):
blame_xml = "<div><div class=\"box\">"
blame_xml += "<p>" + _(BLAME_INFO_TEXT) + ".</p><div><table id=\"blame\" class=\"git\">"
blame_xml += "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th> </tr></thead>".format(
_("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments"))
if self.forcemonths and self.blame.useweeks:
formtup = (_("Author"), _("Rows"), _("Stability"), _("Age, months"), _("Age, weeks"), _("% in comments"))
formmkup = "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th> <th>{5}</th> </tr></thead>"
else:
formtup = (_("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments"))
formmkup = "<thead><tr> <th>{0}</th> <th>{1}</th> <th>{2}</th> <th>{3}</th> <th>{4}</th> </tr></thead>"
blame_xml += formmkup.format(*formtup)
blame_xml += "<tbody>"
chart_data = ""
blames = sorted(self.blame.get_summed_blames().items())
Expand All @@ -64,7 +70,9 @@ def output_html(self):

blame_xml += "<td>" + str(entry[1].rows) + "</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>"
if self.forcemonths and self.blame.useweeks:
blame_xml += "<td>" + "{0:.1f}".format(float(entry[1].get_skew(True)) / entry[1].rows) + "</td>"
blame_xml += "<td>" + "{0:.1f}".format(float(entry[1].get_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>"
blame_xml += "</tr>"
Expand All @@ -73,7 +81,7 @@ def output_html(self):
if blames[-1] != entry:
chart_data += ", "

blame_xml += "<tfoot><tr> <td colspan=\"5\">&nbsp;</td> </tr></tfoot></tbody></table>"
blame_xml += "<tfoot><tr> <td colspan=\"%d\">&nbsp;</td> </tr></tfoot></tbody></table>" % len(formtup)
blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div>"
blame_xml += "<script type=\"text/javascript\">"
blame_xml += " blame_plot = $.plot($(\"#blame_chart\"), [{0}], {{".format(chart_data)
Expand Down Expand Up @@ -107,7 +115,13 @@ def output_json(self):
rows_json = "\t\t\t\t\"rows\": " + str(i[1].rows) + ",\n"
stability_json = ("\t\t\t\t\"stability\": " + "{0:.1f}".format(Blame.get_stability(i[0], i[1].rows,
self.changes)) + ",\n")
age_json = ("\t\t\t\t\"age\": " + "{0:.1f}".format(float(i[1].skew) / i[1].rows) + ",\n")
if self.forcemonths and self.blame.useweeks:
age_json = ("\t\t\t\t\"age_months\": " + "{0:.1f}".format(float(i[1].get_skew(True)) / i[1].rows) + ",\n")
age_t_name = "age_weeks"
else:
age_json = ""
age_t_name = "age"
age_json += (("\t\t\t\t\"%s\": " % age_t_name) + "{0:.1f}".format(float(i[1].get_skew()) / i[1].rows) + ",\n")
percentage_in_comments_json = ("\t\t\t\t\"percentage_in_comments\": " +
"{0:.2f}".format(100.0 * i[1].comments / i[1].rows) + "\n")
blame_json += ("{\n" + name_json + email_json + gravatar_json + rows_json + stability_json + age_json +
Expand All @@ -122,15 +136,27 @@ def output_text(self):
terminal.clear_row()

print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
terminal.printb(terminal.ljust(_("Author"), 21) + terminal.rjust(_("Rows"), 10) + terminal.rjust(_("Stability"), 15) +
terminal.rjust(_("Age"), 13) + terminal.rjust(_("% in comments"), 20))
if self.forcemonths and self.blame.useweeks:
fparams = (18, 8, 10, 12, 14)
else:
fparams = (20, 10, 14, 12, 19)
auwidth, rwidth, swidth, awidth, cwidth = fparams
prints = terminal.ljust(_("Author"), auwidth + 1) + terminal.rjust(_("Rows"), rwidth) + terminal.rjust(_("Stability"), swidth + 1)
if self.forcemonths and self.blame.useweeks:
prints += terminal.rjust(_("Age, months"), awidth + 1) + terminal.rjust(_("Age, weeks"), awidth + 1)
else:
prints += terminal.rjust(_("Age"), awidth + 1)
prints += terminal.rjust(_("% in comments"), cwidth + 1)
terminal.printb(prints)

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.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))
print(terminal.ljust(i[0], auwidth)[0:auwidth - terminal.get_excess_column_count(i[0])], end=" ")
print(str(i[1].rows).rjust(rwidth), end=" ")
print("{0:.1f}".format(Blame.get_stability(i[0], i[1].rows, self.changes)).rjust(swidth), end=" ")
if self.forcemonths and self.blame.useweeks:
print("{0:.1f}".format(float(i[1].get_skew(True)) / i[1].rows).rjust(awidth), end=" ")
print("{0:.1f}".format(float(i[1].get_skew()) / i[1].rows).rjust(awidth), end=" ")
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(cwidth))

def output_xml(self):
message_xml = "\t\t<message>" + _(BLAME_INFO_TEXT) + "</message>\n"
Expand All @@ -145,7 +171,13 @@ def output_xml(self):
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
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")
if self.forcemonths and self.blame.useweeks:
age_xml = ("\t\t\t\t<age_months>" + "{0:.1f}".format(float(i[1].get_skew(True)) / i[1].rows) + "</age_months>\n")
age_t_name = "age_weeks"
else:
age_xml = ""
age_t_name = "age"
age_xml += (("\t\t\t\t<%s>" % age_t_name) + "{0:.1f}".format(float(i[1].get_skew()) / i[1].rows) + ("</%s>\n" % age_t_name))
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
"</percentage-in-comments>\n")
blame_xml += ("\t\t\t<author>\n" + name_xml + email_xml + gravatar_xml + rows_xml + stability_xml +
Expand Down
16 changes: 11 additions & 5 deletions gitinspector/output/timelineoutput.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
from .. import format, gravatar, terminal, timeline
from .outputable import Outputable

TIMELINE_INFO_TEXT = N_("The following history timeline has been gathered from the repository")
TIMELINE_INFO_TEXT_M = N_("The following monthly history timeline has been gathered from the repository")
TIMELINE_INFO_TEXT_W = N_("The following weekly history timeline has been gathered from the repository")
MODIFIED_ROWS_TEXT = N_("Modified Rows:")

def __output_row__text__(timeline_data, periods, names):
Expand Down Expand Up @@ -102,9 +103,14 @@ def __init__(self, changes, useweeks):
self.useweeks = useweeks
Outputable.__init__(self)

def get_tinfo_txt(self):
if self.useweeks:
return (_(TIMELINE_INFO_TEXT_W))
return (_(TIMELINE_INFO_TEXT_M))

def output_text(self):
if self.changes.get_commits():
print("\n" + textwrap.fill(_(TIMELINE_INFO_TEXT) + ":", width=terminal.get_size()[0]))
print("\n" + textwrap.fill(self.get_tinfo_txt() + ":", width=terminal.get_size()[0]))

timeline_data = timeline.TimelineData(self.changes, self.useweeks)
periods = timeline_data.get_periods()
Expand All @@ -123,7 +129,7 @@ def output_html(self):
max_periods_per_row = 8

timeline_xml = "<div><div id=\"timeline\" class=\"box\">"
timeline_xml += "<p>" + _(TIMELINE_INFO_TEXT) + ".</p>"
timeline_xml += "<p>" + self.get_tinfo_txt() + ".</p>"
print(timeline_xml)

for i in range(0, len(periods), max_periods_per_row):
Expand All @@ -134,7 +140,7 @@ def output_html(self):

def output_json(self):
if self.changes.get_commits():
message_json = "\t\t\t\"message\": \"" + _(TIMELINE_INFO_TEXT) + "\",\n"
message_json = "\t\t\t\"message\": \"" + self.get_tinfo_txt() + "\",\n"
timeline_json = ""
periods_json = "\t\t\t\"period_length\": \"{0}\",\n".format("week" if self.useweeks else "month")
periods_json += "\t\t\t\"periods\": [\n\t\t\t"
Expand Down Expand Up @@ -174,7 +180,7 @@ def output_json(self):

def output_xml(self):
if self.changes.get_commits():
message_xml = "\t\t<message>" + _(TIMELINE_INFO_TEXT) + "</message>\n"
message_xml = "\t\t<message>" + self.get_tinfo_txt() + "</message>\n"
timeline_xml = ""
periods_xml = "\t\t<periods length=\"{0}\">\n".format("week" if self.useweeks else "month")

Expand Down