[RISCV] Refactor predicates for rvv intrinsic patterns.
[llvm-project.git] / llvm / utils / git / pre-push.py
blobe50a91370963428a65253ebd0e8acd79b681f351
1 #!/usr/bin/env python3
3 # ======- pre-push - LLVM Git Help Integration ---------*- python -*--========#
5 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 # See https://llvm.org/LICENSE.txt for license information.
7 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9 # ==------------------------------------------------------------------------==#
11 """
12 pre-push git hook integration
13 =============================
15 This script is intended to be setup as a pre-push hook, from the root of the
16 repo run:
18 ln -sf ../../llvm/utils/git/pre-push.py .git/hooks/pre-push
20 From the git doc:
22 The pre-push hook runs during git push, after the remote refs have been
23 updated but before any objects have been transferred. It receives the name
24 and location of the remote as parameters, and a list of to-be-updated refs
25 through stdin. You can use it to validate a set of ref updates before a push
26 occurs (a non-zero exit code will abort the push).
27 """
29 import argparse
30 import os
31 import shutil
32 import subprocess
33 import sys
34 import time
35 from shlex import quote
37 VERBOSE = False
38 QUIET = False
39 dev_null_fd = None
40 z40 = '0000000000000000000000000000000000000000'
43 def eprint(*args, **kwargs):
44 print(*args, file=sys.stderr, **kwargs)
47 def log(*args, **kwargs):
48 if QUIET:
49 return
50 print(*args, **kwargs)
53 def log_verbose(*args, **kwargs):
54 if not VERBOSE:
55 return
56 print(*args, **kwargs)
59 def die(msg):
60 eprint(msg)
61 sys.exit(1)
64 def ask_confirm(prompt):
65 while True:
66 query = input('%s (y/N): ' % (prompt))
67 if query.lower() not in ['y', 'n', '']:
68 print('Expect y or n!')
69 continue
70 return query.lower() == 'y'
73 def get_dev_null():
74 """Lazily create a /dev/null fd for use in shell()"""
75 global dev_null_fd
76 if dev_null_fd is None:
77 dev_null_fd = open(os.devnull, 'w')
78 return dev_null_fd
81 def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True,
82 ignore_errors=False, text=True, print_raw_stderr=False):
83 # Escape args when logging for easy repro.
84 quoted_cmd = [quote(arg) for arg in cmd]
85 cwd_msg = ''
86 if cwd:
87 cwd_msg = ' in %s' % cwd
88 log_verbose('Running%s: %s' % (cwd_msg, ' '.join(quoted_cmd)))
90 err_pipe = subprocess.PIPE
91 if ignore_errors:
92 # Silence errors if requested.
93 err_pipe = get_dev_null()
95 start = time.time()
96 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=err_pipe,
97 stdin=subprocess.PIPE,
98 universal_newlines=text)
99 stdout, stderr = p.communicate(input=stdin)
100 elapsed = time.time() - start
102 log_verbose('Command took %0.1fs' % elapsed)
104 if p.returncode == 0 or ignore_errors:
105 if stderr and not ignore_errors:
106 if not print_raw_stderr:
107 eprint('`%s` printed to stderr:' % ' '.join(quoted_cmd))
108 eprint(stderr.rstrip())
109 if strip:
110 if text:
111 stdout = stdout.rstrip('\r\n')
112 else:
113 stdout = stdout.rstrip(b'\r\n')
114 if VERBOSE:
115 for l in stdout.splitlines():
116 log_verbose('STDOUT: %s' % l)
117 return stdout
118 err_msg = '`%s` returned %s' % (' '.join(quoted_cmd), p.returncode)
119 eprint(err_msg)
120 if stderr:
121 eprint(stderr.rstrip())
122 if die_on_failure:
123 sys.exit(2)
124 raise RuntimeError(err_msg)
127 def git(*cmd, **kwargs):
128 return shell(['git'] + list(cmd), **kwargs)
131 def get_revs_to_push(range):
132 commits = git('rev-list', range).splitlines()
133 # Reverse the order so we print the oldest commit first
134 commits.reverse()
135 return commits
138 def handle_push(args, local_ref, local_sha, remote_ref, remote_sha):
139 '''Check a single push request (which can include multiple revisions)'''
140 log_verbose('Handle push, reproduce with '
141 '`echo %s %s %s %s | pre-push.py %s %s'
142 % (local_ref, local_sha, remote_ref, remote_sha, args.remote,
143 args.url))
144 # Handle request to delete
145 if local_sha == z40:
146 if not ask_confirm('Are you sure you want to delete "%s" on remote "%s"?' % (remote_ref, args.url)):
147 die("Aborting")
148 return
150 # Push a new branch
151 if remote_sha == z40:
152 if not ask_confirm('Are you sure you want to push a new branch/tag "%s" on remote "%s"?' % (remote_ref, args.url)):
153 die("Aborting")
154 range=local_sha
155 return
156 else:
157 # Update to existing branch, examine new commits
158 range='%s..%s' % (remote_sha, local_sha)
159 # Check that the remote commit exists, otherwise let git proceed
160 if "commit" not in git('cat-file','-t', remote_sha, ignore_errors=True):
161 return
163 revs = get_revs_to_push(range)
164 if not revs:
165 # This can happen if someone is force pushing an older revision to a branch
166 return
168 # Print the revision about to be pushed commits
169 print('Pushing to "%s" on remote "%s"' % (remote_ref, args.url))
170 for sha in revs:
171 print(' - ' + git('show', '--oneline', '--quiet', sha))
173 if len(revs) > 1:
174 if not ask_confirm('Are you sure you want to push %d commits?' % len(revs)):
175 die('Aborting')
178 for sha in revs:
179 msg = git('log', '--format=%B', '-n1', sha)
180 if 'Differential Revision' not in msg:
181 continue
182 for line in msg.splitlines():
183 for tag in ['Summary', 'Reviewers', 'Subscribers', 'Tags']:
184 if line.startswith(tag + ':'):
185 eprint('Please remove arcanist tags from the commit message (found "%s" tag in %s)' % (tag, sha[:12]))
186 if len(revs) == 1:
187 eprint('Try running: llvm/utils/git/arcfilter.sh')
188 die('Aborting (force push by adding "--no-verify")')
190 return
193 if __name__ == '__main__':
194 if not shutil.which('git'):
195 die('error: cannot find git command')
197 argv = sys.argv[1:]
198 p = argparse.ArgumentParser(
199 prog='pre-push', formatter_class=argparse.RawDescriptionHelpFormatter,
200 description=__doc__)
201 verbosity_group = p.add_mutually_exclusive_group()
202 verbosity_group.add_argument('-q', '--quiet', action='store_true',
203 help='print less information')
204 verbosity_group.add_argument('-v', '--verbose', action='store_true',
205 help='print more information')
207 p.add_argument('remote', type=str, help='Name of the remote')
208 p.add_argument('url', type=str, help='URL for the remote')
210 args = p.parse_args(argv)
211 VERBOSE = args.verbose
212 QUIET = args.quiet
214 lines = sys.stdin.readlines()
215 sys.stdin = open('/dev/tty', 'r')
216 for line in lines:
217 local_ref, local_sha, remote_ref, remote_sha = line.split()
218 handle_push(args, local_ref, local_sha, remote_ref, remote_sha)