123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- #!/usr/bin/env python
- # Copyright 2014 the V8 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.
- # for py2/py3 compatibility
- from __future__ import print_function
- import argparse
- import subprocess
- import sys
- def GetArgs():
- parser = argparse.ArgumentParser(
- description="Finds a commit that a given patch can be applied to. "
- "Does not actually apply the patch or modify your checkout "
- "in any way.")
- parser.add_argument("patch_file", help="Patch file to match")
- parser.add_argument(
- "--branch", "-b", default="origin/master", type=str,
- help="Git tree-ish where to start searching for commits, "
- "default: %(default)s")
- parser.add_argument(
- "--limit", "-l", default=500, type=int,
- help="Maximum number of commits to search, default: %(default)s")
- parser.add_argument(
- "--verbose", "-v", default=False, action="store_true",
- help="Print verbose output for your entertainment")
- return parser.parse_args()
- def FindFilesInPatch(patch_file):
- files = {}
- next_file = ""
- with open(patch_file) as patch:
- for line in patch:
- if line.startswith("diff --git "):
- # diff --git a/src/objects.cc b/src/objects.cc
- words = line.split()
- assert words[2].startswith("a/") and len(words[2]) > 2
- next_file = words[2][2:]
- elif line.startswith("index "):
- # index add3e61..d1bbf6a 100644
- hashes = line.split()[1]
- old_hash = hashes.split("..")[0]
- if old_hash.startswith("0000000"): continue # Ignore new files.
- files[next_file] = old_hash
- return files
- def GetGitCommitHash(treeish):
- cmd = ["git", "log", "-1", "--format=%H", treeish]
- return subprocess.check_output(cmd).strip()
- def CountMatchingFiles(commit, files):
- matched_files = 0
- # Calling out to git once and parsing the result Python-side is faster
- # than calling 'git ls-tree' for every file.
- cmd = ["git", "ls-tree", "-r", commit] + [f for f in files]
- output = subprocess.check_output(cmd)
- for line in output.splitlines():
- # 100644 blob c6d5daaa7d42e49a653f9861224aad0a0244b944 src/objects.cc
- _, _, actual_hash, filename = line.split()
- expected_hash = files[filename]
- if actual_hash.startswith(expected_hash): matched_files += 1
- return matched_files
- def FindFirstMatchingCommit(start, files, limit, verbose):
- commit = GetGitCommitHash(start)
- num_files = len(files)
- if verbose: print(">>> Found %d files modified by patch." % num_files)
- for _ in range(limit):
- matched_files = CountMatchingFiles(commit, files)
- if verbose: print("Commit %s matched %d files" % (commit, matched_files))
- if matched_files == num_files:
- return commit
- commit = GetGitCommitHash("%s^" % commit)
- print("Sorry, no matching commit found. "
- "Try running 'git fetch', specifying the correct --branch, "
- "and/or setting a higher --limit.")
- sys.exit(1)
- if __name__ == "__main__":
- args = GetArgs()
- files = FindFilesInPatch(args.patch_file)
- commit = FindFirstMatchingCommit(args.branch, files, args.limit, args.verbose)
- if args.verbose:
- print(">>> Matching commit: %s" % commit)
- print(subprocess.check_output(["git", "log", "-1", commit]))
- print(">>> Kthxbai.")
- else:
- print(commit)
|