OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. | 5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly. |
6 # Derived from https://gist.github.com/aljungberg/626518 | 6 # Derived from https://gist.github.com/aljungberg/626518 |
7 import multiprocessing.pool | 7 import multiprocessing.pool |
8 from multiprocessing.pool import IMapIterator | 8 from multiprocessing.pool import IMapIterator |
9 def wrapper(func): | 9 def wrapper(func): |
10 def wrap(self, timeout=None): | 10 def wrap(self, timeout=None): |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 return self.inc | 192 return self.inc |
193 | 193 |
194 def __exit__(self, _exc_type, _exc_value, _traceback): | 194 def __exit__(self, _exc_type, _exc_value, _traceback): |
195 self._dead = True | 195 self._dead = True |
196 with self._dead_cond: | 196 with self._dead_cond: |
197 self._dead_cond.notifyAll() | 197 self._dead_cond.notifyAll() |
198 self._thread.join() | 198 self._thread.join() |
199 del self._thread | 199 del self._thread |
200 | 200 |
201 | 201 |
| 202 def branches(*args): |
| 203 NO_BRANCH = ('* (no branch)', '* (detached from ') |
| 204 for line in run('branch', *args).splitlines(): |
| 205 if line.startswith(NO_BRANCH): |
| 206 continue |
| 207 yield line.split()[-1] |
| 208 |
| 209 |
| 210 def config_list(option): |
| 211 try: |
| 212 return run('config', '--get-all', option).split() |
| 213 except subprocess2.CalledProcessError: |
| 214 return [] |
| 215 |
| 216 |
| 217 def current_branch(): |
| 218 return run('rev-parse', '--abbrev-ref', 'HEAD') |
| 219 |
| 220 |
202 def parse_commitrefs(*commitrefs): | 221 def parse_commitrefs(*commitrefs): |
203 """Returns binary encoded commit hashes for one or more commitrefs. | 222 """Returns binary encoded commit hashes for one or more commitrefs. |
204 | 223 |
205 A commitref is anything which can resolve to a commit. Popular examples: | 224 A commitref is anything which can resolve to a commit. Popular examples: |
206 * 'HEAD' | 225 * 'HEAD' |
207 * 'origin/master' | 226 * 'origin/master' |
208 * 'cool_branch~2' | 227 * 'cool_branch~2' |
209 """ | 228 """ |
210 try: | 229 try: |
211 return map(binascii.unhexlify, hashes(*commitrefs)) | 230 return map(binascii.unhexlify, hash_multi(*commitrefs)) |
212 except subprocess2.CalledProcessError: | 231 except subprocess2.CalledProcessError: |
213 raise BadCommitRefException(commitrefs) | 232 raise BadCommitRefException(commitrefs) |
214 | 233 |
215 | 234 |
216 def run(*cmd, **kwargs): | 235 def run(*cmd, **kwargs): |
217 """Runs a git command. Returns stdout as a string. | 236 """Runs a git command. Returns stdout as a string. |
218 | 237 |
219 If logging is DEBUG, we'll print the command before we run it. | 238 If logging is DEBUG, we'll print the command before we run it. |
220 | 239 |
221 kwargs | 240 kwargs |
222 autostrip (bool) - Strip the output. Defaults to True. | 241 autostrip (bool) - Strip the output. Defaults to True. |
223 Output string is always strip()'d. | 242 Output string is always strip()'d. |
224 """ | 243 """ |
225 autostrip = kwargs.pop('autostrip', True) | 244 autostrip = kwargs.pop('autostrip', True) |
226 cmd = (GIT_EXE,) + cmd | 245 cmd = (GIT_EXE,) + cmd |
227 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) | 246 logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd)) |
228 ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs) | 247 ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs) |
229 if autostrip: | 248 if autostrip: |
230 ret = (ret or '').strip() | 249 ret = (ret or '').strip() |
231 return ret | 250 return ret |
232 | 251 |
233 | 252 |
234 def hashes(*reflike): | 253 def hash_one(reflike): |
| 254 return run('rev-parse', reflike) |
| 255 |
| 256 |
| 257 def hash_multi(*reflike): |
235 return run('rev-parse', *reflike).splitlines() | 258 return run('rev-parse', *reflike).splitlines() |
236 | 259 |
237 | 260 |
238 def intern_f(f, kind='blob'): | 261 def intern_f(f, kind='blob'): |
239 """Interns a file object into the git object store. | 262 """Interns a file object into the git object store. |
240 | 263 |
241 Args: | 264 Args: |
242 f (file-like object) - The file-like object to intern | 265 f (file-like object) - The file-like object to intern |
243 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. | 266 kind (git object type) - One of 'blob', 'commit', 'tree', 'tag'. |
244 | 267 |
245 Returns the git hash of the interned object (hex encoded). | 268 Returns the git hash of the interned object (hex encoded). |
246 """ | 269 """ |
247 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) | 270 ret = run('hash-object', '-t', kind, '-w', '--stdin', stdin=f) |
248 f.close() | 271 f.close() |
249 return ret | 272 return ret |
250 | 273 |
251 | 274 |
| 275 def tags(*args): |
| 276 return run('tag', *args).splitlines() |
| 277 |
| 278 |
252 def tree(treeref, recurse=False): | 279 def tree(treeref, recurse=False): |
253 """Returns a dict representation of a git tree object. | 280 """Returns a dict representation of a git tree object. |
254 | 281 |
255 Args: | 282 Args: |
256 treeref (str) - a git ref which resolves to a tree (commits count as trees). | 283 treeref (str) - a git ref which resolves to a tree (commits count as trees). |
257 recurse (bool) - include all of the tree's decendants too. File names will | 284 recurse (bool) - include all of the tree's decendants too. File names will |
258 take the form of 'some/path/to/file'. | 285 take the form of 'some/path/to/file'. |
259 | 286 |
260 Return format: | 287 Return format: |
261 { 'file_name': (mode, type, ref) } | 288 { 'file_name': (mode, type, ref) } |
(...skipping 17 matching lines...) Expand all Loading... |
279 opts.append(treeref) | 306 opts.append(treeref) |
280 try: | 307 try: |
281 for line in run(*opts).splitlines(): | 308 for line in run(*opts).splitlines(): |
282 mode, typ, ref, name = line.split(None, 3) | 309 mode, typ, ref, name = line.split(None, 3) |
283 ret[name] = (mode, typ, ref) | 310 ret[name] = (mode, typ, ref) |
284 except subprocess2.CalledProcessError: | 311 except subprocess2.CalledProcessError: |
285 return None | 312 return None |
286 return ret | 313 return ret |
287 | 314 |
288 | 315 |
| 316 def upstream(branch): |
| 317 try: |
| 318 return run('rev-parse', '--abbrev-ref', '--symbolic-full-name', |
| 319 branch+'@{upstream}') |
| 320 except subprocess2.CalledProcessError: |
| 321 return None |
| 322 |
| 323 |
289 def mktree(treedict): | 324 def mktree(treedict): |
290 """Makes a git tree object and returns its hash. | 325 """Makes a git tree object and returns its hash. |
291 | 326 |
292 See |tree()| for the values of mode, type, and ref. | 327 See |tree()| for the values of mode, type, and ref. |
293 | 328 |
294 Args: | 329 Args: |
295 treedict - { name: (mode, type, ref) } | 330 treedict - { name: (mode, type, ref) } |
296 """ | 331 """ |
297 with tempfile.TemporaryFile() as f: | 332 with tempfile.TemporaryFile() as f: |
298 for name, (mode, typ, ref) in treedict.iteritems(): | 333 for name, (mode, typ, ref) in treedict.iteritems(): |
299 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) | 334 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) |
300 f.seek(0) | 335 f.seek(0) |
301 return run('mktree', '-z', stdin=f) | 336 return run('mktree', '-z', stdin=f) |
OLD | NEW |