Handle git-rev-list and git-ls-tree with empty changesets (#132, #115).

If the changeset was empty or filtered with no matching files a bunch of
errors would be thrown from git with no proper results being returned
back to gitinspector.

We now pipe stderr (catching the output) and also check the return code
when running these commands.
This commit is contained in:
Adam Waldenberg 2017-05-13 15:30:32 +02:00
parent 8cff4bd208
commit a56680c4b4
3 changed files with 60 additions and 55 deletions

View File

@ -1,6 +1,6 @@
# coding: utf-8 # coding: utf-8
# #
# Copyright © 2012-2015 Ejwa Software. All rights reserved. # Copyright © 2012-2017 Ejwa Software. All rights reserved.
# #
# This file is part of gitinspector. # This file is part of gitinspector.
# #
@ -123,40 +123,42 @@ PROGRESS_TEXT = N_("Checking how many rows belong to each author (2 of 2): {0:.0
class Blame(object): class Blame(object):
def __init__(self, repo, hard, useweeks, changes): def __init__(self, repo, hard, useweeks, changes):
self.blames = {} self.blames = {}
ls_tree_r = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1, ls_tree_p = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1,
stdout=subprocess.PIPE).stdout stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lines = ls_tree_r.readlines() lines = ls_tree_p.communicate()[0].splitlines()
ls_tree_r.close() ls_tree_p.stdout.close()
progress_text = _(PROGRESS_TEXT) if ls_tree_p.returncode == 0:
if repo != None: progress_text = _(PROGRESS_TEXT)
progress_text = "[%s] " % repo.name + progress_text
for i, row in enumerate(lines): if repo != None:
row = row.strip().decode("unicode_escape", "ignore") progress_text = "[%s] " % repo.name + progress_text
row = row.encode("latin-1", "replace")
row = row.decode("utf-8", "replace").strip("\"").strip("'").strip()
if FileDiff.get_extension(row) in extensions.get_located() and FileDiff.is_valid_extension(row) and not \ for i, row in enumerate(lines):
filtering.set_filtered(FileDiff.get_filename(row)): row = row.strip().decode("unicode_escape", "ignore")
blame_command = filter(None, ["git", "blame", "--line-porcelain", "-w"] + \ row = row.encode("latin-1", "replace")
(["-C", "-C", "-M"] if hard else []) + row = row.decode("utf-8", "replace").strip("\"").strip("'").strip()
[interval.get_since(), interval.get_ref(), "--", row])
thread = BlameThread(useweeks, changes, blame_command, FileDiff.get_extension(row),
self.blames, row.strip())
thread.daemon = True
thread.start()
if format.is_interactive_format(): if FileDiff.get_extension(row) in extensions.get_located() and \
terminal.output_progress(progress_text, i, len(lines)) FileDiff.is_valid_extension(row) and not filtering.set_filtered(FileDiff.get_filename(row)):
blame_command = filter(None, ["git", "blame", "--line-porcelain", "-w"] + \
(["-C", "-C", "-M"] if hard else []) +
[interval.get_since(), interval.get_ref(), "--", row])
thread = BlameThread(useweeks, changes, blame_command, FileDiff.get_extension(row),
self.blames, row.strip())
thread.daemon = True
thread.start()
# Make sure all threads have completed. if format.is_interactive_format():
for i in range(0, NUM_THREADS): terminal.output_progress(progress_text, i, len(lines))
__thread_lock__.acquire()
# We also have to release them for future use. # Make sure all threads have completed.
for i in range(0, NUM_THREADS): for i in range(0, NUM_THREADS):
__thread_lock__.release() __thread_lock__.acquire()
# We also have to release them for future use.
for i in range(0, NUM_THREADS):
__thread_lock__.release()
def __iadd__(self, other): def __iadd__(self, other):
try: try:

View File

@ -1,6 +1,6 @@
# coding: utf-8 # coding: utf-8
# #
# Copyright © 2012-2015 Ejwa Software. All rights reserved. # Copyright © 2012-2017 Ejwa Software. All rights reserved.
# #
# This file is part of gitinspector. # This file is part of gitinspector.
# #
@ -183,13 +183,13 @@ class Changes(object):
def __init__(self, repo, hard): def __init__(self, repo, hard):
self.commits = [] self.commits = []
git_log_hashes_r = subprocess.Popen(filter(None, ["git", "rev-list", "--reverse", "--no-merges", git_rev_list_p = subprocess.Popen(filter(None, ["git", "rev-list", "--reverse", "--no-merges",
interval.get_since(), interval.get_until(), "HEAD"]), bufsize=1, interval.get_since(), interval.get_until(), "HEAD"]), bufsize=1,
stdout=subprocess.PIPE).stdout stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lines = git_log_hashes_r.readlines() lines = git_rev_list_p.communicate()[0].splitlines()
git_log_hashes_r.close() git_rev_list_p.stdout.close()
if len(lines) > 0: if git_rev_list_p.returncode == 0 and len(lines) > 0:
progress_text = _(PROGRESS_TEXT) progress_text = _(PROGRESS_TEXT)
if repo != None: if repo != None:
progress_text = "[%s] " % repo.name + progress_text progress_text = "[%s] " % repo.name + progress_text

View File

@ -1,6 +1,6 @@
# coding: utf-8 # coding: utf-8
# #
# Copyright © 2012-2015 Ejwa Software. All rights reserved. # Copyright © 2012-2017 Ejwa Software. All rights reserved.
# #
# This file is part of gitinspector. # This file is part of gitinspector.
# #
@ -44,30 +44,33 @@ class MetricsLogic(object):
self.cyclomatic_complexity = {} self.cyclomatic_complexity = {}
self.cyclomatic_complexity_density = {} self.cyclomatic_complexity_density = {}
ls_tree_r = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1, ls_tree_p = subprocess.Popen(["git", "ls-tree", "--name-only", "-r", interval.get_ref()], bufsize=1,
stdout=subprocess.PIPE).stdout stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
lines = ls_tree_p.communicate()[0].splitlines()
ls_tree_p.stdout.close()
for i in ls_tree_r.readlines(): if ls_tree_p.returncode == 0:
i = i.strip().decode("unicode_escape", "ignore") for i in lines:
i = i.encode("latin-1", "replace") i = i.strip().decode("unicode_escape", "ignore")
i = i.decode("utf-8", "replace").strip("\"").strip("'").strip() i = i.encode("latin-1", "replace")
i = i.decode("utf-8", "replace").strip("\"").strip("'").strip()
if FileDiff.is_valid_extension(i) and not filtering.set_filtered(FileDiff.get_filename(i)): if FileDiff.is_valid_extension(i) and not filtering.set_filtered(FileDiff.get_filename(i)):
file_r = subprocess.Popen(["git", "show", interval.get_ref() + ":{0}".format(i.strip())], file_r = subprocess.Popen(["git", "show", interval.get_ref() + ":{0}".format(i.strip())],
bufsize=1, stdout=subprocess.PIPE).stdout.readlines() bufsize=1, stdout=subprocess.PIPE).stdout.readlines()
extension = FileDiff.get_extension(i) extension = FileDiff.get_extension(i)
lines = MetricsLogic.get_eloc(file_r, extension) lines = MetricsLogic.get_eloc(file_r, extension)
cycc = MetricsLogic.get_cyclomatic_complexity(file_r, extension) cycc = MetricsLogic.get_cyclomatic_complexity(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
if METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD < cycc: if METRIC_CYCLOMATIC_COMPLEXITY_THRESHOLD < cycc:
self.cyclomatic_complexity[i.strip()] = cycc self.cyclomatic_complexity[i.strip()] = cycc
if lines > 0 and METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD < cycc / float(lines): if lines > 0 and METRIC_CYCLOMATIC_COMPLEXITY_DENSITY_THRESHOLD < cycc / float(lines):
self.cyclomatic_complexity_density[i.strip()] = cycc / float(lines) self.cyclomatic_complexity_density[i.strip()] = cycc / float(lines)
def __iadd__(self, other): def __iadd__(self, other):
try: try: