Chromium Code Reviews

Side by Side Diff: tools/find-commit-for-patch.py

Issue 799273003: Add tools/find-commit-for-patch.py (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix 'new file' corner case Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine