OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Usage: %prog [options] [<commitref>]* | 6 """Usage: %prog [options] [<commitref>]* |
7 | 7 |
8 If no <commitref>'s are supplied, it defaults to HEAD. | 8 If no <commitref>'s are supplied, it defaults to HEAD. |
9 | 9 |
10 Calculates the generation number for one or more commits in a git repo. | 10 Calculates the generation number for one or more commits in a git repo. |
(...skipping 19 matching lines...) Expand all Loading... |
30 import sys | 30 import sys |
31 import tempfile | 31 import tempfile |
32 | 32 |
33 import git_common as git | 33 import git_common as git |
34 import subprocess2 | 34 import subprocess2 |
35 | 35 |
36 CHUNK_FMT = '!20sL' | 36 CHUNK_FMT = '!20sL' |
37 CHUNK_SIZE = struct.calcsize(CHUNK_FMT) | 37 CHUNK_SIZE = struct.calcsize(CHUNK_FMT) |
38 DIRTY_TREES = collections.defaultdict(int) | 38 DIRTY_TREES = collections.defaultdict(int) |
39 REF = 'refs/number/commits' | 39 REF = 'refs/number/commits' |
| 40 AUTHOR_NAME = 'git-number' |
| 41 AUTHOR_EMAIL = 'chrome-infrastructure-team@google.com' |
40 | 42 |
41 # Number of bytes to use for the prefix on our internal number structure. | 43 # Number of bytes to use for the prefix on our internal number structure. |
42 # 0 is slow to deserialize. 2 creates way too much bookeeping overhead (would | 44 # 0 is slow to deserialize. 2 creates way too much bookeeping overhead (would |
43 # need to reimplement cache data structures to be a bit more sophisticated than | 45 # need to reimplement cache data structures to be a bit more sophisticated than |
44 # dicts. 1 seems to be just right. | 46 # dicts. 1 seems to be just right. |
45 PREFIX_LEN = 1 | 47 PREFIX_LEN = 1 |
46 | 48 |
47 # Set this to 'threads' to gather coverage data while testing. | 49 # Set this to 'threads' to gather coverage data while testing. |
48 POOL_KIND = 'procs' | 50 POOL_KIND = 'procs' |
49 | 51 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 with git.ScopedPool(kind=POOL_KIND) as leaf_pool: | 148 with git.ScopedPool(kind=POOL_KIND) as leaf_pool: |
147 for item in leaf_pool.imap(leaf_map_fn, prefixes_trees): | 149 for item in leaf_pool.imap(leaf_map_fn, prefixes_trees): |
148 updater.stdin.write(item) | 150 updater.stdin.write(item) |
149 inc() | 151 inc() |
150 | 152 |
151 updater.stdin.close() | 153 updater.stdin.close() |
152 updater.wait() | 154 updater.wait() |
153 assert updater.returncode == 0 | 155 assert updater.returncode == 0 |
154 | 156 |
155 tree_id = git.run('write-tree', env=env) | 157 tree_id = git.run('write-tree', env=env) |
156 commit_cmd = ['commit-tree', '-m', msg, '-p'] + git.hashes(REF) | 158 commit_cmd = [ |
| 159 # Git user.name and/or user.email may not be configured, so specifying |
| 160 # them explicitly. They are not used, but requried by Git. |
| 161 '-c', 'user.name=%s' % AUTHOR_NAME, |
| 162 '-c', 'user.email=%s' % AUTHOR_EMAIL, |
| 163 'commit-tree', |
| 164 '-m', msg, |
| 165 '-p'] + git.hash_multi(REF) |
157 for t in targets: | 166 for t in targets: |
158 commit_cmd.extend(['-p', binascii.hexlify(t)]) | 167 commit_cmd.extend(['-p', binascii.hexlify(t)]) |
159 commit_cmd.append(tree_id) | 168 commit_cmd.append(tree_id) |
160 commit_hash = git.run(*commit_cmd) | 169 commit_hash = git.run(*commit_cmd) |
161 git.run('update-ref', REF, commit_hash) | 170 git.run('update-ref', REF, commit_hash) |
162 DIRTY_TREES.clear() | 171 DIRTY_TREES.clear() |
163 | 172 |
164 | 173 |
165 def preload_tree(prefix): | 174 def preload_tree(prefix): |
166 """Returns the prefix and parsed tree object for the specified prefix.""" | 175 """Returns the prefix and parsed tree object for the specified prefix.""" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 help='Do not actually cache anything we calculate.') | 245 help='Do not actually cache anything we calculate.') |
237 parser.add_option('--reset', action='store_true', | 246 parser.add_option('--reset', action='store_true', |
238 help='Reset the generation number cache and quit.') | 247 help='Reset the generation number cache and quit.') |
239 parser.add_option('-v', '--verbose', action='count', default=0, | 248 parser.add_option('-v', '--verbose', action='count', default=0, |
240 help='Be verbose. Use more times for more verbosity.') | 249 help='Be verbose. Use more times for more verbosity.') |
241 opts, args = parser.parse_args() | 250 opts, args = parser.parse_args() |
242 | 251 |
243 levels = [logging.ERROR, logging.INFO, logging.DEBUG] | 252 levels = [logging.ERROR, logging.INFO, logging.DEBUG] |
244 logging.basicConfig(level=levels[min(opts.verbose, len(levels) - 1)]) | 253 logging.basicConfig(level=levels[min(opts.verbose, len(levels) - 1)]) |
245 | 254 |
| 255 # 'git number' should only be used on bots. |
| 256 if os.getenv('CHROME_HEADLESS') != '1': |
| 257 logging.error("'git-number' is an infrastructure tool that is only " |
| 258 "intended to be used internally by bots. Developers should " |
| 259 "use the 'Cr-Commit-Position' value in the commit's message.") |
| 260 return 1 |
| 261 |
| 262 if opts.reset: |
| 263 clear_caches(on_disk=True) |
| 264 return |
| 265 |
246 try: | 266 try: |
247 if opts.reset: | 267 targets = git.parse_commitrefs(*(args or ['HEAD'])) |
248 clear_caches(on_disk=True) | 268 except git.BadCommitRefException as e: |
249 return | 269 parser.error(e) |
250 | 270 |
251 try: | 271 load_generation_numbers(targets) |
252 targets = git.parse_commitrefs(*(args or ['HEAD'])) | 272 if not opts.no_cache: |
253 except git.BadCommitRefException as e: | 273 finalize(targets) |
254 parser.error(e) | |
255 | 274 |
256 load_generation_numbers(targets) | 275 print '\n'.join(map(str, map(get_num, targets))) |
257 if not opts.no_cache: | 276 return 0 |
258 finalize(targets) | |
259 | |
260 print '\n'.join(map(str, map(get_num, targets))) | |
261 return 0 | |
262 except KeyboardInterrupt: | |
263 return 1 | |
264 | 277 |
265 | 278 |
266 if __name__ == '__main__': # pragma: no cover | 279 if __name__ == '__main__': # pragma: no cover |
267 sys.exit(main()) | 280 try: |
| 281 sys.exit(main()) |
| 282 except KeyboardInterrupt: |
| 283 sys.stderr.write('interrupted\n') |
| 284 sys.exit(1) |
OLD | NEW |