Import tools/ from master branch
Change-Id: I476f43ea513e7c140f4e4f14df73dd3131cb2692
This commit is contained in:
160
tools/ftfy.sh
Executable file
160
tools/ftfy.sh
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
self="$0"
|
||||||
|
dirname_self=$(dirname "$self")
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF >&2
|
||||||
|
Usage: $self [option]
|
||||||
|
|
||||||
|
This script applies a whitespace transformation to the commit at HEAD. If no
|
||||||
|
options are given, then the modified files are left in the working tree.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Shows this message
|
||||||
|
-n, --dry-run Shows a diff of the changes to be made.
|
||||||
|
--amend Squashes the changes into the commit at HEAD
|
||||||
|
This option will also reformat the commit message.
|
||||||
|
--commit Creates a new commit containing only the whitespace changes
|
||||||
|
--msg-only Reformat the commit message only, ignore the patch itself.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
rm -f ${CLEAN_FILES}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "${self##*/}: $@" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vpx_style() {
|
||||||
|
astyle --style=bsd --min-conditional-indent=0 --break-blocks \
|
||||||
|
--pad-oper --pad-header --unpad-paren \
|
||||||
|
--align-pointer=name \
|
||||||
|
--indent-preprocessor --convert-tabs --indent-labels \
|
||||||
|
--suffix=none --quiet "$@"
|
||||||
|
sed -i "" 's/[[:space:]]\{1,\},/,/g' "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
apply() {
|
||||||
|
[ $INTERSECT_RESULT -ne 0 ] && patch -p1 < "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
commit() {
|
||||||
|
LAST_CHANGEID=$(git show | awk '/Change-Id:/{print $2}')
|
||||||
|
if [ -z "$LAST_CHANGEID" ]; then
|
||||||
|
log "HEAD doesn't have a Change-Id, unable to generate a new commit"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build a deterministic Change-Id from the parent's
|
||||||
|
NEW_CHANGEID=${LAST_CHANGEID}-styled
|
||||||
|
NEW_CHANGEID=I$(echo $NEW_CHANGEID | git hash-object --stdin)
|
||||||
|
|
||||||
|
# Commit, preserving authorship from the parent commit.
|
||||||
|
git commit -a -C HEAD > /dev/null
|
||||||
|
git commit --amend -F- << EOF
|
||||||
|
Cosmetic: Fix whitespace in change ${LAST_CHANGEID:0:9}
|
||||||
|
|
||||||
|
Change-Id: ${NEW_CHANGEID}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
show_commit_msg_diff() {
|
||||||
|
if [ $DIFF_MSG_RESULT -ne 0 ]; then
|
||||||
|
log "Modified commit message:"
|
||||||
|
diff -u "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG" | tail -n +3
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
amend() {
|
||||||
|
show_commit_msg_diff
|
||||||
|
if [ $DIFF_MSG_RESULT -ne 0 ] || [ $INTERSECT_RESULT -ne 0 ]; then
|
||||||
|
git commit -a --amend -F "$NEW_COMMIT_MSG"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
diff_msg() {
|
||||||
|
git log -1 --format=%B > "$ORIG_COMMIT_MSG"
|
||||||
|
"${dirname_self}"/wrap-commit-msg.py \
|
||||||
|
< "$ORIG_COMMIT_MSG" > "$NEW_COMMIT_MSG"
|
||||||
|
cmp -s "$ORIG_COMMIT_MSG" "$NEW_COMMIT_MSG"
|
||||||
|
DIFF_MSG_RESULT=$?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
ORIG_DIFF=orig.diff.$$
|
||||||
|
MODIFIED_DIFF=modified.diff.$$
|
||||||
|
FINAL_DIFF=final.diff.$$
|
||||||
|
ORIG_COMMIT_MSG=orig.commit-msg.$$
|
||||||
|
NEW_COMMIT_MSG=new.commit-msg.$$
|
||||||
|
CLEAN_FILES="${ORIG_DIFF} ${MODIFIED_DIFF} ${FINAL_DIFF}"
|
||||||
|
CLEAN_FILES="${CLEAN_FILES} ${ORIG_COMMIT_MSG} ${NEW_COMMIT_MSG}"
|
||||||
|
|
||||||
|
# Preconditions
|
||||||
|
[ $# -lt 2 ] || usage
|
||||||
|
|
||||||
|
# Check that astyle supports pad-header and align-pointer=name
|
||||||
|
if ! astyle --pad-header --align-pointer=name < /dev/null; then
|
||||||
|
log "Install astyle v1.24 or newer"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff --quiet HEAD; then
|
||||||
|
log "Working tree is dirty, commit your changes first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Need to be in the root
|
||||||
|
cd "$(git rev-parse --show-toplevel)"
|
||||||
|
|
||||||
|
# Collect the original diff
|
||||||
|
git show > "${ORIG_DIFF}"
|
||||||
|
|
||||||
|
# Apply the style guide on new and modified files and collect its diff
|
||||||
|
for f in $(git diff HEAD^ --name-only -M90 --diff-filter=AM \
|
||||||
|
| grep '\.[ch]$'); do
|
||||||
|
case "$f" in
|
||||||
|
third_party/*) continue;;
|
||||||
|
nestegg/*) continue;;
|
||||||
|
esac
|
||||||
|
vpx_style "$f"
|
||||||
|
done
|
||||||
|
git diff --no-color --no-ext-diff > "${MODIFIED_DIFF}"
|
||||||
|
|
||||||
|
# Intersect the two diffs
|
||||||
|
"${dirname_self}"/intersect-diffs.py \
|
||||||
|
"${ORIG_DIFF}" "${MODIFIED_DIFF}" > "${FINAL_DIFF}"
|
||||||
|
INTERSECT_RESULT=$?
|
||||||
|
git reset --hard >/dev/null
|
||||||
|
|
||||||
|
# Fixup the commit message
|
||||||
|
diff_msg
|
||||||
|
|
||||||
|
# Handle options
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) usage;;
|
||||||
|
-n|--dry-run) cat "${FINAL_DIFF}"; show_commit_msg_diff;;
|
||||||
|
--commit) apply "${FINAL_DIFF}"; commit;;
|
||||||
|
--amend) apply "${FINAL_DIFF}"; amend;;
|
||||||
|
--msg-only) amend;;
|
||||||
|
*) usage;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
apply "${FINAL_DIFF}"
|
||||||
|
if ! git diff --quiet; then
|
||||||
|
log "Formatting changes applied, verify and commit."
|
||||||
|
log "See also: http://www.webmproject.org/code/contribute/conventions/"
|
||||||
|
git diff --stat
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f ${CLEAN_FILES}
|
188
tools/intersect-diffs.py
Executable file
188
tools/intersect-diffs.py
Executable file
@@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
## Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||||
|
##
|
||||||
|
## Use of this source code is governed by a BSD-style license
|
||||||
|
## that can be found in the LICENSE file in the root of the source
|
||||||
|
## tree. An additional intellectual property rights grant can be found
|
||||||
|
## in the file PATENTS. All contributing project authors may
|
||||||
|
## be found in the AUTHORS file in the root of the source tree.
|
||||||
|
##
|
||||||
|
"""Calculates the "intersection" of two unified diffs.
|
||||||
|
|
||||||
|
Given two diffs, A and B, it finds all hunks in B that had non-context lines
|
||||||
|
in A and prints them to stdout. This is useful to determine the hunks in B that
|
||||||
|
are relevant to A. The resulting file can be applied with patch(1) on top of A.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "jkoleszar@google.com"
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class DiffLines(object):
|
||||||
|
"""A container for one half of a diff."""
|
||||||
|
|
||||||
|
def __init__(self, filename, offset, length):
|
||||||
|
self.filename = filename
|
||||||
|
self.offset = offset
|
||||||
|
self.length = length
|
||||||
|
self.lines = []
|
||||||
|
self.delta_line_nums = []
|
||||||
|
|
||||||
|
def Append(self, line):
|
||||||
|
l = len(self.lines)
|
||||||
|
if line[0] != " ":
|
||||||
|
self.delta_line_nums.append(self.offset + l)
|
||||||
|
self.lines.append(line[1:])
|
||||||
|
assert l+1 <= self.length
|
||||||
|
|
||||||
|
def Complete(self):
|
||||||
|
return len(self.lines) == self.length
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return item >= self.offset and item <= self.offset + self.length - 1
|
||||||
|
|
||||||
|
|
||||||
|
class DiffHunk(object):
|
||||||
|
"""A container for one diff hunk, consisting of two DiffLines."""
|
||||||
|
|
||||||
|
def __init__(self, header, file_a, file_b, start_a, len_a, start_b, len_b):
|
||||||
|
self.header = header
|
||||||
|
self.left = DiffLines(file_a, start_a, len_a)
|
||||||
|
self.right = DiffLines(file_b, start_b, len_b)
|
||||||
|
self.lines = []
|
||||||
|
|
||||||
|
def Append(self, line):
|
||||||
|
"""Adds a line to the DiffHunk and its DiffLines children."""
|
||||||
|
if line[0] == "-":
|
||||||
|
self.left.Append(line)
|
||||||
|
elif line[0] == "+":
|
||||||
|
self.right.Append(line)
|
||||||
|
elif line[0] == " ":
|
||||||
|
self.left.Append(line)
|
||||||
|
self.right.Append(line)
|
||||||
|
else:
|
||||||
|
assert False, ("Unrecognized character at start of diff line "
|
||||||
|
"%r" % line[0])
|
||||||
|
self.lines.append(line)
|
||||||
|
|
||||||
|
def Complete(self):
|
||||||
|
return self.left.Complete() and self.right.Complete()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "DiffHunk(%s, %s, len %d)" % (
|
||||||
|
self.left.filename, self.right.filename,
|
||||||
|
max(self.left.length, self.right.length))
|
||||||
|
|
||||||
|
|
||||||
|
def ParseDiffHunks(stream):
|
||||||
|
"""Walk a file-like object, yielding DiffHunks as they're parsed."""
|
||||||
|
|
||||||
|
file_regex = re.compile(r"(\+\+\+|---) (\S+)")
|
||||||
|
range_regex = re.compile(r"@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?")
|
||||||
|
hunk = None
|
||||||
|
while True:
|
||||||
|
line = stream.readline()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
|
||||||
|
if hunk is None:
|
||||||
|
# Parse file names
|
||||||
|
diff_file = file_regex.match(line)
|
||||||
|
if diff_file:
|
||||||
|
if line.startswith("---"):
|
||||||
|
a_line = line
|
||||||
|
a = diff_file.group(2)
|
||||||
|
continue
|
||||||
|
if line.startswith("+++"):
|
||||||
|
b_line = line
|
||||||
|
b = diff_file.group(2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Parse offset/lengths
|
||||||
|
diffrange = range_regex.match(line)
|
||||||
|
if diffrange:
|
||||||
|
if diffrange.group(2):
|
||||||
|
start_a = int(diffrange.group(1))
|
||||||
|
len_a = int(diffrange.group(3))
|
||||||
|
else:
|
||||||
|
start_a = 1
|
||||||
|
len_a = int(diffrange.group(1))
|
||||||
|
|
||||||
|
if diffrange.group(5):
|
||||||
|
start_b = int(diffrange.group(4))
|
||||||
|
len_b = int(diffrange.group(6))
|
||||||
|
else:
|
||||||
|
start_b = 1
|
||||||
|
len_b = int(diffrange.group(4))
|
||||||
|
|
||||||
|
header = [a_line, b_line, line]
|
||||||
|
hunk = DiffHunk(header, a, b, start_a, len_a, start_b, len_b)
|
||||||
|
else:
|
||||||
|
# Add the current line to the hunk
|
||||||
|
hunk.Append(line)
|
||||||
|
|
||||||
|
# See if the whole hunk has been parsed. If so, yield it and prepare
|
||||||
|
# for the next hunk.
|
||||||
|
if hunk.Complete():
|
||||||
|
yield hunk
|
||||||
|
hunk = None
|
||||||
|
|
||||||
|
# Partial hunks are a parse error
|
||||||
|
assert hunk is None
|
||||||
|
|
||||||
|
|
||||||
|
def FormatDiffHunks(hunks):
|
||||||
|
"""Re-serialize a list of DiffHunks."""
|
||||||
|
r = []
|
||||||
|
last_header = None
|
||||||
|
for hunk in hunks:
|
||||||
|
this_header = hunk.header[0:2]
|
||||||
|
if last_header != this_header:
|
||||||
|
r.extend(hunk.header)
|
||||||
|
last_header = this_header
|
||||||
|
else:
|
||||||
|
r.extend(hunk.header[2])
|
||||||
|
r.extend(hunk.lines)
|
||||||
|
r.append("\n")
|
||||||
|
return "".join(r)
|
||||||
|
|
||||||
|
|
||||||
|
def ZipHunks(rhs_hunks, lhs_hunks):
|
||||||
|
"""Join two hunk lists on filename."""
|
||||||
|
for rhs_hunk in rhs_hunks:
|
||||||
|
rhs_file = rhs_hunk.right.filename.split("/")[1:]
|
||||||
|
|
||||||
|
for lhs_hunk in lhs_hunks:
|
||||||
|
lhs_file = lhs_hunk.left.filename.split("/")[1:]
|
||||||
|
if lhs_file != rhs_file:
|
||||||
|
continue
|
||||||
|
yield (rhs_hunk, lhs_hunk)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
old_hunks = [x for x in ParseDiffHunks(open(sys.argv[1], "r"))]
|
||||||
|
new_hunks = [x for x in ParseDiffHunks(open(sys.argv[2], "r"))]
|
||||||
|
out_hunks = []
|
||||||
|
|
||||||
|
# Join the right hand side of the older diff with the left hand side of the
|
||||||
|
# newer diff.
|
||||||
|
for old_hunk, new_hunk in ZipHunks(old_hunks, new_hunks):
|
||||||
|
if new_hunk in out_hunks:
|
||||||
|
continue
|
||||||
|
old_lines = old_hunk.right
|
||||||
|
new_lines = new_hunk.left
|
||||||
|
|
||||||
|
# Determine if this hunk overlaps any non-context line from the other
|
||||||
|
for i in old_lines.delta_line_nums:
|
||||||
|
if i in new_lines:
|
||||||
|
out_hunks.append(new_hunk)
|
||||||
|
break
|
||||||
|
|
||||||
|
if out_hunks:
|
||||||
|
print FormatDiffHunks(out_hunks)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
70
tools/wrap-commit-msg.py
Executable file
70
tools/wrap-commit-msg.py
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
## Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||||
|
##
|
||||||
|
## Use of this source code is governed by a BSD-style license
|
||||||
|
## that can be found in the LICENSE file in the root of the source
|
||||||
|
## tree. An additional intellectual property rights grant can be found
|
||||||
|
## in the file PATENTS. All contributing project authors may
|
||||||
|
## be found in the AUTHORS file in the root of the source tree.
|
||||||
|
##
|
||||||
|
"""Wraps paragraphs of text, preserving manual formatting
|
||||||
|
|
||||||
|
This is like fold(1), but has the special convention of not modifying lines
|
||||||
|
that start with whitespace. This allows you to intersperse blocks with
|
||||||
|
special formatting, like code blocks, with written prose. The prose will
|
||||||
|
be wordwrapped, and the manual formatting will be preserved.
|
||||||
|
|
||||||
|
* This won't handle the case of a bulleted (or ordered) list specially, so
|
||||||
|
manual wrapping must be done.
|
||||||
|
|
||||||
|
Occasionally it's useful to put something with explicit formatting that
|
||||||
|
doesn't look at all like a block of text inline.
|
||||||
|
|
||||||
|
indicator = has_leading_whitespace(line);
|
||||||
|
if (indicator)
|
||||||
|
preserve_formatting(line);
|
||||||
|
|
||||||
|
The intent is that this docstring would make it through the transform
|
||||||
|
and still be legible and presented as it is in the source. If additional
|
||||||
|
cases are handled, update this doc to describe the effect.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "jkoleszar@google.com"
|
||||||
|
import textwrap
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def wrap(text):
|
||||||
|
if text:
|
||||||
|
return textwrap.fill(text, break_long_words=False) + '\n'
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def main(fileobj):
|
||||||
|
text = ""
|
||||||
|
output = ""
|
||||||
|
while True:
|
||||||
|
line = fileobj.readline()
|
||||||
|
if not line:
|
||||||
|
break
|
||||||
|
|
||||||
|
if line.lstrip() == line:
|
||||||
|
text += line
|
||||||
|
else:
|
||||||
|
output += wrap(text)
|
||||||
|
text=""
|
||||||
|
output += line
|
||||||
|
output += wrap(text)
|
||||||
|
|
||||||
|
# Replace the file or write to stdout.
|
||||||
|
if fileobj == sys.stdin:
|
||||||
|
fileobj = sys.stdout
|
||||||
|
else:
|
||||||
|
fileobj.seek(0)
|
||||||
|
fileobj.truncate(0)
|
||||||
|
fileobj.write(output)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
main(open(sys.argv[1], "r+"))
|
||||||
|
else:
|
||||||
|
main(sys.stdin)
|
Reference in New Issue
Block a user