Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright 2014 the V8 project authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 import argparse | |
| 7 import subprocess | |
| 8 import sys | |
| 9 | |
| 10 | |
| 11 def GetArgs(): | |
| 12 parser = argparse.ArgumentParser( | |
| 13 description="Finds a commit that a given patch can be applied to. " | |
| 14 "Does not actually apply the patch or modify your checkout " | |
| 15 "in any way.") | |
| 16 parser.add_argument("patch_file", help="Patch file to match") | |
| 17 parser.add_argument( | |
| 18 "--branch", "-b", default="origin/master", type=str, | |
| 19 help="Git tree-ish where to start searching for commits, " | |
| 20 "default: %(default)s") | |
| 21 parser.add_argument( | |
| 22 "--limit", "-l", default=500, type=int, | |
| 23 help="Maximum number of commits to search, default: %(default)s") | |
| 24 parser.add_argument( | |
| 25 "--verbose", "-v", default=False, action="store_true", | |
|
Michael Achenbach
2014/12/16 10:29:54
nit: Could use python's logging module. Set it to
Jakob Kummerow
2014/12/16 13:51:31
Acknowledged. IIUC this wouldn't provide observabl
| |
| 26 help="Print verbose output for your entertainment") | |
| 27 return parser.parse_args() | |
| 28 | |
| 29 | |
| 30 def FindFilesInPatch(patch_file): | |
| 31 files = {} | |
| 32 next_file = "" | |
| 33 with open(patch_file) as patch: | |
| 34 for line in patch: | |
| 35 if line.startswith("diff --git "): | |
|
Michael Achenbach
2014/12/16 10:29:54
Remark (no action required): This scans all lines
Jakob Kummerow
2014/12/16 13:51:31
Actually, I'm pretty sure it does work on all vali
Michael Achenbach
2014/12/16 13:56:18
Ah - I didn't see the space in the beginning of th
| |
| 36 # diff --git a/src/objects.cc b/src/objects.cc | |
|
Michael Achenbach
2014/12/16 10:29:54
The patch could have been made with the option --s
Jakob Kummerow
2014/12/16 13:51:31
I'd just say the first time someone encounters thi
| |
| 37 words = line.split() | |
| 38 assert words[2].startswith("a/") and len(words[2]) > 2 | |
| 39 next_file = words[2][2:] | |
| 40 elif line.startswith("index "): | |
| 41 # index add3e61..d1bbf6a 100644 | |
| 42 hashes = line.split()[1] | |
| 43 old_hash = hashes.split("..")[0] | |
| 44 if old_hash.startswith("0000000"): continue # Ignore new files. | |
| 45 files[next_file] = old_hash | |
| 46 return files | |
| 47 | |
| 48 | |
| 49 def GetGitCommitHash(treeish): | |
| 50 cmd = ["git", "log", "-1", "--format=%H", treeish] | |
| 51 return subprocess.check_output(cmd).strip() | |
| 52 | |
| 53 | |
| 54 def CountMatchingFiles(commit, files): | |
| 55 matched_files = 0 | |
| 56 # Calling out to git once and parsing the result Python-side is faster | |
| 57 # than calling 'git ls-tree' for every file. | |
| 58 output = subprocess.check_output(["git", "ls-tree", "-r", commit]) | |
|
Michael Achenbach
2014/12/16 10:29:54
Possible improvement: This command accepts a list
Jakob Kummerow
2014/12/16 13:51:31
Done -- good idea!
| |
| 59 for line in output.splitlines(): | |
| 60 # 100644 blob c6d5daaa7d42e49a653f9861224aad0a0244b944 src/objects.cc | |
| 61 words = line.split() | |
|
Michael Achenbach
2014/12/16 10:29:54
nit: You can assign more explicitely:
_, _, actual
Jakob Kummerow
2014/12/16 13:51:31
Done.
| |
| 62 filename = words[3] | |
| 63 if filename in files: | |
|
Michael Achenbach
2014/12/16 10:29:54
nit: possible optimization:
expected_hash = files.
Jakob Kummerow
2014/12/16 13:51:31
Acknowledged, but after your comment above, we don
| |
| 64 expected_hash = files[filename] | |
| 65 actual_hash = words[2] | |
| 66 if actual_hash.startswith(expected_hash): matched_files += 1 | |
| 67 return matched_files | |
| 68 | |
| 69 | |
| 70 def FindFirstMatchingCommit(start, files, limit, verbose): | |
| 71 commit = GetGitCommitHash(start) | |
| 72 num_files = len(files) | |
| 73 if verbose: print(">>> Found %d files modified by patch." % num_files) | |
| 74 while limit > 0: | |
|
Michael Achenbach
2014/12/16 10:29:54
nit: Maybe: for _ in range(limit):
Jakob Kummerow
2014/12/16 13:51:31
Done.
| |
| 75 limit -= 1 | |
| 76 matched_files = CountMatchingFiles(commit, files) | |
| 77 if verbose: print("Commit %s matched %d files" % (commit, matched_files)) | |
| 78 if matched_files == num_files: | |
| 79 return commit | |
| 80 commit = GetGitCommitHash("%s^" % commit) | |
| 81 print("Sorry, no matching commit found. " | |
| 82 "Try running 'git fetch', specifying the correct --branch, " | |
| 83 "and/or setting a higher --limit.") | |
| 84 sys.exit(1) | |
| 85 | |
| 86 | |
| 87 if __name__ == "__main__": | |
| 88 args = GetArgs() | |
| 89 files = FindFilesInPatch(args.patch_file) | |
| 90 commit = FindFirstMatchingCommit(args.branch, files, args.limit, args.verbose) | |
| 91 if args.verbose: | |
| 92 print(">>> Matching commit: %s" % commit) | |
| 93 print(subprocess.check_output(["git", "log", "-1", commit])) | |
| 94 print(">>> Kthxbai.") | |
| 95 else: | |
| 96 print(commit) | |
| OLD | NEW |