mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 10:41:31 +00:00
switch to 4 space indent
Leave the recipes/ code at 2 space to match the rest of the recipes
project in other repos.
Reformatted using:
files=( $(
git ls-tree -r --name-only HEAD | \
grep -Ev -e '^(third_party|recipes)/' | \
grep '\.py$';
git grep -l '#!/usr/bin/env.*python' | grep -v '\.py$'
) )
parallel ./yapf -i -- "${files[@]}"
~/chromiumos/chromite/contrib/reflow_overlong_comments "${files[@]}"
The files that still had strings that were too long were manually
reformatted because they were easy and only a few issues.
autoninja.py
clang_format.py
download_from_google_storage.py
fix_encoding.py
gclient_utils.py
git_cache.py
git_common.py
git_map_branches.py
git_reparent_branch.py
gn.py
my_activity.py
owners_finder.py
presubmit_canned_checks.py
reclient_helper.py
reclientreport.py
roll_dep.py
rustfmt.py
siso.py
split_cl.py
subcommand.py
subprocess2.py
swift_format.py
upload_to_google_storage.py
These files still had lines (strings) that were too long, so the pylint
warnings were suppressed with a TODO.
auth.py
gclient.py
gclient_eval.py
gclient_paths.py
gclient_scm.py
gerrit_util.py
git_cl.py
presubmit_canned_checks.py
presubmit_support.py
scm.py
Change-Id: Ia6535c4f2c48d46b589ec1e791dde6c6b2ea858f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4836379
Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
Auto-Submit: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
# Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Wrapper around git blame that ignores certain commits.
|
||||
"""
|
||||
|
||||
@@ -17,135 +16,133 @@ import git_common
|
||||
import git_dates
|
||||
import setup_color
|
||||
|
||||
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
|
||||
DEFAULT_IGNORE_FILE_NAME = '.git-blame-ignore-revs'
|
||||
|
||||
|
||||
class Commit(object):
|
||||
"""Info about a commit."""
|
||||
def __init__(self, commithash):
|
||||
self.commithash = commithash
|
||||
self.author = None
|
||||
self.author_mail = None
|
||||
self.author_time = None
|
||||
self.author_tz = None
|
||||
self.committer = None
|
||||
self.committer_mail = None
|
||||
self.committer_time = None
|
||||
self.committer_tz = None
|
||||
self.summary = None
|
||||
self.boundary = None
|
||||
self.previous = None
|
||||
self.filename = None
|
||||
"""Info about a commit."""
|
||||
def __init__(self, commithash):
|
||||
self.commithash = commithash
|
||||
self.author = None
|
||||
self.author_mail = None
|
||||
self.author_time = None
|
||||
self.author_tz = None
|
||||
self.committer = None
|
||||
self.committer_mail = None
|
||||
self.committer_time = None
|
||||
self.committer_tz = None
|
||||
self.summary = None
|
||||
self.boundary = None
|
||||
self.previous = None
|
||||
self.filename = None
|
||||
|
||||
def __repr__(self): # pragma: no cover
|
||||
return '<Commit %s>' % self.commithash
|
||||
def __repr__(self): # pragma: no cover
|
||||
return '<Commit %s>' % self.commithash
|
||||
|
||||
|
||||
BlameLine = collections.namedtuple(
|
||||
'BlameLine',
|
||||
'commit context lineno_then lineno_now modified')
|
||||
'BlameLine', 'commit context lineno_then lineno_now modified')
|
||||
|
||||
|
||||
def parse_blame(blameoutput):
|
||||
"""Parses the output of git blame -p into a data structure."""
|
||||
lines = blameoutput.split('\n')
|
||||
i = 0
|
||||
commits = {}
|
||||
"""Parses the output of git blame -p into a data structure."""
|
||||
lines = blameoutput.split('\n')
|
||||
i = 0
|
||||
commits = {}
|
||||
|
||||
while i < len(lines):
|
||||
# Read a commit line and parse it.
|
||||
line = lines[i]
|
||||
i += 1
|
||||
if not line.strip():
|
||||
continue
|
||||
commitline = line.split()
|
||||
commithash = commitline[0]
|
||||
lineno_then = int(commitline[1])
|
||||
lineno_now = int(commitline[2])
|
||||
|
||||
try:
|
||||
commit = commits[commithash]
|
||||
except KeyError:
|
||||
commit = Commit(commithash)
|
||||
commits[commithash] = commit
|
||||
|
||||
# Read commit details until we find a context line.
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
i += 1
|
||||
if line.startswith('\t'):
|
||||
break
|
||||
# Read a commit line and parse it.
|
||||
line = lines[i]
|
||||
i += 1
|
||||
if not line.strip():
|
||||
continue
|
||||
commitline = line.split()
|
||||
commithash = commitline[0]
|
||||
lineno_then = int(commitline[1])
|
||||
lineno_now = int(commitline[2])
|
||||
|
||||
try:
|
||||
key, value = line.split(' ', 1)
|
||||
except ValueError:
|
||||
key = line
|
||||
value = True
|
||||
setattr(commit, key.replace('-', '_'), value)
|
||||
try:
|
||||
commit = commits[commithash]
|
||||
except KeyError:
|
||||
commit = Commit(commithash)
|
||||
commits[commithash] = commit
|
||||
|
||||
context = line[1:]
|
||||
# Read commit details until we find a context line.
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
i += 1
|
||||
if line.startswith('\t'):
|
||||
break
|
||||
|
||||
yield BlameLine(commit, context, lineno_then, lineno_now, False)
|
||||
try:
|
||||
key, value = line.split(' ', 1)
|
||||
except ValueError:
|
||||
key = line
|
||||
value = True
|
||||
setattr(commit, key.replace('-', '_'), value)
|
||||
|
||||
context = line[1:]
|
||||
|
||||
yield BlameLine(commit, context, lineno_then, lineno_now, False)
|
||||
|
||||
|
||||
def print_table(outbuf, table, align):
|
||||
"""Print a 2D rectangular array, aligning columns with spaces.
|
||||
"""Print a 2D rectangular array, aligning columns with spaces.
|
||||
|
||||
Args:
|
||||
align: string of 'l' and 'r', designating whether each column is left- or
|
||||
right-aligned.
|
||||
"""
|
||||
if len(table) == 0:
|
||||
return
|
||||
if len(table) == 0:
|
||||
return
|
||||
|
||||
colwidths = None
|
||||
for row in table:
|
||||
if colwidths is None:
|
||||
colwidths = [len(x) for x in row]
|
||||
else:
|
||||
colwidths = [max(colwidths[i], len(x)) for i, x in enumerate(row)]
|
||||
colwidths = None
|
||||
for row in table:
|
||||
if colwidths is None:
|
||||
colwidths = [len(x) for x in row]
|
||||
else:
|
||||
colwidths = [max(colwidths[i], len(x)) for i, x in enumerate(row)]
|
||||
|
||||
for row in table:
|
||||
cells = []
|
||||
for i, cell in enumerate(row):
|
||||
padding = ' ' * (colwidths[i] - len(cell))
|
||||
if align[i] == 'r':
|
||||
cell = padding + cell
|
||||
elif i < len(row) - 1:
|
||||
# Do not pad the final column if left-aligned.
|
||||
cell += padding
|
||||
cells.append(cell.encode('utf-8', 'replace'))
|
||||
try:
|
||||
outbuf.write(b' '.join(cells) + b'\n')
|
||||
except IOError: # pragma: no cover
|
||||
# Can happen on Windows if the pipe is closed early.
|
||||
pass
|
||||
for row in table:
|
||||
cells = []
|
||||
for i, cell in enumerate(row):
|
||||
padding = ' ' * (colwidths[i] - len(cell))
|
||||
if align[i] == 'r':
|
||||
cell = padding + cell
|
||||
elif i < len(row) - 1:
|
||||
# Do not pad the final column if left-aligned.
|
||||
cell += padding
|
||||
cells.append(cell.encode('utf-8', 'replace'))
|
||||
try:
|
||||
outbuf.write(b' '.join(cells) + b'\n')
|
||||
except IOError: # pragma: no cover
|
||||
# Can happen on Windows if the pipe is closed early.
|
||||
pass
|
||||
|
||||
|
||||
def pretty_print(outbuf, parsedblame, show_filenames=False):
|
||||
"""Pretty-prints the output of parse_blame."""
|
||||
table = []
|
||||
for line in parsedblame:
|
||||
author_time = git_dates.timestamp_offset_to_datetime(
|
||||
line.commit.author_time, line.commit.author_tz)
|
||||
row = [line.commit.commithash[:8],
|
||||
'(' + line.commit.author,
|
||||
git_dates.datetime_string(author_time),
|
||||
str(line.lineno_now) + ('*' if line.modified else '') + ')',
|
||||
line.context]
|
||||
if show_filenames:
|
||||
row.insert(1, line.commit.filename)
|
||||
table.append(row)
|
||||
print_table(outbuf, table, align='llllrl' if show_filenames else 'lllrl')
|
||||
"""Pretty-prints the output of parse_blame."""
|
||||
table = []
|
||||
for line in parsedblame:
|
||||
author_time = git_dates.timestamp_offset_to_datetime(
|
||||
line.commit.author_time, line.commit.author_tz)
|
||||
row = [
|
||||
line.commit.commithash[:8], '(' + line.commit.author,
|
||||
git_dates.datetime_string(author_time),
|
||||
str(line.lineno_now) + ('*' if line.modified else '') + ')',
|
||||
line.context
|
||||
]
|
||||
if show_filenames:
|
||||
row.insert(1, line.commit.filename)
|
||||
table.append(row)
|
||||
print_table(outbuf, table, align='llllrl' if show_filenames else 'lllrl')
|
||||
|
||||
|
||||
def get_parsed_blame(filename, revision='HEAD'):
|
||||
blame = git_common.blame(filename, revision=revision, porcelain=True)
|
||||
return list(parse_blame(blame))
|
||||
blame = git_common.blame(filename, revision=revision, porcelain=True)
|
||||
return list(parse_blame(blame))
|
||||
|
||||
|
||||
# Map from (oldrev, newrev) to hunk list (caching the results of git diff, but
|
||||
@@ -156,41 +153,41 @@ diff_hunks_cache = {}
|
||||
|
||||
|
||||
def cache_diff_hunks(oldrev, newrev):
|
||||
def parse_start_length(s):
|
||||
# Chop the '-' or '+'.
|
||||
s = s[1:]
|
||||
# Length is optional (defaults to 1).
|
||||
def parse_start_length(s):
|
||||
# Chop the '-' or '+'.
|
||||
s = s[1:]
|
||||
# Length is optional (defaults to 1).
|
||||
try:
|
||||
start, length = s.split(',')
|
||||
except ValueError:
|
||||
start = s
|
||||
length = 1
|
||||
return int(start), int(length)
|
||||
|
||||
try:
|
||||
start, length = s.split(',')
|
||||
except ValueError:
|
||||
start = s
|
||||
length = 1
|
||||
return int(start), int(length)
|
||||
return diff_hunks_cache[(oldrev, newrev)]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return diff_hunks_cache[(oldrev, newrev)]
|
||||
except KeyError:
|
||||
pass
|
||||
# Use -U0 to get the smallest possible hunks.
|
||||
diff = git_common.diff(oldrev, newrev, '-U0')
|
||||
|
||||
# Use -U0 to get the smallest possible hunks.
|
||||
diff = git_common.diff(oldrev, newrev, '-U0')
|
||||
# Get all the hunks.
|
||||
hunks = []
|
||||
for line in diff.split('\n'):
|
||||
if not line.startswith('@@'):
|
||||
continue
|
||||
ranges = line.split(' ', 3)[1:3]
|
||||
ranges = tuple(parse_start_length(r) for r in ranges)
|
||||
hunks.append(ranges)
|
||||
|
||||
# Get all the hunks.
|
||||
hunks = []
|
||||
for line in diff.split('\n'):
|
||||
if not line.startswith('@@'):
|
||||
continue
|
||||
ranges = line.split(' ', 3)[1:3]
|
||||
ranges = tuple(parse_start_length(r) for r in ranges)
|
||||
hunks.append(ranges)
|
||||
|
||||
diff_hunks_cache[(oldrev, newrev)] = hunks
|
||||
return hunks
|
||||
diff_hunks_cache[(oldrev, newrev)] = hunks
|
||||
return hunks
|
||||
|
||||
|
||||
def approx_lineno_across_revs(filename, newfilename, revision, newrevision,
|
||||
lineno):
|
||||
"""Computes the approximate movement of a line number between two revisions.
|
||||
"""Computes the approximate movement of a line number between two revisions.
|
||||
|
||||
Consider line |lineno| in |filename| at |revision|. This function computes the
|
||||
line number of that line in |newfilename| at |newrevision|. This is
|
||||
@@ -206,183 +203,200 @@ def approx_lineno_across_revs(filename, newfilename, revision, newrevision,
|
||||
Returns:
|
||||
Line number within |newfilename| at |newrevision|.
|
||||
"""
|
||||
# This doesn't work that well if there are a lot of line changes within the
|
||||
# hunk (demonstrated by GitHyperBlameLineMotionTest.testIntraHunkLineMotion).
|
||||
# A fuzzy heuristic that takes the text of the new line and tries to find a
|
||||
# deleted line within the hunk that mostly matches the new line could help.
|
||||
# This doesn't work that well if there are a lot of line changes within the
|
||||
# hunk (demonstrated by
|
||||
# GitHyperBlameLineMotionTest.testIntraHunkLineMotion). A fuzzy heuristic
|
||||
# that takes the text of the new line and tries to find a deleted line
|
||||
# within the hunk that mostly matches the new line could help.
|
||||
|
||||
# Use the <revision>:<filename> syntax to diff between two blobs. This is the
|
||||
# only way to diff a file that has been renamed.
|
||||
old = '%s:%s' % (revision, filename)
|
||||
new = '%s:%s' % (newrevision, newfilename)
|
||||
hunks = cache_diff_hunks(old, new)
|
||||
# Use the <revision>:<filename> syntax to diff between two blobs. This is
|
||||
# the only way to diff a file that has been renamed.
|
||||
old = '%s:%s' % (revision, filename)
|
||||
new = '%s:%s' % (newrevision, newfilename)
|
||||
hunks = cache_diff_hunks(old, new)
|
||||
|
||||
cumulative_offset = 0
|
||||
cumulative_offset = 0
|
||||
|
||||
# Find the hunk containing lineno (if any).
|
||||
for (oldstart, oldlength), (newstart, newlength) in hunks:
|
||||
cumulative_offset += newlength - oldlength
|
||||
# Find the hunk containing lineno (if any).
|
||||
for (oldstart, oldlength), (newstart, newlength) in hunks:
|
||||
cumulative_offset += newlength - oldlength
|
||||
|
||||
if lineno >= oldstart + oldlength:
|
||||
# Not there yet.
|
||||
continue
|
||||
if lineno >= oldstart + oldlength:
|
||||
# Not there yet.
|
||||
continue
|
||||
|
||||
if lineno < oldstart:
|
||||
# Gone too far.
|
||||
break
|
||||
if lineno < oldstart:
|
||||
# Gone too far.
|
||||
break
|
||||
|
||||
# lineno is in [oldstart, oldlength] at revision; [newstart, newlength] at
|
||||
# newrevision.
|
||||
# lineno is in [oldstart, oldlength] at revision; [newstart, newlength]
|
||||
# at newrevision.
|
||||
|
||||
# If newlength == 0, newstart will be the line before the deleted hunk.
|
||||
# Since the line must have been deleted, just return that as the nearest
|
||||
# line in the new file. Caution: newstart can be 0 in this case.
|
||||
if newlength == 0:
|
||||
return max(1, newstart)
|
||||
# If newlength == 0, newstart will be the line before the deleted hunk.
|
||||
# Since the line must have been deleted, just return that as the nearest
|
||||
# line in the new file. Caution: newstart can be 0 in this case.
|
||||
if newlength == 0:
|
||||
return max(1, newstart)
|
||||
|
||||
newend = newstart + newlength - 1
|
||||
newend = newstart + newlength - 1
|
||||
|
||||
# Move lineno based on the amount the entire hunk shifted.
|
||||
lineno = lineno + newstart - oldstart
|
||||
# Constrain the output within the range [newstart, newend].
|
||||
return min(newend, max(newstart, lineno))
|
||||
# Move lineno based on the amount the entire hunk shifted.
|
||||
lineno = lineno + newstart - oldstart
|
||||
# Constrain the output within the range [newstart, newend].
|
||||
return min(newend, max(newstart, lineno))
|
||||
|
||||
# Wasn't in a hunk. Figure out the line motion based on the difference in
|
||||
# length between the hunks seen so far.
|
||||
return lineno + cumulative_offset
|
||||
# Wasn't in a hunk. Figure out the line motion based on the difference in
|
||||
# length between the hunks seen so far.
|
||||
return lineno + cumulative_offset
|
||||
|
||||
|
||||
def hyper_blame(outbuf, ignored, filename, revision):
|
||||
# Map from commit to parsed blame from that commit.
|
||||
blame_from = {}
|
||||
filename = os.path.normpath(filename)
|
||||
# Map from commit to parsed blame from that commit.
|
||||
blame_from = {}
|
||||
filename = os.path.normpath(filename)
|
||||
|
||||
def cache_blame_from(filename, commithash):
|
||||
try:
|
||||
return blame_from[commithash]
|
||||
except KeyError:
|
||||
parsed = get_parsed_blame(filename, commithash)
|
||||
blame_from[commithash] = parsed
|
||||
return parsed
|
||||
|
||||
def cache_blame_from(filename, commithash):
|
||||
try:
|
||||
return blame_from[commithash]
|
||||
except KeyError:
|
||||
parsed = get_parsed_blame(filename, commithash)
|
||||
blame_from[commithash] = parsed
|
||||
return parsed
|
||||
parsed = cache_blame_from(filename, git_common.hash_one(revision))
|
||||
except subprocess2.CalledProcessError as e:
|
||||
sys.stderr.write(e.stderr.decode())
|
||||
return e.returncode
|
||||
|
||||
try:
|
||||
parsed = cache_blame_from(filename, git_common.hash_one(revision))
|
||||
except subprocess2.CalledProcessError as e:
|
||||
sys.stderr.write(e.stderr.decode())
|
||||
return e.returncode
|
||||
new_parsed = []
|
||||
|
||||
new_parsed = []
|
||||
# We don't show filenames in blame output unless we have to.
|
||||
show_filenames = False
|
||||
|
||||
# We don't show filenames in blame output unless we have to.
|
||||
show_filenames = False
|
||||
for line in parsed:
|
||||
# If a line references an ignored commit, blame that commit's parent
|
||||
# repeatedly until we find a non-ignored commit.
|
||||
while line.commit.commithash in ignored:
|
||||
if line.commit.previous is None:
|
||||
# You can't ignore the commit that added this file.
|
||||
break
|
||||
|
||||
for line in parsed:
|
||||
# If a line references an ignored commit, blame that commit's parent
|
||||
# repeatedly until we find a non-ignored commit.
|
||||
while line.commit.commithash in ignored:
|
||||
if line.commit.previous is None:
|
||||
# You can't ignore the commit that added this file.
|
||||
break
|
||||
previouscommit, previousfilename = line.commit.previous.split(
|
||||
' ', 1)
|
||||
parent_blame = cache_blame_from(previousfilename, previouscommit)
|
||||
|
||||
previouscommit, previousfilename = line.commit.previous.split(' ', 1)
|
||||
parent_blame = cache_blame_from(previousfilename, previouscommit)
|
||||
if len(parent_blame) == 0:
|
||||
# The previous version of this file was empty, therefore, you
|
||||
# can't ignore this commit.
|
||||
break
|
||||
|
||||
if len(parent_blame) == 0:
|
||||
# The previous version of this file was empty, therefore, you can't
|
||||
# ignore this commit.
|
||||
break
|
||||
# line.lineno_then is the line number in question at line.commit. We
|
||||
# need to translate that line number so that it refers to the
|
||||
# position of the same line on previouscommit.
|
||||
lineno_previous = approx_lineno_across_revs(line.commit.filename,
|
||||
previousfilename,
|
||||
line.commit.commithash,
|
||||
previouscommit,
|
||||
line.lineno_then)
|
||||
logging.debug('ignore commit %s on line p%d/t%d/n%d',
|
||||
line.commit.commithash, lineno_previous,
|
||||
line.lineno_then, line.lineno_now)
|
||||
|
||||
# line.lineno_then is the line number in question at line.commit. We need
|
||||
# to translate that line number so that it refers to the position of the
|
||||
# same line on previouscommit.
|
||||
lineno_previous = approx_lineno_across_revs(
|
||||
line.commit.filename, previousfilename, line.commit.commithash,
|
||||
previouscommit, line.lineno_then)
|
||||
logging.debug('ignore commit %s on line p%d/t%d/n%d',
|
||||
line.commit.commithash, lineno_previous, line.lineno_then,
|
||||
line.lineno_now)
|
||||
# Get the line at lineno_previous in the parent commit.
|
||||
assert 1 <= lineno_previous <= len(parent_blame)
|
||||
newline = parent_blame[lineno_previous - 1]
|
||||
|
||||
# Get the line at lineno_previous in the parent commit.
|
||||
assert 1 <= lineno_previous <= len(parent_blame)
|
||||
newline = parent_blame[lineno_previous - 1]
|
||||
# Replace the commit and lineno_then, but not the lineno_now or
|
||||
# context.
|
||||
line = BlameLine(newline.commit, line.context, newline.lineno_then,
|
||||
line.lineno_now, True)
|
||||
logging.debug(' replacing with %r', line)
|
||||
|
||||
# Replace the commit and lineno_then, but not the lineno_now or context.
|
||||
line = BlameLine(newline.commit, line.context, newline.lineno_then,
|
||||
line.lineno_now, True)
|
||||
logging.debug(' replacing with %r', line)
|
||||
# If any line has a different filename to the file's current name, turn
|
||||
# on filename display for the entire blame output. Use normpath to make
|
||||
# variable consistent across platforms.
|
||||
if os.path.normpath(line.commit.filename) != filename:
|
||||
show_filenames = True
|
||||
|
||||
# If any line has a different filename to the file's current name, turn on
|
||||
# filename display for the entire blame output.
|
||||
# Use normpath to make variable consistent across platforms.
|
||||
if os.path.normpath(line.commit.filename) != filename:
|
||||
show_filenames = True
|
||||
new_parsed.append(line)
|
||||
|
||||
new_parsed.append(line)
|
||||
pretty_print(outbuf, new_parsed, show_filenames=show_filenames)
|
||||
|
||||
pretty_print(outbuf, new_parsed, show_filenames=show_filenames)
|
||||
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def parse_ignore_file(ignore_file):
|
||||
for line in ignore_file:
|
||||
line = line.split('#', 1)[0].strip()
|
||||
if line:
|
||||
yield line
|
||||
for line in ignore_file:
|
||||
line = line.split('#', 1)[0].strip()
|
||||
if line:
|
||||
yield line
|
||||
|
||||
|
||||
def main(args, outbuf):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='git hyper-blame',
|
||||
description='git blame with support for ignoring certain commits.')
|
||||
parser.add_argument('-i', metavar='REVISION', action='append', dest='ignored',
|
||||
default=[], help='a revision to ignore')
|
||||
parser.add_argument('--ignore-file', metavar='FILE', dest='ignore_file',
|
||||
help='a file containing a list of revisions to ignore')
|
||||
parser.add_argument('--no-default-ignores', dest='no_default_ignores',
|
||||
action='store_true',
|
||||
help='Do not ignore commits from .git-blame-ignore-revs.')
|
||||
parser.add_argument('revision', nargs='?', default='HEAD', metavar='REVISION',
|
||||
help='revision to look at')
|
||||
parser.add_argument('filename', metavar='FILE', help='filename to blame')
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='git hyper-blame',
|
||||
description='git blame with support for ignoring certain commits.')
|
||||
parser.add_argument('-i',
|
||||
metavar='REVISION',
|
||||
action='append',
|
||||
dest='ignored',
|
||||
default=[],
|
||||
help='a revision to ignore')
|
||||
parser.add_argument('--ignore-file',
|
||||
metavar='FILE',
|
||||
dest='ignore_file',
|
||||
help='a file containing a list of revisions to ignore')
|
||||
parser.add_argument(
|
||||
'--no-default-ignores',
|
||||
dest='no_default_ignores',
|
||||
action='store_true',
|
||||
help='Do not ignore commits from .git-blame-ignore-revs.')
|
||||
parser.add_argument('revision',
|
||||
nargs='?',
|
||||
default='HEAD',
|
||||
metavar='REVISION',
|
||||
help='revision to look at')
|
||||
parser.add_argument('filename', metavar='FILE', help='filename to blame')
|
||||
|
||||
args = parser.parse_args(args)
|
||||
try:
|
||||
repo_root = git_common.repo_root()
|
||||
except subprocess2.CalledProcessError as e:
|
||||
sys.stderr.write(e.stderr.decode())
|
||||
return e.returncode
|
||||
|
||||
# Make filename relative to the repository root, and cd to the root dir (so
|
||||
# all filenames throughout this script are relative to the root).
|
||||
filename = os.path.relpath(args.filename, repo_root)
|
||||
os.chdir(repo_root)
|
||||
|
||||
# Normalize filename so we can compare it to other filenames git gives us.
|
||||
filename = os.path.normpath(filename)
|
||||
filename = os.path.normcase(filename)
|
||||
|
||||
ignored_list = list(args.ignored)
|
||||
if not args.no_default_ignores and os.path.exists(DEFAULT_IGNORE_FILE_NAME):
|
||||
with open(DEFAULT_IGNORE_FILE_NAME) as ignore_file:
|
||||
ignored_list.extend(parse_ignore_file(ignore_file))
|
||||
|
||||
if args.ignore_file:
|
||||
with open(args.ignore_file) as ignore_file:
|
||||
ignored_list.extend(parse_ignore_file(ignore_file))
|
||||
|
||||
ignored = set()
|
||||
for c in ignored_list:
|
||||
args = parser.parse_args(args)
|
||||
try:
|
||||
ignored.add(git_common.hash_one(c))
|
||||
repo_root = git_common.repo_root()
|
||||
except subprocess2.CalledProcessError as e:
|
||||
# Custom warning string (the message from git-rev-parse is inappropriate).
|
||||
sys.stderr.write('warning: unknown revision \'%s\'.\n' % c)
|
||||
sys.stderr.write(e.stderr.decode())
|
||||
return e.returncode
|
||||
|
||||
return hyper_blame(outbuf, ignored, filename, args.revision)
|
||||
# Make filename relative to the repository root, and cd to the root dir (so
|
||||
# all filenames throughout this script are relative to the root).
|
||||
filename = os.path.relpath(args.filename, repo_root)
|
||||
os.chdir(repo_root)
|
||||
|
||||
# Normalize filename so we can compare it to other filenames git gives us.
|
||||
filename = os.path.normpath(filename)
|
||||
filename = os.path.normcase(filename)
|
||||
|
||||
ignored_list = list(args.ignored)
|
||||
if not args.no_default_ignores and os.path.exists(DEFAULT_IGNORE_FILE_NAME):
|
||||
with open(DEFAULT_IGNORE_FILE_NAME) as ignore_file:
|
||||
ignored_list.extend(parse_ignore_file(ignore_file))
|
||||
|
||||
if args.ignore_file:
|
||||
with open(args.ignore_file) as ignore_file:
|
||||
ignored_list.extend(parse_ignore_file(ignore_file))
|
||||
|
||||
ignored = set()
|
||||
for c in ignored_list:
|
||||
try:
|
||||
ignored.add(git_common.hash_one(c))
|
||||
except subprocess2.CalledProcessError as e:
|
||||
# Custom warning string (the message from git-rev-parse is
|
||||
# inappropriate).
|
||||
sys.stderr.write('warning: unknown revision \'%s\'.\n' % c)
|
||||
|
||||
return hyper_blame(outbuf, ignored, filename, args.revision)
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
setup_color.init()
|
||||
with git_common.less() as less_input:
|
||||
sys.exit(main(sys.argv[1:], less_input))
|
||||
setup_color.init()
|
||||
with git_common.less() as less_input:
|
||||
sys.exit(main(sys.argv[1:], less_input))
|
||||
|
||||
Reference in New Issue
Block a user