diff --git a/blame.py b/blame.py index 53b8297..3e117ea 100644 --- a/blame.py +++ b/blame.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable from changes import FileDiff import comment 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 " "intact in the current revision") -def output_html(hard): - get(hard) +class BlameOutput(Outputable): + def __init__(self, hard): + self.hard = hard + Outputable.__init__(self) - blame_xml = "<div class=\"box statistics\">" - 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 + def output_html(self): + get(self.hard) - for i in blames: - total_blames += i[1].rows + blame_xml = "<div class=\"statistics right\"><div class=\"box\">" + 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): - 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)) + for i in blames: + total_blames += i[1].rows - if blames[-1] != entry: - chart_data += ", " + for i, entry in enumerate(blames): + 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> </td> <td> </td> <td> </td> </tr></tfoot></tbody></table>" - blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div></div>" + if blames[-1] != entry: + chart_data += ", " - 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>" + blame_xml += "<tfoot><tr> <td> </td> <td> </td> <td> </td> </tr></tfoot></tbody></table>" + blame_xml += "<div class=\"chart\" id=\"blame_chart\"></div></div></div></div>" - 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("") - get(hard) + print(blame_xml) - if hard and sys.stdout.isatty(): - terminal.clear_row() + def output_text(self): + print("") + get(self.hard) - print(textwrap.fill(__blame_info_text__ + ":", width=terminal.get_size()[0]) + "\n") - 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)) + if self.hard and sys.stdout.isatty(): + terminal.clear_row() -def output_xml(hard): - get(hard) + print(textwrap.fill(__blame_info_text__ + ":", width=terminal.get_size()[0]) + "\n") + 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" - blame_xml = "" + def output_xml(self): + get(self.hard) - 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" + message_xml = "\t\t<message>" + __blame_info_text__ + "</message>\n" + blame_xml = "" - 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>") diff --git a/changes.py b/changes.py index 3873a1c..5c6fe20 100644 --- a/changes.py +++ b/changes.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import extensions import filtering import re @@ -151,60 +152,98 @@ def get(hard): return __changes__ __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): - print("HTML output not yet supported.") +class ChangesOutput(Outputable): + def __init__(self, hard): + self.hard = hard + Outputable.__init__(self) -def output_text(hard): - authorinfo_list = get(hard).get_authorinfo_list() - total_changes = 0.0 + def output_html(self): + authorinfo_list = get(self.hard).get_authorinfo_list() + total_changes = 0.0 + changes_xml = "<div class=\"statistics right\"><div class=\"box\">" - for i in authorinfo_list: - total_changes += authorinfo_list.get(i).insertions - total_changes += authorinfo_list.get(i).deletions + for i in authorinfo_list: + total_changes += authorinfo_list.get(i).insertions + total_changes += authorinfo_list.get(i).deletions - if authorinfo_list: - print(textwrap.fill(__historical_info_text__ + ":", width=terminal.get_size()[0]) + "\n") - terminal.printb("Author".ljust(21) + "Commits " + "Insertions " + "Deletions " + "% of changes") + if authorinfo_list: + changes_xml += "<p>" + __historical_info_text__ + ".</p><div><table class=\"git\">" + 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): - authorinfo = authorinfo_list.get(i) - percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100 + for i, entry in enumerate(sorted(authorinfo_list)): + authorinfo = authorinfo_list.get(entry) + percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100 - print(i.ljust(20)[0:20], end=" ") - print(str(authorinfo.commits).rjust(7), end=" ") - print(str(authorinfo.insertions).rjust(12), end=" ") - print(str(authorinfo.deletions).rjust(11), end=" ") - print("{0:.2f}".format(percentage).rjust(14)) - else: - print("No commited files with the specified extensions were found.") + changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">") + changes_xml += "<td>" + entry + "</td>" + changes_xml += "<td>" + str(authorinfo.commits) + "</td>" + changes_xml += "<td>" + str(authorinfo.insertions) + "</td>" + changes_xml += "<td>" + str(authorinfo.deletions) + "</td>" + changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>" + changes_xml += "</tr>" -def output_xml(hard): - authorinfo_list = get(hard).get_authorinfo_list() - total_changes = 0.0 + changes_xml += ("<tfoot><tr> <td> </td> <td> </td> <td> </td> <td> </td> <td> </td>" + + "</tr></tfoot></tbody></table>") + changes_xml += "</div>" + else: + changes_xml += "<p>" + __no_commited_files__ + ".</p>" - for i in authorinfo_list: - total_changes += authorinfo_list.get(i).insertions - total_changes += authorinfo_list.get(i).deletions + changes_xml += "</div></div>" + print(changes_xml) - if authorinfo_list: - message_xml = "\t\t<message>" + __historical_info_text__ + "</message>\n" - changes_xml = "" + def output_text(self): + authorinfo_list = get(self.hard).get_authorinfo_list() + total_changes = 0.0 - 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 + for i in authorinfo_list: + total_changes += authorinfo_list.get(i).insertions + total_changes += authorinfo_list.get(i).deletions - 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" + if authorinfo_list: + print(textwrap.fill(__historical_info_text__ + ":", width=terminal.get_size()[0]) + "\n") + terminal.printb("Author".ljust(21) + "Commits " + "Insertions " + "Deletions " + "% of changes") - changes_xml += ("\t\t\t<author>\n" + name_xml + commits_xml + insertions_xml + - deletions_xml + percentage_xml + "\t\t\t</author>\n") + 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 - 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 with the specified extensions were found." + - "</exception>\n\t</changes>") + print(i.ljust(20)[0:20], end=" ") + print(str(authorinfo.commits).rjust(7), end=" ") + print(str(authorinfo.insertions).rjust(12), end=" ") + 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>") diff --git a/extensions.py b/extensions.py index 17fa510..3a7a3fc 100644 --- a/extensions.py +++ b/extensions.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import terminal import textwrap @@ -38,32 +39,30 @@ def add_located(string): __extensions_info_text__ = "The extensions below were found in the repository history" -def output_html(): - print("HTML output not yet supported.") +class Extensions(Outputable): + 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(): - if __located_extensions__: - print("\n" + textwrap.fill(__extensions_info_text__ + "\n(extensions used during statistical analysis are marked):", - width=terminal.get_size()[0])) + for i in __located_extensions__: + if i in __extensions__: + print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ") + else: + print (i, end=" ") + print("") - for i in __located_extensions__: - if i in __extensions__: - print("[" + terminal.__bold__ + i + terminal.__normal__ + "]", end=" ") - else: - print (i, end=" ") - print("") + def output_xml(self): + if __located_extensions__: + message_xml = "\t\t<message>" + __extensions_info_text__ + "</message>\n" + used_extensions_xml = "" + unused_extensions_xml = "" -def output_xml(): - if __located_extensions__: - message_xml = "\t\t<message>" + __extensions_info_text__ + "</message>\n" - used_extensions_xml = "" - unused_extensions_xml = "" + for i in __located_extensions__: + if i in __extensions__: + used_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n" + else: + unused_extensions_xml += "\t\t\t<extension>" + i + "</extension>\n" - for i in __located_extensions__: - if i in __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>") + 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>") diff --git a/filtering.py b/filtering.py index f0ee051..2ddd3f9 100644 --- a/filtering.py +++ b/filtering.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import terminal 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" "specified exclusion patterns") -def output_html(): - print("HTML output not yet supported.") +class Filtering(Outputable): + def output_text(self): + if __filtered_files__: + print("\n" + textwrap.fill(__filtering_info_text__ + ":", width=terminal.get_size()[0])) -def output_text(): - if __filtered_files__: - print("\n" + textwrap.fill(__filtering_info_text__ + ":", width=terminal.get_size()[0])) + for i in __filtered_files__: + (width, _) = terminal.get_size() + print("...%s" % i[-width+3:] if len(i) > width else i) - for i in __filtered_files__: - (width, _) = terminal.get_size() - print("...%s" % i[-width+3:] if len(i) > width else i) + def output_xml(self): + if __filtered_files__: + message_xml = "\t\t<message>" + __filtering_info_text__ + "</message>\n" + filtering_xml = "" -def output_xml(): - if __filtered_files__: - message_xml = "\t\t<message>" + __filtering_info_text__ + "</message>\n" - filtering_xml = "" + for i in __filtered_files__: + filtering_xml += "\t\t\t<file>" + i + "</file>\n" - for i in __filtered_files__: - 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>") + print("\t<filering>\n" + message_xml + "\t\t<files>\n" + filtering_xml + "\t\t</files>\n\t</filtering>") diff --git a/format.py b/format.py index a64675a..6429eda 100644 --- a/format.py +++ b/format.py @@ -18,11 +18,10 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +import version import base64 import basedir import os -import terminal -import version import zipfile __available_formats__ = ["html", "text", "xml"] @@ -38,6 +37,9 @@ def select(format): return format in __available_formats__ +def get_selected(): + return __selected_format__ + def is_interactive_format(): return __selected_format__ == "text" @@ -75,11 +77,3 @@ def output_footer(): print(html_footer) elif __selected_format__ == "xml": 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) diff --git a/gitinspector.py b/gitinspector.py index 59cc0c6..7adbe02 100755 --- a/gitinspector.py +++ b/gitinspector.py @@ -29,6 +29,7 @@ import help import metrics import missing import os +import outputable import responsibilities import sys import terminal @@ -51,27 +52,25 @@ class Runner: previous_directory = os.getcwd() os.chdir(self.repo) 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(): - format.call_output_function(blame.output_html, blame.output_text, blame.output_xml, self.hard) + outputable.output(blame.BlameOutput(self.hard)) if self.timeline: - format.call_output_function(timeline.output_html, timeline.output_text, timeline.output_xml, - changes.get(self.hard), self.useweeks) + outputable.output(timeline.Timeline(changes.get(self.hard), self.useweeks)) if self.include_metrics: - format.call_output_function(metrics.output_html, metrics.output_text, metrics.output_xml) + outputable.output(metrics.Metrics()) if self.responsibilities: - format.call_output_function(responsibilities.output_html, responsibilities.output_text, - responsibilities.output_xml, self.hard) + outputable.output(responsibilities.ResponsibilitiesOutput(self.hard)) - format.call_output_function(missing.output_html, missing.output_text, missing.output_xml) - format.call_output_function(filtering.output_html, filtering.output_text, filtering.output_xml) + outputable.output(missing.Missing()) + outputable.output(filtering.Filtering()) 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() os.chdir(previous_directory) diff --git a/metrics.py b/metrics.py index 442dd86..01e41c0 100644 --- a/metrics.py +++ b/metrics.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable from changes import FileDiff import comment import filtering @@ -27,7 +28,7 @@ import subprocess __metric_eloc__ = {"java": 500, "c": 500, "cpp": 500, "h": 300, "hpp": 300, "py": 500, "glsl": 1000, "rb": 500, "js": 500, "sql": 1000, "xml": 1000} -class Metrics: +class MetricsLogic: def __init__(self): self.eloc = {} 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()): file_r = open(i.strip(), "rb") 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: self.eloc[i.strip()] = lines @@ -63,31 +64,29 @@ class Metrics: __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" -def output_html(): - print("HTML output not yet supported.") +class Metrics(Outputable): + def output_text(self): + metrics_logic = MetricsLogic() -def output_text(): - metrics = Metrics() + if not metrics_logic.eloc: + 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: - print("\n" + __metrics_missing_info_text__ + ".") - 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(self): + metrics_logic = MetricsLogic() -def output_xml(): - metrics = Metrics() + if not metrics_logic.eloc: + 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<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.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>") + 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>") diff --git a/missing.py b/missing.py index 11e1649..c14b324 100644 --- a/missing.py +++ b/missing.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import os import subprocess 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 " "either checkout manually using git or use the -c option in gitinspector") -def output_html(): - print("HTML output not yet supported.") +class Missing(Outputable): + def output_text(self): + if __missing_files__: + print("\n" + textwrap.fill(__missing_info_text__ + ":", width=terminal.get_size()[0])) -def output_text(): - if __missing_files__: - print("\n" + textwrap.fill(__missing_info_text__ + ":", width=terminal.get_size()[0])) + for missing in __missing_files__: + (width, _) = terminal.get_size() + print("...%s" % missing[-width+3:] if len(missing) > width else missing) - for missing in __missing_files__: - (width, _) = terminal.get_size() - print("...%s" % missing[-width+3:] if len(missing) > width else missing) + def output_xml(self): + if __missing_files__: + message_xml = "\t\t<message>" + __missing_info_text__ + "</message>\n" + missing_xml = "" -def output_xml(): - if __missing_files__: - message_xml = "\t\t<message>" + __missing_info_text__ + "</message>\n" - missing_xml = "" + for missing in __missing_files__: + missing_xml += "\t\t\t<file>" + missing + "</file>\n" - for missing in __missing_files__: - 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>") + print("\t<missing>\n" + message_xml + "\t\t<files>\n" + missing_xml + "\t\t</files>\n\t</missing>") diff --git a/outputable.py b/outputable.py new file mode 100644 index 0000000..648b26d --- /dev/null +++ b/outputable.py @@ -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() diff --git a/responsibilities.py b/responsibilities.py index bf7b05e..1ae9d82 100644 --- a/responsibilities.py +++ b/responsibilities.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import blame import terminal import textwrap @@ -41,46 +42,49 @@ class Responsibilities: __responsibilities_info_text__ = ("The following repsonsibilties, by author, were found in the current " "revision of the repository (comments are exluded from the line count, " "if possible)") -def output_html(hard): - print("HTML output not yet supported.") -def output_text(hard): - print("\n" + textwrap.fill(__responsibilities_info_text__ + ":", width=terminal.get_size()[0])) +class ResponsibilitiesOutput(Outputable): + def __init__(self, hard): + self.hard = hard + Outputable.__init__(self) - for i in sorted(set(i[0] for i in blame.get(hard).blames)): - print("\n" + i, "is mostly responsible for:") - responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(hard, i)), reverse=True) + def output_text(self): + print("\n" + textwrap.fill(__responsibilities_info_text__ + ":", width=terminal.get_size()[0])) - for j, entry in enumerate(responsibilities): - (width, _) = terminal.get_size() - width -= 7 + for i in sorted(set(i[0] for i in blame.get(self.hard).blames)): + print("\n" + i, "is mostly responsible for:") + responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True) - print(str(entry[0]).rjust(6), end=" ") - print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1]) + for j, entry in enumerate(responsibilities): + (width, _) = terminal.get_size() + width -= 7 - if j >= 9: - break + print(str(entry[0]).rjust(6), end=" ") + print("...%s" % entry[1][-width+3:] if len(entry[1]) > width else entry[1]) -def output_xml(hard): - message_xml = "\t\t<message>" + __responsibilities_info_text__ + "</message>\n" - resp_xml = "" + if j >= 9: + break - for i in sorted(set(i[0] for i in blame.get(hard).blames)): - resp_xml += "\t\t\t<author>\n" - resp_xml += "\t\t\t\t<name>" + i + "</name>\n" - resp_xml += "\t\t\t\t<files>\n" - responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(hard, i)), reverse=True) + def output_xml(self): + message_xml = "\t\t<message>" + __responsibilities_info_text__ + "</message>\n" + resp_xml = "" - for j, entry in enumerate(responsibilities): - 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" + for i in sorted(set(i[0] for i in blame.get(self.hard).blames)): + resp_xml += "\t\t\t<author>\n" + resp_xml += "\t\t\t\t<name>" + i + "</name>\n" + resp_xml += "\t\t\t\t<files>\n" + responsibilities = sorted(((i[1], i[0]) for i in Responsibilities.get(self.hard, i)), reverse=True) - if j >= 9: - break + for j, entry in enumerate(responsibilities): + 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" - resp_xml += "\t\t\t</author>\n" + if j >= 9: + 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>") diff --git a/timeline.py b/timeline.py index 40cc5ef..e5ee59f 100644 --- a/timeline.py +++ b/timeline.py @@ -18,6 +18,7 @@ # along with gitinspector. If not, see <http://www.gnu.org/licenses/>. from __future__ import print_function +from outputable import Outputable import datetime import terminal import textwrap @@ -93,9 +94,6 @@ class TimelineData: __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): 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=" ") print("") -def output_text(changes, useweeks): - if changes.get_commits(): - print("\n" + textwrap.fill(__timeline_info_text__ + ":", width=terminal.get_size()[0])) +class Timeline(Outputable): + def __init__(self, changes, useweeks): + self.changes = changes + self.useweeks = useweeks + Outputable.__init__(self) - timeline_data = TimelineData(changes, useweeks) - periods = timeline_data.get_periods() - names = timeline_data.get_authors() - (width, _) = terminal.get_size() - max_periods_per_row = int((width - 21) / 11) + def output_text(self): + if self.changes.get_commits(): + print("\n" + textwrap.fill(__timeline_info_text__ + ":", width=terminal.get_size()[0])) - for i in range(0, len(periods), max_periods_per_row): - __output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names) + timeline_data = TimelineData(self.changes, self.useweeks) + 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): - if changes.get_commits(): - 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") + for i in range(0, len(periods), max_periods_per_row): + __output_row__text__(timeline_data, periods[i:i+max_periods_per_row], names) - timeline_data = TimelineData(changes, useweeks) - periods = timeline_data.get_periods() - names = timeline_data.get_authors() + def output_xml(self): + if self.changes.get_commits(): + 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: - name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n" - authors_xml = "" + timeline_data = TimelineData(self.changes, self.useweeks) + periods = timeline_data.get_periods() + names = timeline_data.get_authors() - for name in names: - authors_xml += "\t\t\t\t<authors>\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] * "+") + for period in periods: + name_xml = "\t\t\t\t<name>" + str(period) + "</name>\n" + authors_xml = "" - 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" + for name in names: + authors_xml += "\t\t\t\t<authors>\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>")