| Index: tools/release/search_related_commits.py
|
| diff --git a/tools/release/search_related_commits.py b/tools/release/search_related_commits.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..aae258443b504bd351af92365011bfd36d468d6b
|
| --- /dev/null
|
| +++ b/tools/release/search_related_commits.py
|
| @@ -0,0 +1,218 @@
|
| +#!/usr/bin/env python
|
| +# Copyright 2015 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.
|
| +
|
| +import argparse
|
| +import operator
|
| +import os
|
| +import re
|
| +from sets import Set
|
| +from subprocess import Popen, PIPE
|
| +import sys
|
| +
|
| +def search_all_related_commits(
|
| + git_working_dir, start_hash, until, separator, verbose=False):
|
| +
|
| + all_commits_raw = _find_commits_inbetween(
|
| + start_hash, until, git_working_dir, verbose)
|
| + if verbose:
|
| + print "All commits between <of> and <until>: " + all_commits_raw
|
| +
|
| + # Adding start hash too
|
| + all_commits = [start_hash]
|
| + all_commits.extend(all_commits_raw.splitlines())
|
| + all_related_commits = {}
|
| + already_treated_commits = Set([])
|
| + for commit in all_commits:
|
| + if commit in already_treated_commits:
|
| + continue
|
| +
|
| + related_commits = _search_related_commits(
|
| + git_working_dir, commit, until, separator, verbose)
|
| + if len(related_commits) > 0:
|
| + all_related_commits[commit] = related_commits
|
| + already_treated_commits.update(related_commits)
|
| +
|
| + already_treated_commits.update(commit)
|
| +
|
| + return all_related_commits
|
| +
|
| +def _search_related_commits(
|
| + git_working_dir, start_hash, until, separator, verbose=False):
|
| +
|
| + if separator:
|
| + commits_between = _find_commits_inbetween(
|
| + start_hash, separator, git_working_dir, verbose)
|
| + if commits_between == "":
|
| + return []
|
| +
|
| + # Extract commit position
|
| + original_message = _git_execute(
|
| + git_working_dir,
|
| + ["show", "-s", "--format=%B", start_hash],
|
| + verbose)
|
| + title = original_message.splitlines()[0]
|
| +
|
| + matches = re.search("(\{#)([0-9]*)(\})", original_message)
|
| +
|
| + if not matches:
|
| + return []
|
| +
|
| + commit_position = matches.group(2)
|
| + if verbose:
|
| + print "1.) Commit position to look for: " + commit_position
|
| +
|
| + search_range = start_hash + ".." + until
|
| +
|
| + def git_args(grep_pattern):
|
| + return [
|
| + "log",
|
| + "--reverse",
|
| + "--grep=" + grep_pattern,
|
| + "--format=%H",
|
| + search_range,
|
| + ]
|
| +
|
| + found_by_hash = _git_execute(
|
| + git_working_dir, git_args(start_hash), verbose).strip()
|
| +
|
| + if verbose:
|
| + print "2.) Found by hash: " + found_by_hash
|
| +
|
| + found_by_commit_pos = _git_execute(
|
| + git_working_dir, git_args(commit_position), verbose).strip()
|
| +
|
| + if verbose:
|
| + print "3.) Found by commit position: " + found_by_commit_pos
|
| +
|
| + # Replace brackets or else they are wrongly interpreted by --grep
|
| + title = title.replace("[", "\\[")
|
| + title = title.replace("]", "\\]")
|
| +
|
| + found_by_title = _git_execute(
|
| + git_working_dir, git_args(title), verbose).strip()
|
| +
|
| + if verbose:
|
| + print "4.) Found by title: " + found_by_title
|
| +
|
| + hits = (
|
| + _convert_to_array(found_by_hash) +
|
| + _convert_to_array(found_by_commit_pos) +
|
| + _convert_to_array(found_by_title))
|
| + hits = _remove_duplicates(hits)
|
| +
|
| + if separator:
|
| + for current_hit in hits:
|
| + commits_between = _find_commits_inbetween(
|
| + separator, current_hit, git_working_dir, verbose)
|
| + if commits_between != "":
|
| + return hits
|
| + return []
|
| +
|
| + return hits
|
| +
|
| +def _find_commits_inbetween(start_hash, end_hash, git_working_dir, verbose):
|
| + commits_between = _git_execute(
|
| + git_working_dir,
|
| + ["rev-list", "--reverse", start_hash + ".." + end_hash],
|
| + verbose)
|
| + return commits_between.strip()
|
| +
|
| +def _convert_to_array(string_of_hashes):
|
| + return string_of_hashes.splitlines()
|
| +
|
| +def _remove_duplicates(array):
|
| + no_duplicates = []
|
| + for current in array:
|
| + if not current in no_duplicates:
|
| + no_duplicates.append(current)
|
| + return no_duplicates
|
| +
|
| +def _git_execute(working_dir, args, verbose=False):
|
| + command = ["git", "-C", working_dir] + args
|
| + if verbose:
|
| + print "Git working dir: " + working_dir
|
| + print "Executing git command:" + str(command)
|
| + p = Popen(args=command, stdin=PIPE,
|
| + stdout=PIPE, stderr=PIPE)
|
| + output, err = p.communicate()
|
| + rc = p.returncode
|
| + if rc != 0:
|
| + raise Exception(err)
|
| + if verbose:
|
| + print "Git return value: " + output
|
| + return output
|
| +
|
| +def _pretty_print_entry(hash, git_dir, pre_text, verbose):
|
| + text_to_print = _git_execute(
|
| + git_dir,
|
| + ["show",
|
| + "--quiet",
|
| + "--date=iso",
|
| + hash,
|
| + "--format=%ad # %H # %s"],
|
| + verbose)
|
| + return pre_text + text_to_print.strip()
|
| +
|
| +def main(options):
|
| + all_related_commits = search_all_related_commits(
|
| + options.git_dir,
|
| + options.of[0],
|
| + options.until[0],
|
| + options.separator,
|
| + options.verbose)
|
| +
|
| + sort_key = lambda x: (
|
| + _git_execute(
|
| + options.git_dir,
|
| + ["show", "--quiet", "--date=iso", x, "--format=%ad"],
|
| + options.verbose)).strip()
|
| +
|
| + high_level_commits = sorted(all_related_commits.keys(), key=sort_key)
|
| +
|
| + for current_key in high_level_commits:
|
| + if options.prettyprint:
|
| + yield _pretty_print_entry(
|
| + current_key,
|
| + options.git_dir,
|
| + "+",
|
| + options.verbose)
|
| + else:
|
| + yield "+" + current_key
|
| +
|
| + found_commits = all_related_commits[current_key]
|
| + for current_commit in found_commits:
|
| + if options.prettyprint:
|
| + yield _pretty_print_entry(
|
| + current_commit,
|
| + options.git_dir,
|
| + "| ",
|
| + options.verbose)
|
| + else:
|
| + yield "| " + current_commit
|
| +
|
| +if __name__ == "__main__": # pragma: no cover
|
| + parser = argparse.ArgumentParser(
|
| + "This tool analyzes the commit range between <of> and <until>. "
|
| + "It finds commits which belong together e.g. Implement/Revert pairs and "
|
| + "Implement/Port/Revert triples. All supplied hashes need to be "
|
| + "from the same branch e.g. master.")
|
| + parser.add_argument("-g", "--git-dir", required=False, default=".",
|
| + help="The path to your git working directory.")
|
| + parser.add_argument("--verbose", action="store_true",
|
| + help="Enables a very verbose output")
|
| + parser.add_argument("of", nargs=1,
|
| + help="Hash of the commit to be searched.")
|
| + parser.add_argument("until", nargs=1,
|
| + help="Commit when searching should stop")
|
| + parser.add_argument("--separator", required=False,
|
| + help="The script will only list related commits "
|
| + "which are separated by hash <--separator>.")
|
| + parser.add_argument("--prettyprint", action="store_true",
|
| + help="Pretty prints the output")
|
| +
|
| + args = sys.argv[1:]
|
| + options = parser.parse_args(args)
|
| + for current_line in main(options):
|
| + print current_line
|
|
|