1
0
Fork 0
mirror of https://github.com/ejwa/gitinspector.git synced 2025-03-24 09:18:06 +01:00

Added an Outputable class and worked a little more on the HTML output.

The Outputable class is now the base class of all the classes that want to
output formatted text. This is more object oriented and cleaner solution
compared to the previous implementation.
This commit is contained in:
Adam Waldenberg 2013-03-11 00:23:50 +01:00
parent 267a00dae4
commit 37c4260149
11 changed files with 350 additions and 269 deletions

116
blame.py
View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
from changes import FileDiff from changes import FileDiff
import comment import comment
import filtering import filtering
@ -146,72 +147,77 @@ def get(hard):
__blame_info_text__ = ("Below are the number of rows from each author that have survived and are still " __blame_info_text__ = ("Below are the number of rows from each author that have survived and are still "
"intact in the current revision") "intact in the current revision")
def output_html(hard): class BlameOutput(Outputable):
get(hard) def __init__(self, hard):
self.hard = hard
Outputable.__init__(self)
blame_xml = "<div class=\"box statistics\">" def output_html(self):
blame_xml += "<p>" + __blame_info_text__ + ".</p><div><table class=\"git\">" get(self.hard)
blame_xml += "<thead><tr> <th>Author</th> <th>Rows</th> <th>% in comments</th> </tr></thead>"
blame_xml += "<tbody>"
chart_data = ""
blames = sorted(__blame__.get_summed_blames().items())
total_blames = 0
for i in blames: blame_xml = "<div class=\"statistics right\"><div class=\"box\">"
total_blames += i[1].rows blame_xml += "<p>" + __blame_info_text__ + ".</p><div><table class=\"git\">"
blame_xml += "<thead><tr> <th>Author</th> <th>Rows</th> <th>% in comments</th> </tr></thead>"
blame_xml += "<tbody>"
chart_data = ""
blames = sorted(__blame__.get_summed_blames().items())
total_blames = 0
for i, entry in enumerate(blames): for i in blames:
blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">") total_blames += i[1].rows
blame_xml += "<td>" + entry[0] + "</td>"
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
blame_xml += "</tr>"
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry[0], "{0:.2f}".format(100.0 * entry[1].rows / total_blames))
if blames[-1] != entry: for i, entry in enumerate(blames):
chart_data += ", " blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
blame_xml += "<td>" + entry[0] + "</td>"
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
blame_xml += "</tr>"
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry[0], "{0:.2f}".format(100.0 * entry[1].rows / total_blames))
blame_xml += "<tfoot><tr> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr></tfoot></tbody></table>" if blames[-1] != entry:
blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div></div>" chart_data += ", "
blame_xml += "<script type=\"text/javascript\">" blame_xml += "<tfoot><tr> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr></tfoot></tbody></table>"
blame_xml += " $.plot($(\"#blame_chart\"), [{0}], {{".format(chart_data) blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div></div></div>"
blame_xml += " series: {"
blame_xml += " pie: {"
blame_xml += " innerRadius: 0.4,"
blame_xml += " show: true"
blame_xml += " }"
blame_xml += " }"
blame_xml += " });"
blame_xml += "</script>"
print(blame_xml) blame_xml += "<script type=\"text/javascript\">"
blame_xml += " $.plot($(\"#blame_chart\"), [{0}], {{".format(chart_data)
blame_xml += " series: {"
blame_xml += " pie: {"
blame_xml += " innerRadius: 0.4,"
blame_xml += " show: true"
blame_xml += " }"
blame_xml += " }"
blame_xml += " });"
blame_xml += "</script>"
def output_text(hard): print(blame_xml)
print("")
get(hard)
if hard and sys.stdout.isatty(): def output_text(self):
terminal.clear_row() print("")
get(self.hard)
print(textwrap.fill(__blame_info_text__ + ":", width=terminal.get_size()[0]) + "\n") if self.hard and sys.stdout.isatty():
terminal.printb("Author".ljust(21) + "Rows".rjust(10) + "% in comments".rjust(16)) terminal.clear_row()
for i in sorted(__blame__.get_summed_blames().items()):
print(i[0].ljust(20)[0:20], end=" ")
print(str(i[1].rows).rjust(10), end=" ")
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(15))
def output_xml(hard): print(textwrap.fill(__blame_info_text__ + ":", width=terminal.get_size()[0]) + "\n")
get(hard) terminal.printb("Author".ljust(21) + "Rows".rjust(10) + "% in comments".rjust(16))
for i in sorted(__blame__.get_summed_blames().items()):
print(i[0].ljust(20)[0:20], end=" ")
print(str(i[1].rows).rjust(10), end=" ")
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(15))
message_xml = "\t\t<message>" + __blame_info_text__ + "</message>\n" def output_xml(self):
blame_xml = "" get(self.hard)
for i in sorted(__blame__.get_summed_blames().items()): message_xml = "\t\t<message>" + __blame_info_text__ + "</message>\n"
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n" blame_xml = ""
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
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 + rows_xml + percentage_in_comments_xml + "\t\t\t</author>\n"
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>") for i in sorted(__blame__.get_summed_blames().items()):
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
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 + rows_xml + percentage_in_comments_xml + "\t\t\t</author>\n"
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>")

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import extensions import extensions
import filtering import filtering
import re import re
@ -151,60 +152,98 @@ def get(hard):
return __changes__ return __changes__
__historical_info_text__ = "The following historical commit information, by author, was found in the repository" __historical_info_text__ = "The following historical commit information, by author, was found in the repository"
__no_commited_files__ = "No commited files with the specified extensions were found"
def output_html(hard): class ChangesOutput(Outputable):
print("HTML output not yet supported.") def __init__(self, hard):
self.hard = hard
Outputable.__init__(self)
def output_text(hard): def output_html(self):
authorinfo_list = get(hard).get_authorinfo_list() authorinfo_list = get(self.hard).get_authorinfo_list()
total_changes = 0.0 total_changes = 0.0
changes_xml = "<div class=\"statistics right\"><div class=\"box\">"
for i in authorinfo_list: for i in authorinfo_list:
total_changes += authorinfo_list.get(i).insertions total_changes += authorinfo_list.get(i).insertions
total_changes += authorinfo_list.get(i).deletions total_changes += authorinfo_list.get(i).deletions
if authorinfo_list: if authorinfo_list:
print(textwrap.fill(__historical_info_text__ + ":", width=terminal.get_size()[0]) + "\n") changes_xml += "<p>" + __historical_info_text__ + ".</p><div><table class=\"git\">"
terminal.printb("Author".ljust(21) + "Commits " + "Insertions " + "Deletions " + "% of changes") changes_xml += ("<thead><tr> <th>Author</th> <th>Commits</th> <th>Insertions</th> <th>Deletions</th>" +
"<th>% of changes</th> </tr></thead>")
changes_xml += "<tbody>"
for i in sorted(authorinfo_list): for i, entry in enumerate(sorted(authorinfo_list)):
authorinfo = authorinfo_list.get(i) authorinfo = authorinfo_list.get(entry)
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100 percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
print(i.ljust(20)[0:20], end=" ") changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
print(str(authorinfo.commits).rjust(7), end=" ") changes_xml += "<td>" + entry + "</td>"
print(str(authorinfo.insertions).rjust(12), end=" ") changes_xml += "<td>" + str(authorinfo.commits) + "</td>"
print(str(authorinfo.deletions).rjust(11), end=" ") changes_xml += "<td>" + str(authorinfo.insertions) + "</td>"
print("{0:.2f}".format(percentage).rjust(14)) changes_xml += "<td>" + str(authorinfo.deletions) + "</td>"
else: changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>"
print("No commited files with the specified extensions were found.") changes_xml += "</tr>"
def output_xml(hard): changes_xml += ("<tfoot><tr> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td>" +
authorinfo_list = get(hard).get_authorinfo_list() "</tr></tfoot></tbody></table>")
total_changes = 0.0 changes_xml += "</div>"
else:
changes_xml += "<p>" + __no_commited_files__ + ".</p>"
for i in authorinfo_list: changes_xml += "</div></div>"
total_changes += authorinfo_list.get(i).insertions print(changes_xml)
total_changes += authorinfo_list.get(i).deletions
if authorinfo_list: def output_text(self):
message_xml = "\t\t<message>" + __historical_info_text__ + "</message>\n" authorinfo_list = get(self.hard).get_authorinfo_list()
changes_xml = "" total_changes = 0.0
for i in sorted(authorinfo_list): for i in authorinfo_list:
authorinfo = authorinfo_list.get(i) total_changes += authorinfo_list.get(i).insertions
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100 total_changes += authorinfo_list.get(i).deletions
name_xml = "\t\t\t\t<name>" + i + "</name>\n" if authorinfo_list:
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n" print(textwrap.fill(__historical_info_text__ + ":", width=terminal.get_size()[0]) + "\n")
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n" terminal.printb("Author".ljust(21) + "Commits " + "Insertions " + "Deletions " + "% of changes")
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
changes_xml += ("\t\t\t<author>\n" + name_xml + commits_xml + insertions_xml + for i in sorted(authorinfo_list):
deletions_xml + percentage_xml + "\t\t\t</author>\n") authorinfo = authorinfo_list.get(i)
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>") print(i.ljust(20)[0:20], end=" ")
else: print(str(authorinfo.commits).rjust(7), end=" ")
print("\t<changes>\n\t\t<exception>" + "No commited files with the specified extensions were found." + print(str(authorinfo.insertions).rjust(12), end=" ")
"</exception>\n\t</changes>") print(str(authorinfo.deletions).rjust(11), end=" ")
print("{0:.2f}".format(percentage).rjust(14))
else:
print(__no_commited_files__ + ".")
def output_xml(self):
authorinfo_list = get(self.hard).get_authorinfo_list()
total_changes = 0.0
for i in authorinfo_list:
total_changes += authorinfo_list.get(i).insertions
total_changes += authorinfo_list.get(i).deletions
if authorinfo_list:
message_xml = "\t\t<message>" + __historical_info_text__ + "</message>\n"
changes_xml = ""
for i in sorted(authorinfo_list):
authorinfo = authorinfo_list.get(i)
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
name_xml = "\t\t\t\t<name>" + i + "</name>\n"
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n"
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n"
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
changes_xml += ("\t\t\t<author>\n" + name_xml + commits_xml + insertions_xml +
deletions_xml + percentage_xml + "\t\t\t</author>\n")
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>")
else:
print("\t<changes>\n\t\t<exception>" + __no_commited_files__ + "</exception>\n\t</changes>")

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import terminal import terminal
import textwrap import textwrap
@ -38,32 +39,30 @@ def add_located(string):
__extensions_info_text__ = "The extensions below were found in the repository history" __extensions_info_text__ = "The extensions below were found in the repository history"
def output_html(): class Extensions(Outputable):
print("HTML output not yet supported.") def output_text(self):
if __located_extensions__:
print("\n" + textwrap.fill(__extensions_info_text__ + "\n(extensions used during statistical analysis are marked):",
width=terminal.get_size()[0]))
def output_text(): for i in __located_extensions__:
if __located_extensions__: if i in __extensions__:
print("\n" + textwrap.fill(__extensions_info_text__ + "\n(extensions used during statistical analysis are marked):", print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ")
width=terminal.get_size()[0])) else:
print (i, end=" ")
print("")
for i in __located_extensions__: def output_xml(self):
if i in __extensions__: if __located_extensions__:
print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ") message_xml = "\t\t<message>" + __extensions_info_text__ + "</message>\n"
else: used_extensions_xml = ""
print (i, end=" ") unused_extensions_xml = ""
print("")
def output_xml(): for i in __located_extensions__:
if __located_extensions__: if i in __extensions__:
message_xml = "\t\t<message>" + __extensions_info_text__ + "</message>\n" used_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
used_extensions_xml = "" else:
unused_extensions_xml = "" unused_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
for i in __located_extensions__: print("\t<extensions>\n" + "\t\t<used>\n" + used_extensions_xml + "\t\t</used>\n" +
if i in __extensions__: "\t\t<unused>\n" + unused_extensions_xml + "\t\t</unused>\n" + "\t</extensions>")
used_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
else:
unused_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n"
print("\t<extensions>\n" + "\t\t<used>\n" + used_extensions_xml + "\t\t</used>\n" +
"\t\t<unused>\n" + unused_extensions_xml + "\t\t</unused>\n" + "\t</extensions>")

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import terminal import terminal
import textwrap import textwrap
@ -46,23 +47,21 @@ def set_filtered(file_name):
__filtering_info_text__ = ("The following files were excluded from the statistics due to the" __filtering_info_text__ = ("The following files were excluded from the statistics due to the"
"specified exclusion patterns") "specified exclusion patterns")
def output_html(): class Filtering(Outputable):
print("HTML output not yet supported.") def output_text(self):
if __filtered_files__:
print("\n" + textwrap.fill(__filtering_info_text__ + ":", width=terminal.get_size()[0]))
def output_text(): for i in __filtered_files__:
if __filtered_files__: (width, _) = terminal.get_size()
print("\n" + textwrap.fill(__filtering_info_text__ + ":", width=terminal.get_size()[0])) print("...%s" % i[-width+3:] if len(i) > width else i)
for i in __filtered_files__: def output_xml(self):
(width, _) = terminal.get_size() if __filtered_files__:
print("...%s" % i[-width+3:] if len(i) > width else i) message_xml = "\t\t<message>" + __filtering_info_text__ + "</message>\n"
filtering_xml = ""
def output_xml(): for i in __filtered_files__:
if __filtered_files__: filtering_xml += "\t\t\t<file>" + i + "</file>\n"
message_xml = "\t\t<message>" + __filtering_info_text__ + "</message>\n"
filtering_xml = ""
for i in __filtered_files__: print("\t<filering>\n" + message_xml + "\t\t<files>\n" + filtering_xml + "\t\t</files>\n\t</filtering>")
filtering_xml += "\t\t\t<file>" + i + "</file>\n"
print("\t<filering>\n" + message_xml + "\t\t<files>\n" + filtering_xml + "\t\t</files>\n\t</filtering>")

View file

@ -18,11 +18,10 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
import version
import base64 import base64
import basedir import basedir
import os import os
import terminal
import version
import zipfile import zipfile
__available_formats__ = ["html", "text", "xml"] __available_formats__ = ["html", "text", "xml"]
@ -38,6 +37,9 @@ def select(format):
return format in __available_formats__ return format in __available_formats__
def get_selected():
return __selected_format__
def is_interactive_format(): def is_interactive_format():
return __selected_format__ == "text" return __selected_format__ == "text"
@ -75,11 +77,3 @@ def output_footer():
print(html_footer) print(html_footer)
elif __selected_format__ == "xml": elif __selected_format__ == "xml":
print("</gitinspector>") print("</gitinspector>")
def call_output_function(html_function, text_function, xml_function, *parameters):
if __selected_format__ == "html":
html_function(*parameters)
elif __selected_format__ == "text":
text_function(*parameters)
else:
xml_function(*parameters)

View file

@ -29,6 +29,7 @@ import help
import metrics import metrics
import missing import missing
import os import os
import outputable
import responsibilities import responsibilities
import sys import sys
import terminal import terminal
@ -51,27 +52,25 @@ class Runner:
previous_directory = os.getcwd() previous_directory = os.getcwd()
os.chdir(self.repo) os.chdir(self.repo)
format.output_header() format.output_header()
format.call_output_function(changes.output_html, changes.output_text, changes.output_xml, self.hard) outputable.output(changes.ChangesOutput(self.hard))
if changes.get(self.hard).get_commits(): if changes.get(self.hard).get_commits():
format.call_output_function(blame.output_html, blame.output_text, blame.output_xml, self.hard) outputable.output(blame.BlameOutput(self.hard))
if self.timeline: if self.timeline:
format.call_output_function(timeline.output_html, timeline.output_text, timeline.output_xml, outputable.output(timeline.Timeline(changes.get(self.hard), self.useweeks))
changes.get(self.hard), self.useweeks)
if self.include_metrics: if self.include_metrics:
format.call_output_function(metrics.output_html, metrics.output_text, metrics.output_xml) outputable.output(metrics.Metrics())
if self.responsibilities: if self.responsibilities:
format.call_output_function(responsibilities.output_html, responsibilities.output_text, outputable.output(responsibilities.ResponsibilitiesOutput(self.hard))
responsibilities.output_xml, self.hard)
format.call_output_function(missing.output_html, missing.output_text, missing.output_xml) outputable.output(missing.Missing())
format.call_output_function(filtering.output_html, filtering.output_text, filtering.output_xml) outputable.output(filtering.Filtering())
if self.list_file_types: if self.list_file_types:
format.call_output_function(extensions.output_html, extensions.output_text, extensions.output_xml) outputable.output(extensions.Extensions())
format.output_footer() format.output_footer()
os.chdir(previous_directory) os.chdir(previous_directory)

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
from changes import FileDiff from changes import FileDiff
import comment import comment
import filtering import filtering
@ -27,7 +28,7 @@ import subprocess
__metric_eloc__ = {"java": 500, "c": 500, "cpp": 500, "h": 300, "hpp": 300, "py": 500, "glsl": 1000, __metric_eloc__ = {"java": 500, "c": 500, "cpp": 500, "h": 300, "hpp": 300, "py": 500, "glsl": 1000,
"rb": 500, "js": 500, "sql": 1000, "xml": 1000} "rb": 500, "js": 500, "sql": 1000, "xml": 1000}
class Metrics: class MetricsLogic:
def __init__(self): def __init__(self):
self.eloc = {} self.eloc = {}
ls_tree_r = subprocess.Popen("git ls-tree --name-only -r HEAD", shell=True, bufsize=1, stdout=subprocess.PIPE).stdout ls_tree_r = subprocess.Popen("git ls-tree --name-only -r HEAD", shell=True, bufsize=1, stdout=subprocess.PIPE).stdout
@ -38,7 +39,7 @@ class Metrics:
if not missing.add(i.strip()): if not missing.add(i.strip()):
file_r = open(i.strip(), "rb") file_r = open(i.strip(), "rb")
extension = FileDiff.get_extension(i) extension = FileDiff.get_extension(i)
lines = Metrics.get_eloc(file_r, extension) lines = MetricsLogic.get_eloc(file_r, extension)
if __metric_eloc__.get(extension, None) != None and __metric_eloc__[extension] < lines: if __metric_eloc__.get(extension, None) != None and __metric_eloc__[extension] < lines:
self.eloc[i.strip()] = lines self.eloc[i.strip()] = lines
@ -63,31 +64,29 @@ class Metrics:
__eloc_info_text__ = "The following files are suspiciously big (in order of severity)" __eloc_info_text__ = "The following files are suspiciously big (in order of severity)"
__metrics_missing_info_text__ = "No metrics violations were found in the repository" __metrics_missing_info_text__ = "No metrics violations were found in the repository"
def output_html(): class Metrics(Outputable):
print("HTML output not yet supported.") def output_text(self):
metrics_logic = MetricsLogic()
def output_text(): if not metrics_logic.eloc:
metrics = Metrics() print("\n" + __metrics_missing_info_text__ + ".")
else:
print("\n" + __eloc_info_text__ + ":")
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse = True):
print(i[1] + " (" + str(i[0]) + " eloc)")
if not metrics.eloc: def output_xml(self):
print("\n" + __metrics_missing_info_text__ + ".") metrics_logic = MetricsLogic()
else:
print("\n" + __eloc_info_text__ + ":")
for i in sorted(set([(j, i) for (i, j) in metrics.eloc.items()]), reverse = True):
print(i[1] + " (" + str(i[0]) + " eloc)")
def output_xml(): if not metrics_logic.eloc:
metrics = Metrics() print("\t<metrics>\n\t\t<message>" + __metrics_missing_info_text__ + "</message>\n\t</metrics>")
else:
eloc_xml = ""
for i in sorted(set([(j, i) for (i, j) in metrics_logic.eloc.items()]), reverse = True):
eloc_xml += "\t\t\t\t\t<violation>\n"
eloc_xml += "\t\t\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
eloc_xml += "\t\t\t\t\t\t<lines-of-code>" + str(i[0]) + "</lines-of-code>\n"
eloc_xml += "\t\t\t\t\t</violation>\n"
if not metrics.eloc: print("\t\t<metrics>\n\t\t\t<eloc>\n\t\t\t\t<message>" + __eloc_info_text__ +
print("\t<metrics>\n\t\t<message>" + __metrics_missing_info_text__ + "</message>\n\t</metrics>") "</message>\n\t\t\t\t<violations>\n" + eloc_xml + "\t\t\t\t</violations>\n\t\t\t</eloc>\n\t\t</metrics>")
else:
eloc_xml = ""
for i in sorted(set([(j, i) for (i, j) in metrics.eloc.items()]), reverse = True):
eloc_xml += "\t\t\t\t\t<violation>\n"
eloc_xml += "\t\t\t\t\t\t<file-name>" + i[1] + "</file-name>\n"
eloc_xml += "\t\t\t\t\t\t<lines-of-code>" + str(i[0]) + "</lines-of-code>\n"
eloc_xml += "\t\t\t\t\t</violation>\n"
print("\t\t<metrics>\n\t\t\t<eloc>\n\t\t\t\t<message>" + __eloc_info_text__ +
"</message>\n\t\t\t\t<violations>\n" + eloc_xml + "\t\t\t\t</violations>\n\t\t\t</eloc>\n\t\t</metrics>")

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import os import os
import subprocess import subprocess
import terminal import terminal
@ -43,23 +44,21 @@ __missing_info_text__ = ("The following files were missing in the repository and
"completely included in the statistical analysis. To include them, you can " "completely included in the statistical analysis. To include them, you can "
"either checkout manually using git or use the -c option in gitinspector") "either checkout manually using git or use the -c option in gitinspector")
def output_html(): class Missing(Outputable):
print("HTML output not yet supported.") def output_text(self):
if __missing_files__:
print("\n" + textwrap.fill(__missing_info_text__ + ":", width=terminal.get_size()[0]))
def output_text(): for missing in __missing_files__:
if __missing_files__: (width, _) = terminal.get_size()
print("\n" + textwrap.fill(__missing_info_text__ + ":", width=terminal.get_size()[0])) print("...%s" % missing[-width+3:] if len(missing) > width else missing)
for missing in __missing_files__: def output_xml(self):
(width, _) = terminal.get_size() if __missing_files__:
print("...%s" % missing[-width+3:] if len(missing) > width else missing) message_xml = "\t\t<message>" + __missing_info_text__ + "</message>\n"
missing_xml = ""
def output_xml(): for missing in __missing_files__:
if __missing_files__: missing_xml += "\t\t\t<file>" + missing + "</file>\n"
message_xml = "\t\t<message>" + __missing_info_text__ + "</message>\n"
missing_xml = ""
for missing in __missing_files__: print("\t<missing>\n" + message_xml + "\t\t<files>\n" + missing_xml + "\t\t</files>\n\t</missing>")
missing_xml += "\t\t\t<file>" + missing + "</file>\n"
print("\t<missing>\n" + message_xml + "\t\t<files>\n" + missing_xml + "\t\t</files>\n\t</missing>")

39
outputable.py Normal file
View file

@ -0,0 +1,39 @@
# coding: utf-8
#
# Copyright © 2012 Ejwa Software. All rights reserved.
#
# This file is part of gitinspector.
#
# gitinspector is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# gitinspector is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import format
class Outputable(object):
def output_html(self):
print("HTML output not yet supported in " + self + ".")
def output_text(self):
print("Text output not yet supported in " + self + ".")
def output_xml(self):
print("XML output not yet supported in " + self + ".")
def output(outputable):
if format.get_selected() == "html":
outputable.output_html()
elif format.get_selected() == "text":
outputable.output_text()
else:
outputable.output_xml()

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import blame import blame
import terminal import terminal
import textwrap import textwrap
@ -41,46 +42,49 @@ class Responsibilities:
__responsibilities_info_text__ = ("The following repsonsibilties, by author, were found in the current " __responsibilities_info_text__ = ("The following repsonsibilties, by author, were found in the current "
"revision of the repository (comments are exluded from the line count, " "revision of the repository (comments are exluded from the line count, "
"if possible)") "if possible)")
def output_html(hard):
print("HTML output not yet supported.")
def output_text(hard): class ResponsibilitiesOutput(Outputable):
print("\n" + textwrap.fill(__responsibilities_info_text__ + ":", width=terminal.get_size()[0])) def __init__(self, hard):
self.hard = hard
Outputable.__init__(self)
for i in sorted(set(i[0] for i in blame.get(hard).blames)): def output_text(self):
print("\n" + i, "is mostly responsible for:") print("\n" + textwrap.fill(__responsibilities_info_text__ + ":", width=terminal.get_size()[0]))
responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(hard, i)), reverse=True)
for j, entry in enumerate(responsibilities): for i in sorted(set(i[0] for i in blame.get(self.hard).blames)):
(width, _) = terminal.get_size() print("\n" + i, "is mostly responsible for:")
width -= 7 responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True)
print(str(entry[0]).rjust(6), end=" ") for j, entry in enumerate(responsibilities):
print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1]) (width, _) = terminal.get_size()
width -= 7
if j >= 9: print(str(entry[0]).rjust(6), end=" ")
break print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1])
def output_xml(hard): if j >= 9:
message_xml = "\t\t<message>" + __responsibilities_info_text__ + "</message>\n" break
resp_xml = ""
for i in sorted(set(i[0] for i in blame.get(hard).blames)): def output_xml(self):
resp_xml += "\t\t\t<author>\n" message_xml = "\t\t<message>" + __responsibilities_info_text__ + "</message>\n"
resp_xml += "\t\t\t\t<name>" + i + "</name>\n" resp_xml = ""
resp_xml += "\t\t\t\t<files>\n"
responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(hard, i)), reverse=True)
for j, entry in enumerate(responsibilities): for i in sorted(set(i[0] for i in blame.get(self.hard).blames)):
resp_xml += "\t\t\t\t\t<file>\n" resp_xml += "\t\t\t<author>\n"
resp_xml += "\t\t\t\t\t\t<name>" + entry[1] + "</name>\n" resp_xml += "\t\t\t\t<name>" + i + "</name>\n"
resp_xml += "\t\t\t\t\t\t<rows>" + str(entry[0]) + "</rows>\n" resp_xml += "\t\t\t\t<files>\n"
resp_xml += "\t\t\t\t\t</file>\n" responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True)
if j >= 9: for j, entry in enumerate(responsibilities):
break resp_xml += "\t\t\t\t\t<file>\n"
resp_xml += "\t\t\t\t\t\t<name>" + entry[1] + "</name>\n"
resp_xml += "\t\t\t\t\t\t<rows>" + str(entry[0]) + "</rows>\n"
resp_xml += "\t\t\t\t\t</file>\n"
resp_xml += "\t\t\t\t</files>\n" if j >= 9:
resp_xml += "\t\t\t</author>\n" break
print("\t<responsibilities>\n" + message_xml + "\t\t<authors>\n" + resp_xml + "\t\t</authors>\n\t</responsibilities>") resp_xml += "\t\t\t\t</files>\n"
resp_xml += "\t\t\t</author>\n"
print("\t<responsibilities>\n" + message_xml + "\t\t<authors>\n" + resp_xml + "\t\t</authors>\n\t</responsibilities>")

