diff --git a/gitinspector/blame.py b/gitinspector/blame.py index 3c964cbe..76797b48 100644 --- a/gitinspector/blame.py +++ b/gitinspector/blame.py @@ -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() @@ -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. @@ -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() @@ -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 diff --git a/gitinspector/config.py b/gitinspector/config.py index 4eaf15c6..12da453b 100644 --- a/gitinspector/config.py +++ b/gitinspector/config.py @@ -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]: diff --git a/gitinspector/gitinspector.py b/gitinspector/gitinspector.py index b725fb23..c6368be7 100644 --- a/gitinspector/gitinspector.py +++ b/gitinspector/gitinspector.py @@ -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__) @@ -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: @@ -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. @@ -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 diff --git a/gitinspector/output/blameoutput.py b/gitinspector/output/blameoutput.py index f49ee63b..c23f2aa4 100644 --- a/gitinspector/output/blameoutput.py +++ b/gitinspector/output/blameoutput.py @@ -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 = "
" blame_xml += "

" + _(BLAME_INFO_TEXT) + ".

" - blame_xml += "".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 = "" + else: + formtup = (_("Author"), _("Rows"), _("Stability"), _("Age"), _("% in comments")) + formmkup = "" + blame_xml += formmkup.format(*formtup) blame_xml += "" chart_data = "" blames = sorted(self.blame.get_summed_blames().items()) @@ -64,7 +70,9 @@ def output_html(self): blame_xml += "" blame_xml += "") - blame_xml += "" + if self.forcemonths and self.blame.useweeks: + blame_xml += "" + blame_xml += "" blame_xml += "" blame_xml += "" blame_xml += "" @@ -73,7 +81,7 @@ def output_html(self): if blames[-1] != entry: chart_data += ", " - blame_xml += "
{0} {1} {2} {3} {4}
{0} {1} {2} {3} {4} {5}
{0} {1} {2} {3} {4}
" + str(entry[1].rows) + "" + ("{0:.1f}".format(Blame.get_stability(entry[0], entry[1].rows, self.changes)) + "" + "{0:.1f}".format(float(entry[1].skew) / entry[1].rows) + "" + "{0:.1f}".format(float(entry[1].get_skew(True)) / entry[1].rows) + "" + "{0:.1f}".format(float(entry[1].get_skew()) / entry[1].rows) + "" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "" + work_percentage + "
 
" + blame_xml += "   " % len(formtup) blame_xml += "
" blame_xml += "