Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: git_common.py

Issue 26109002: Add git-number script to calculate generation numbers for commits. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Remove silly author line :) Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 # Monkeypatch IMapIterator so that Ctrl-C can kill everything properly.
6 # Derived from https://gist.github.com/aljungberg/626518
7 import multiprocessing.pool
8 from multiprocessing.pool import IMapIterator
M-A Ruel 2013/10/21 17:56:44 Can't this be done later?
iannucci 2013/10/22 07:28:22 'this' ? Parallelizing, or monkey-patching IMapIte
M-A Ruel 2013/10/24 13:23:03 Monkey patching, but I don't mind. Leave it there.
9 def wrapper(func):
10 def wrap(self, timeout=None):
11 return func(self, timeout=timeout or 1e100)
12 return wrap
13 IMapIterator.next = wrapper(IMapIterator.next)
14 IMapIterator.__next__ = IMapIterator.next
15
16 import contextlib
17 import functools
18 import signal
19 import subprocess
20 import sys
21 import tempfile
22 import threading
23 import binascii
M-A Ruel 2013/10/21 17:56:44 Order
iannucci 2013/10/22 07:28:22 Done.
24
25 hexlify = binascii.hexlify
M-A Ruel 2013/10/21 17:56:44 It's not used once. Why?
iannucci 2013/10/22 07:28:22 It's imported (in git_number). Used for dealing wi
M-A Ruel 2013/10/24 13:23:03 Then import it where it's used.
26 unhexlify = binascii.unhexlify
M-A Ruel 2013/10/21 17:56:44 It's used once, why?
27 pathlify = lambda s: '/'.join('%02x' % ord(b) for b in s)
28
29 VERBOSE_LEVEL = 0
30
M-A Ruel 2013/10/21 17:56:44 2 lines
iannucci 2013/10/22 07:28:22 Done.
31 class CalledProcessError(Exception):
32 def __init__(self, returncode, cmd, output=None, out_err=None):
33 super(CalledProcessError, self).__init__()
34 self.returncode = returncode
35 self.cmd = cmd
36 self.output = output
37 self.out_err = out_err
agable 2013/10/21 20:16:42 output and out_err are never used.
iannucci 2013/10/22 07:28:22 True. Done.
38
39 def __str__(self):
40 return (
41 'Command "%s" returned non-zero exit status %d' %
42 (self.cmd, self.returncode))
43
44
45 def memoize_one(f):
agable 2013/10/21 20:16:42 Is there anywhere else in depot_tools this could l
iannucci 2013/10/22 07:28:22 Not sure...
46 """
M-A Ruel 2013/10/21 17:56:44 """Memoizes a single-argument pure function.
iannucci 2013/10/22 07:28:22 Done.
47 Memoizes a single-argument pure function.
48
49 Values of None are not cached.
50
51 Adds a mutable attribute to the decorated function:
52 * cache (dict) - Maps arg to f(arg)
53 """
54 cache = {}
55
56 @functools.wraps(f)
57 def inner(arg):
58 ret = cache.get(arg)
59 if ret is None:
60 ret = f(arg)
61 if ret is not None:
62 cache[arg] = ret
63 return ret
64 inner.cache = cache
65 inner.default_enabled = False
66
67 return inner
68
69
70 def initer(orig, orig_args):
agable 2013/10/21 20:16:42 Define this inside ScopedPool?
iannucci 2013/10/22 07:28:22 Can't. Multprocessing sux and this must be importa
71 signal.signal(signal.SIGINT, signal.SIG_IGN)
72 if orig:
73 orig(*orig_args)
74
75
76 @contextlib.contextmanager
77 def ScopedPool(*args, **kwargs):
78 if kwargs.pop('kind', None) == 'threads':
79 pool = multiprocessing.pool.ThreadPool(*args, **kwargs)
80 else:
81 orig, orig_args = kwargs.get('initializer'), kwargs.get('initargs', ())
82 kwargs['initializer'] = initer
83 kwargs['initargs'] = orig, orig_args
84 pool = multiprocessing.pool.Pool(*args, **kwargs)
85
86 try:
87 yield pool
88 pool.close()
89 except:
90 pool.terminate()
91 raise
92 finally:
93 pool.join()
94
95
96 class StatusPrinter(object):
agable 2013/10/21 20:16:42 This is more like a ProgressPrinter, since it incr
iannucci 2013/10/22 07:28:22 Done.
97 """Threaded single-stat status message printer."""
98 def __init__(self, fmt):
99 """
100 Create a StatusPrinter.
agable 2013/10/21 20:16:42 Bump up a line.
iannucci 2013/10/22 07:28:22 Done.
101
102 Call .start() to get it going, or use it as a context manager which produces
agable 2013/10/21 20:16:42 Doesn't actually have a .start() method.
iannucci 2013/10/22 07:28:22 well how about that... Done.
103 a simple 'increment' method:
104
105 with StatusPrinter('(%%d/%d)' % 1000) as inc:
106 for i in xrange(1000):
107 # do stuff
108 if i % 10 == 0:
109 inc(10)
110
111 Args:
112 fmt - String format with a single '%d' where the counter value should go.
113 """
114 self.fmt = fmt
115 self._count = 0
116 self._dead = False
117 self._dead_cond = threading.Condition()
118 self._thread = threading.Thread(target=self._run)
119
120 @staticmethod
121 def _emit(s):
122 if VERBOSE_LEVEL > 0:
123 sys.stderr.write('\r'+s)
124 sys.stderr.flush()
125
126 def _run(self):
127 with self._dead_cond:
128 while not self._dead:
129 self._emit(self.fmt % self._count)
130 self._dead_cond.wait(.5)
131 self._emit((self.fmt+'\n') % self._count)
132
133 def inc(self, amount=1):
134 self._count += amount
135
136 def __enter__(self):
137 self._thread.start()
138 return self.inc
139
140 def __exit__(self, _exc_type, _exc_value, _traceback):
141 self._dead = True
142 with self._dead_cond:
143 self._dead_cond.notifyAll()
144 self._thread.join()
145 del self._thread
146
147
148 def parse_committish(*committish):
agable 2013/10/21 20:16:42 Docstring. Unclear why a committish would have mul
iannucci 2013/10/22 07:28:22 Added comments to *lify, added docstring and renam
149 try:
150 return map(unhexlify, git_hash(*committish).splitlines())
151 except CalledProcessError:
152 raise Exception('%r does not seem to be a valid commitish.' % committish)
153
154
155 def check_output(*popenargs, **kwargs):
agable 2013/10/21 20:16:42 Docstriiing.
iannucci 2013/10/22 07:28:22 Done.
156 kwargs.setdefault('stdout', subprocess.PIPE)
157 kwargs.setdefault('stderr', subprocess.PIPE)
158 indata = kwargs.pop('indata', None)
159 if indata is not None:
160 kwargs['stdin'] = subprocess.PIPE
161 process = subprocess.Popen(*popenargs, **kwargs)
162 output, out_err = process.communicate(indata)
agable 2013/10/21 20:16:42 I thought communicate misbehaved if you didn't hav
iannucci 2013/10/22 07:28:22 We do this if indata is not-None.
163 retcode = process.poll()
164 if retcode:
agable 2013/10/21 20:16:42 You need to handle the case where poll() returns N
iannucci 2013/10/22 07:28:22 communicate() guarantees that the process is ended
165 cmd = kwargs.get('args')
166 if cmd is None:
167 cmd = popenargs[0]
168 raise CalledProcessError(retcode, cmd, output=output, out_err=out_err)
169 return output
170
171
172 GIT_EXE = 'git.bat' if sys.platform.startswith('win') else 'git'
M-A Ruel 2013/10/21 17:56:44 Constants should be at the top.
iannucci 2013/10/22 07:28:22 Yep. Done.
173
174 def run_git(*cmd, **kwargs):
agable 2013/10/21 20:16:42 Doooooooc strriiiiiiing.
iannucci 2013/10/22 07:28:22 Done.
M-A Ruel 2013/10/24 13:23:03 I don't think this particular function needed a do
175 cmd = (GIT_EXE,) + cmd
176 if VERBOSE_LEVEL > 1:
177 print 'running:', " ".join(repr(tok) for tok in cmd)
178 ret = check_output(cmd, **kwargs)
179 ret = (ret or '').strip()
180 return ret
181
182
183 def git_hash(*reflike):
agable 2013/10/21 20:16:42 Like seriously. All functions are worth good docst
iannucci 2013/10/22 07:28:22 really? this is a one-line function... """Returns
M-A Ruel 2013/10/24 13:23:03 I think it's more about *what* this call does. It
iannucci 2013/10/25 00:52:41 Hm... at the callsite: hashes = git_hash('HEAD'
184 return run_git('rev-parse', *reflike)
185
186
187 def git_intern_f(f, kind='blob'):
M-A Ruel 2013/10/21 17:56:44 This function is worth a docstring.
iannucci 2013/10/22 07:28:22 Done.
188 ret = run_git('hash-object', '-t', kind, '-w', '--stdin', stdin=f)
189 f.close()
190 return ret
191
192
193 def git_tree(treeish, recurse=False):
194 ret = {}
195 opts = ['ls-tree', '--full-tree']
196 if recurse:
197 opts += ['-r']
198 opts.append(treeish)
199 try:
200 for line in run_git(*opts).splitlines():
201 if not line:
202 continue
203 mode, typ, ref, name = line.split(None, 3)
204 ret[name] = (mode, typ, ref)
205 except CalledProcessError:
206 return None
207 return ret
208
209
210 def git_mktree(treedict):
211 """
212 Args:
213 treedict - { name: (mode, type, ref) }
214 """
215 with tempfile.TemporaryFile() as f:
216 for name, (mode, typ, ref) in treedict.iteritems():
217 f.write('%s %s %s\t%s\0' % (mode, typ, ref, name))
218 f.seek(0)
219 return run_git('mktree', '-z', stdin=f)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698