View file

@ -18,6 +18,7 @@
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>. # along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function from __future__ import print_function
from outputable import Outputable
import datetime import datetime
import terminal import terminal
import textwrap import textwrap
@ -93,9 +94,6 @@ class TimelineData:
__timeline_info_text__ = "The following history timeline has been gathered from the repository" __timeline_info_text__ = "The following history timeline has been gathered from the repository"
def output_html(changes, useweeks):
print("HTML output not yet supported.")
def __output_row__text__(timeline_data, periods, names): def __output_row__text__(timeline_data, periods, names):
print("\n" + terminal.__bold__ + "Author".ljust(20), end=" ") print("\n" + terminal.__bold__ + "Author".ljust(20), end=" ")
@ -114,45 +112,51 @@ def __output_row__text__(timeline_data, periods, names):
len(signs_str) == 0 else signs_str).rjust(10), end=" ") len(signs_str) == 0 else signs_str).rjust(10), end=" ")
print("") print("")
def output_text(changes, useweeks): class Timeline(Outputable):
if changes.get_commits(): def __init__(self, changes, useweeks):
print("\n" + textwrap.fill(__timeline_info_text__ + ":", width=terminal.get_size()[0])) self.changes = changes
self.useweeks = useweeks
Outputable.__init__(self)
timeline_data = TimelineData(changes, useweeks) def output_text(self):
periods = timeline_data.get_periods() if self.changes.get_commits():
names = timeline_data.get_authors() print("\n" + textwrap.fill(__timeline_info_text__ + ":", width=terminal.get_size()[0]))
(width, _) = terminal.get_size()
max_periods_per_row = int((width - 21) / 11)
for i in range(0, len(periods), max_periods_per_row): timeline_data = TimelineData(self.changes, self.useweeks)
__output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names) periods = timeline_data.get_periods()
names = timeline_data.get_authors()
(width, _) = terminal.get_size()
max_periods_per_row = int((width - 21) / 11)
def output_xml(changes, useweeks): for i in range(0, len(periods), max_periods_per_row):
if changes.get_commits(): __output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names)
message_xml = "\t\t<message>" + __timeline_info_text__ + "</message>\n"
timeline_xml = ""
periods_xml = "\t\t<periods length=\"{0}\">\n".format("week" if useweeks else "month")
timeline_data = TimelineData(changes, useweeks) def output_xml(self):
periods = timeline_data.get_periods() if self.changes.get_commits():
names = timeline_data.get_authors() message_xml = "\t\t<message>" + __timeline_info_text__ + "</message>\n"
timeline_xml = ""
periods_xml = "\t\t<periods length=\"{0}\">\n".format("week" if self.useweeks else "month")
for period in periods: timeline_data = TimelineData(self.changes, self.useweeks)
name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n" periods = timeline_data.get_periods()
authors_xml = "" names = timeline_data.get_authors()
for name in names: for period in periods:
authors_xml += "\t\t\t\t<authors>\n" name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n"
multiplier = timeline_data.get_multiplier(period, 24) authors_xml = ""
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
signs_str = (signs[1] * "-" + signs[0] * "+")
if not len(signs_str) == 0: for name in names:
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name + "</name>\n" authors_xml += "\t\t\t\t<authors>\n"
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n" multiplier = timeline_data.get_multiplier(period, 24)
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
signs_str = (signs[1] * "-" + signs[0] * "+")
authors_xml += "\t\t\t\t</authors>\n" if not len(signs_str) == 0:
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name + "</name>\n"
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n"
timeline_xml += "\t\t\t<period>\n" + name_xml + authors_xml + "\t\t\t</period>\n" authors_xml += "\t\t\t\t</authors>\n"
print("\t<timeline>\n" + message_xml + periods_xml + timeline_xml + "\t\t</periods>\n\t</timeline>") timeline_xml += "\t\t\t<period>\n" + name_xml + authors_xml + "\t\t\t</period>\n"
print("\t<timeline>\n" + message_xml + periods_xml + timeline_xml + "\t\t</periods>\n\t</timeline>")