9 right = "OpenSSL_1_1_1-stable"
12 def parse_arguments():
13 parser = argparse.ArgumentParser(
14 description = """Shows the commits in '{left}...{right}'
15 which are eligible for cherry-picking. A commit is considered
16 cherry-picked, if there is another commit on the "other side"
17 which introduces an equivalent patch.
18 For details, see the documentation of the '--cherry-mark' option
19 in the git-log(1) manpage.
20 """.format(left=left, right=right))
24 action = 'store_true',
25 help = "Show all commits, also those which have been cherry-picked."\
30 action = 'store_true',
31 help = "Sort commits w.r.t. pull request number and author date."\
36 action = 'store_true',
37 help = "Compare the remote branches instead of the local ones."\
40 args = parser.parse_args()
45 def check_openssl_git_repo():
46 """Checks whether we're inside a openssl.git downstrem repository"""
48 if "/openssl.git" in subprocess.check_output(
49 ["git", "remote", "-v"]
60 return subprocess.check_output(
61 ["git", "config", "branch.master.remote"]
67 def pick_cherries(left, right, all = False):
68 """Lists all commits from the symmetric difference of left and right
70 By default, all commits are omitted which have an 'equivalent' commit
71 on the other side, unless 'all' == True.
75 "git", "log", "--oneline", "--cherry-mark", "--left-right",
76 left + "..." + right, "--pretty=%at;%m;%h;%s"
79 prnum_regex = re.compile("|".join([
80 # The standard pull request annotation
81 "\(Merged from https://github.com/openssl/openssl/pull/([0-9]+)\)",
82 # @kroeck's special pull request annotation ;-)
86 fixes_regex = re.compile(
87 "Fixes[:]?\s+(#|https://github.com/openssl/openssl/pull/)([0-9]+)")
89 for line in subprocess.check_output(git_command).decode().splitlines():
91 timestamp, branch, commit, subject = line.split(";", maxsplit=3)
93 if branch == '=' and not all:
96 # shorten overlong subject lines
98 subject = subject[:70] + "..."
100 # search commit message for pull request number
101 message = subprocess.check_output(
102 ["git", "show", "--no-patch", commit]
105 match = prnum_regex.search(message)
108 prnum = match.group(1)
110 prnum = match.group(2)
114 match = fixes_regex.search(message)
116 fixes = "#" + match.group(2)
120 yield prnum, fixes, timestamp, branch, commit, subject
124 if __name__ == '__main__':
125 args = parse_arguments()
127 if not check_openssl_git_repo():
128 print("cherry-checker: Not inside an openssl git repository.", file=sys.stderr)
133 remote = get_remote()
134 left = remote+"/"+left
135 right = remote+"/"+right
137 commits = pick_cherries(left, right, args.all)
140 commits = sorted(commits, reverse=True)
142 print("""These cherries are hanging on the git-tree:
148 prnum | fixes | br | commit | subject
149 ------- | ------ | -- | ---------- | -------------------------------------------""".format(
153 branch_marker = { '<': '<-', '>': '->', '=' : '==' }
156 for prnum, fixes, _, branch, commit, subject in commits:
157 print(' {:>6} | {:>6} | {} | {} | {} '.format(
158 '#'+prnum, fixes, branch_marker[branch], commit, subject
160 except subprocess.CalledProcessError as e:
161 print(e, file=sys.stderr)