OLD | NEW |
1 # Copyright 2009 Google Inc. All Rights Reserved. | 1 # Copyright 2009 Google Inc. All Rights Reserved. |
2 # | 2 # |
3 # Licensed under the Apache License, Version 2.0 (the "License"); | 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
4 # you may not use this file except in compliance with the License. | 4 # you may not use this file except in compliance with the License. |
5 # You may obtain a copy of the License at | 5 # You may obtain a copy of the License at |
6 # | 6 # |
7 # http://www.apache.org/licenses/LICENSE-2.0 | 7 # http://www.apache.org/licenses/LICENSE-2.0 |
8 # | 8 # |
9 # Unless required by applicable law or agreed to in writing, software | 9 # Unless required by applicable law or agreed to in writing, software |
10 # distributed under the License is distributed on an "AS IS" BASIS, | 10 # distributed under the License is distributed on an "AS IS" BASIS, |
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 # See the License for the specific language governing permissions and | 12 # See the License for the specific language governing permissions and |
13 # limitations under the License. | 13 # limitations under the License. |
14 | 14 |
15 """Generic utils.""" | 15 """Generic utils.""" |
16 | 16 |
17 import errno | 17 import errno |
18 import logging | 18 import logging |
19 import os | 19 import os |
20 import re | 20 import re |
21 import stat | 21 import stat |
22 import subprocess | 22 import subprocess |
23 import sys | 23 import sys |
24 import threading | 24 import threading |
25 import time | 25 import time |
26 import threading | |
27 import xml.dom.minidom | 26 import xml.dom.minidom |
28 import xml.parsers.expat | 27 import xml.parsers.expat |
29 | 28 |
30 | 29 |
31 class CheckCallError(OSError): | 30 class CheckCallError(OSError): |
32 """CheckCall() returned non-0.""" | 31 """CheckCall() returned non-0.""" |
33 def __init__(self, command, cwd, retcode, stdout, stderr=None): | 32 def __init__(self, command, cwd, retcode, stdout, stderr=None): |
34 OSError.__init__(self, command, cwd, retcode, stdout, stderr) | 33 OSError.__init__(self, command, cwd, retcode, stdout, stderr) |
35 self.command = command | 34 self.command = command |
36 self.cwd = cwd | 35 self.cwd = cwd |
37 self.retcode = retcode | 36 self.retcode = retcode |
38 self.stdout = stdout | 37 self.stdout = stdout |
39 self.stderr = stderr | 38 self.stderr = stderr |
40 | 39 |
41 | 40 |
| 41 def Popen(*args, **kwargs): |
| 42 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the |
| 43 # executable, but shell=True makes subprocess on Linux fail when it's called |
| 44 # with a list because it only tries to execute the first item in the list. |
| 45 if not 'env' in kwargs: |
| 46 # It's easier to parse the stdout if it is always in English. |
| 47 kwargs['env'] = os.environ.copy() |
| 48 kwargs['env']['LANGUAGE'] = 'en' |
| 49 return subprocess.Popen(*args, shell=(sys.platform=='win32'), **kwargs) |
| 50 |
| 51 |
42 def CheckCall(command, cwd=None, print_error=True): | 52 def CheckCall(command, cwd=None, print_error=True): |
43 """Like subprocess.check_call() but returns stdout. | 53 """Similar subprocess.check_call() but redirects stdout and |
| 54 returns (stdout, stderr). |
44 | 55 |
45 Works on python 2.4 | 56 Works on python 2.4 |
46 """ | 57 """ |
47 logging.debug('%s, cwd=%s' % (str(command), str(cwd))) | 58 logging.debug('%s, cwd=%s' % (str(command), str(cwd))) |
48 try: | 59 try: |
49 stderr = None | 60 stderr = None |
50 if not print_error: | 61 if not print_error: |
51 stderr = subprocess.PIPE | 62 stderr = subprocess.PIPE |
52 env = os.environ.copy() | 63 process = Popen(command, cwd=cwd, stdout=subprocess.PIPE, stderr=stderr) |
53 env['LANGUAGE'] = 'en' | |
54 process = subprocess.Popen(command, cwd=cwd, | |
55 shell=sys.platform.startswith('win'), | |
56 stdout=subprocess.PIPE, | |
57 stderr=stderr, | |
58 env=env) | |
59 std_out, std_err = process.communicate() | 64 std_out, std_err = process.communicate() |
60 except OSError, e: | 65 except OSError, e: |
61 raise CheckCallError(command, cwd, e.errno, None) | 66 raise CheckCallError(command, cwd, e.errno, None) |
62 if process.returncode: | 67 if process.returncode: |
63 raise CheckCallError(command, cwd, process.returncode, std_out, std_err) | 68 raise CheckCallError(command, cwd, process.returncode, std_out, std_err) |
64 return std_out, std_err | 69 return std_out, std_err |
65 | 70 |
66 | 71 |
67 def SplitUrlRevision(url): | 72 def SplitUrlRevision(url): |
68 """Splits url and returns a two-tuple: url, rev""" | 73 """Splits url and returns a two-tuple: url, rev""" |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 trimmed. | 273 trimmed. |
269 | 274 |
270 If the command fails, as indicated by a nonzero exit status, gclient will | 275 If the command fails, as indicated by a nonzero exit status, gclient will |
271 exit with an exit status of fail_status. If fail_status is None (the | 276 exit with an exit status of fail_status. If fail_status is None (the |
272 default), gclient will raise an Error exception. | 277 default), gclient will raise an Error exception. |
273 """ | 278 """ |
274 logging.debug(command) | 279 logging.debug(command) |
275 if print_messages: | 280 if print_messages: |
276 print('\n________ running \'%s\' in \'%s\'' | 281 print('\n________ running \'%s\' in \'%s\'' |
277 % (' '.join(command), in_directory)) | 282 % (' '.join(command), in_directory)) |
278 env = os.environ.copy() | |
279 env['LANGUAGE'] = 'en' | |
280 | 283 |
281 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the | 284 kid = Popen(command, bufsize=0, cwd=in_directory, |
282 # executable, but shell=True makes subprocess on Linux fail when it's called | 285 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
283 # with a list because it only tries to execute the first item in the list. | |
284 kid = subprocess.Popen(command, bufsize=0, cwd=in_directory, | |
285 shell=(sys.platform == 'win32'), stdout=subprocess.PIPE, | |
286 stderr=subprocess.STDOUT, env=env) | |
287 | 286 |
288 # Do a flush of sys.stdout before we begin reading from the subprocess's | 287 # Do a flush of sys.stdout before we begin reading from the subprocess's |
289 # stdout. | 288 # stdout. |
290 last_flushed_at = time.time() | 289 last_flushed_at = time.time() |
291 sys.stdout.flush() | 290 sys.stdout.flush() |
292 | 291 |
293 # Also, we need to forward stdout to prevent weird re-ordering of output. | 292 # Also, we need to forward stdout to prevent weird re-ordering of output. |
294 # This has to be done on a per byte basis to make sure it is not buffered: | 293 # This has to be done on a per byte basis to make sure it is not buffered: |
295 # normally buffering is done for each line, but if svn requests input, no | 294 # normally buffering is done for each line, but if svn requests input, no |
296 # end-of-line character is output after the prompt and it would not show up. | 295 # end-of-line character is output after the prompt and it would not show up. |
(...skipping 19 matching lines...) Expand all Loading... |
316 if (time.time() - last_flushed_at) > 10: | 315 if (time.time() - last_flushed_at) > 10: |
317 last_flushed_at = time.time() | 316 last_flushed_at = time.time() |
318 sys.stdout.flush() | 317 sys.stdout.flush() |
319 in_byte = kid.stdout.read(1) | 318 in_byte = kid.stdout.read(1) |
320 rv = kid.wait() | 319 rv = kid.wait() |
321 | 320 |
322 if rv: | 321 if rv: |
323 msg = 'failed to run command: %s' % ' '.join(command) | 322 msg = 'failed to run command: %s' % ' '.join(command) |
324 | 323 |
325 if fail_status != None: | 324 if fail_status != None: |
326 print >>sys.stderr, msg | 325 print >> sys.stderr, msg |
327 sys.exit(fail_status) | 326 sys.exit(fail_status) |
328 | 327 |
329 raise Error(msg) | 328 raise Error(msg) |
330 | 329 |
331 | 330 |
332 def FindGclientRoot(from_dir, filename='.gclient'): | 331 def FindGclientRoot(from_dir, filename='.gclient'): |
333 """Tries to find the gclient root.""" | 332 """Tries to find the gclient root.""" |
334 path = os.path.realpath(from_dir) | 333 path = os.path.realpath(from_dir) |
335 while not os.path.exists(os.path.join(path, filename)): | 334 while not os.path.exists(os.path.join(path, filename)): |
336 next = os.path.split(path) | 335 split_path = os.path.split(path) |
337 if not next[1]: | 336 if not split_path[1]: |
338 return None | 337 return None |
339 path = next[0] | 338 path = split_path[0] |
340 logging.info('Found gclient root at ' + path) | 339 logging.info('Found gclient root at ' + path) |
341 return path | 340 return path |
342 | 341 |
343 | 342 |
344 def PathDifference(root, subpath): | 343 def PathDifference(root, subpath): |
345 """Returns the difference subpath minus root.""" | 344 """Returns the difference subpath minus root.""" |
346 root = os.path.realpath(root) | 345 root = os.path.realpath(root) |
347 subpath = os.path.realpath(subpath) | 346 subpath = os.path.realpath(subpath) |
348 if not subpath.startswith(root): | 347 if not subpath.startswith(root): |
349 return None | 348 return None |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
520 if exception: | 519 if exception: |
521 self.parent.exceptions.append(exception) | 520 self.parent.exceptions.append(exception) |
522 if self.parent.progress: | 521 if self.parent.progress: |
523 self.parent.progress.update(1) | 522 self.parent.progress.update(1) |
524 assert not self.item.name in self.parent.ran | 523 assert not self.item.name in self.parent.ran |
525 if not self.item.name in self.parent.ran: | 524 if not self.item.name in self.parent.ran: |
526 self.parent.ran.append(self.item.name) | 525 self.parent.ran.append(self.item.name) |
527 finally: | 526 finally: |
528 self.parent.ready_cond.notifyAll() | 527 self.parent.ready_cond.notifyAll() |
529 self.parent.ready_cond.release() | 528 self.parent.ready_cond.release() |
OLD | NEW |