OLD | NEW |
1 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2006-2009 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 """SCM-specific utility classes.""" | 5 """SCM-specific utility classes.""" |
6 | 6 |
7 import cStringIO | 7 import cStringIO |
8 import glob | 8 import glob |
9 import os | 9 import os |
10 import re | 10 import re |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 results = [] | 110 results = [] |
111 if status: | 111 if status: |
112 for statusline in status.split('\n'): | 112 for statusline in status.split('\n'): |
113 m = re.match('^(\w)\t(.+)$', statusline) | 113 m = re.match('^(\w)\t(.+)$', statusline) |
114 if not m: | 114 if not m: |
115 raise Exception("status currently unsupported: %s" % statusline) | 115 raise Exception("status currently unsupported: %s" % statusline) |
116 results.append(('%s ' % m.group(1), m.group(2))) | 116 results.append(('%s ' % m.group(1), m.group(2))) |
117 return results | 117 return results |
118 | 118 |
119 @staticmethod | 119 @staticmethod |
120 def RunAndFilterOutput(args, | 120 def RunAndFilterOutput(args, **kwargs): |
121 in_directory, | 121 """Wrapper to gclient_utils.SubprocessCallAndFilter().""" |
122 print_messages, | 122 return gclient_utils.SubprocessCallAndFilter([GIT.COMMAND] + args, **kwargs) |
123 print_stdout, | |
124 filter_fn, | |
125 stdout=None): | |
126 """Runs a command, optionally outputting to stdout. | |
127 | |
128 stdout is passed line-by-line to the given filter_fn function. If | |
129 print_stdout is true, it is also printed to sys.stdout as in Run. | |
130 | |
131 Args: | |
132 args: A sequence of command line parameters to be passed. | |
133 in_directory: The directory where git is to be run. | |
134 print_messages: Whether to print status messages to stdout about | |
135 which commands are being run. | |
136 print_stdout: Whether to forward program's output to stdout. | |
137 filter_fn: A function taking one argument (a string) which will be | |
138 passed each line (with the ending newline character removed) of | |
139 program's output for filtering. | |
140 | |
141 Raises: | |
142 gclient_utils.Error: An error occurred while running the command. | |
143 """ | |
144 command = [GIT.COMMAND] | |
145 command.extend(args) | |
146 gclient_utils.SubprocessCallAndFilter(command, | |
147 in_directory, | |
148 print_messages, | |
149 print_stdout, | |
150 filter_fn=filter_fn, | |
151 stdout=stdout) | |
152 | 123 |
153 @staticmethod | 124 @staticmethod |
154 def GetEmail(repo_root): | 125 def GetEmail(repo_root): |
155 """Retrieves the user email address if known.""" | 126 """Retrieves the user email address if known.""" |
156 # We could want to look at the svn cred when it has a svn remote but it | 127 # We could want to look at the svn cred when it has a svn remote but it |
157 # should be fine for now, users should simply configure their git settings. | 128 # should be fine for now, users should simply configure their git settings. |
158 return GIT.Capture(['config', 'user.email'], | 129 return GIT.Capture(['config', 'user.email'], |
159 repo_root, error_ok=True)[0].strip() | 130 repo_root, error_ok=True)[0].strip() |
160 | 131 |
161 @staticmethod | 132 @staticmethod |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 elif ver > min_ver: | 309 elif ver > min_ver: |
339 return (True, current_version) | 310 return (True, current_version) |
340 return (True, current_version) | 311 return (True, current_version) |
341 | 312 |
342 | 313 |
343 class SVN(object): | 314 class SVN(object): |
344 COMMAND = "svn" | 315 COMMAND = "svn" |
345 current_version = None | 316 current_version = None |
346 | 317 |
347 @staticmethod | 318 @staticmethod |
348 def Run(args, in_directory): | 319 def Run(args, **kwargs): |
349 """Runs svn, sending output to stdout. | 320 """Wrappers to gclient_utils.SubprocessCall().""" |
350 | 321 return gclient_utils.SubprocessCall([SVN.COMMAND] + args, **kwargs) |
351 Args: | |
352 args: A sequence of command line parameters to be passed to svn. | |
353 in_directory: The directory where svn is to be run. | |
354 | |
355 Raises: | |
356 Error: An error occurred while running the svn command. | |
357 """ | |
358 c = [SVN.COMMAND] | |
359 c.extend(args) | |
360 # TODO(maruel): This is very gclient-specific. | |
361 gclient_utils.SubprocessCall(c, in_directory) | |
362 | 322 |
363 @staticmethod | 323 @staticmethod |
364 def Capture(args, in_directory=None, print_error=True): | 324 def Capture(args, in_directory=None, print_error=True): |
365 """Runs svn, capturing output sent to stdout as a string. | 325 """Runs svn, capturing output sent to stdout as a string. |
366 | 326 |
367 Args: | 327 Args: |
368 args: A sequence of command line parameters to be passed to svn. | 328 args: A sequence of command line parameters to be passed to svn. |
369 in_directory: The directory where svn is to be run. | 329 in_directory: The directory where svn is to be run. |
370 | 330 |
371 Returns: | 331 Returns: |
372 The output sent to stdout as a string. | 332 The output sent to stdout as a string. |
373 """ | 333 """ |
374 c = [SVN.COMMAND] | 334 c = [SVN.COMMAND] |
375 c.extend(args) | 335 c.extend(args) |
376 stderr = None | 336 stderr = None |
377 if not print_error: | 337 if not print_error: |
378 stderr = subprocess.PIPE | 338 stderr = subprocess.PIPE |
379 return gclient_utils.Popen(c, cwd=in_directory, stdout=subprocess.PIPE, | 339 return gclient_utils.Popen(c, cwd=in_directory, stdout=subprocess.PIPE, |
380 stderr=stderr).communicate()[0] | 340 stderr=stderr).communicate()[0] |
381 | 341 |
382 @staticmethod | 342 @staticmethod |
383 def RunAndGetFileList(verbose, args, in_directory, file_list, stdout=None): | 343 def RunAndGetFileList(verbose, args, cwd, file_list, stdout=None): |
384 """Runs svn checkout, update, or status, output to stdout. | 344 """Runs svn checkout, update, or status, output to stdout. |
385 | 345 |
386 The first item in args must be either "checkout", "update", or "status". | 346 The first item in args must be either "checkout", "update", or "status". |
387 | 347 |
388 svn's stdout is parsed to collect a list of files checked out or updated. | 348 svn's stdout is parsed to collect a list of files checked out or updated. |
389 These files are appended to file_list. svn's stdout is also printed to | 349 These files are appended to file_list. svn's stdout is also printed to |
390 sys.stdout as in Run. | 350 sys.stdout as in Run. |
391 | 351 |
392 Args: | 352 Args: |
393 verbose: If True, uses verbose output | 353 verbose: If True, uses verbose output |
394 args: A sequence of command line parameters to be passed to svn. | 354 args: A sequence of command line parameters to be passed to svn. |
395 in_directory: The directory where svn is to be run. | 355 cwd: The directory where svn is to be run. |
396 | 356 |
397 Raises: | 357 Raises: |
398 Error: An error occurred while running the svn command. | 358 Error: An error occurred while running the svn command. |
399 """ | 359 """ |
400 command = [SVN.COMMAND] | 360 stdout = stdout or sys.stdout |
401 command.extend(args) | |
402 | 361 |
403 # svn update and svn checkout use the same pattern: the first three columns | 362 # svn update and svn checkout use the same pattern: the first three columns |
404 # are for file status, property status, and lock status. This is followed | 363 # are for file status, property status, and lock status. This is followed |
405 # by two spaces, and then the path to the file. | 364 # by two spaces, and then the path to the file. |
406 update_pattern = '^... (.*)$' | 365 update_pattern = '^... (.*)$' |
407 | 366 |
408 # The first three columns of svn status are the same as for svn update and | 367 # The first three columns of svn status are the same as for svn update and |
409 # svn checkout. The next three columns indicate addition-with-history, | 368 # svn checkout. The next three columns indicate addition-with-history, |
410 # switch, and remote lock status. This is followed by one space, and then | 369 # switch, and remote lock status. This is followed by one space, and then |
411 # the path to the file. | 370 # the path to the file. |
(...skipping 15 matching lines...) Expand all Loading... |
427 failure = [] | 386 failure = [] |
428 | 387 |
429 def CaptureMatchingLines(line): | 388 def CaptureMatchingLines(line): |
430 match = compiled_pattern.search(line) | 389 match = compiled_pattern.search(line) |
431 if match: | 390 if match: |
432 file_list.append(match.group(1)) | 391 file_list.append(match.group(1)) |
433 if line.startswith('svn: '): | 392 if line.startswith('svn: '): |
434 failure.append(line) | 393 failure.append(line) |
435 | 394 |
436 try: | 395 try: |
437 SVN.RunAndFilterOutput(args, | 396 SVN.RunAndFilterOutput(args, cwd=cwd, print_messages=verbose, |
438 in_directory, | 397 print_stdout=True, |
439 verbose, | 398 filter_fn=CaptureMatchingLines, |
440 True, | |
441 CaptureMatchingLines, | |
442 stdout=stdout) | 399 stdout=stdout) |
443 except gclient_utils.Error: | 400 except gclient_utils.Error: |
444 def IsKnownFailure(): | 401 def IsKnownFailure(): |
445 for x in failure: | 402 for x in failure: |
446 if (x.startswith('svn: OPTIONS of') or | 403 if (x.startswith('svn: OPTIONS of') or |
447 x.startswith('svn: PROPFIND of') or | 404 x.startswith('svn: PROPFIND of') or |
448 x.startswith('svn: REPORT of') or | 405 x.startswith('svn: REPORT of') or |
449 x.startswith('svn: Unknown hostname') or | 406 x.startswith('svn: Unknown hostname') or |
450 x.startswith('svn: Server sent unexpected return value')): | 407 x.startswith('svn: Server sent unexpected return value')): |
451 return True | 408 return True |
(...skipping 22 matching lines...) Expand all Loading... |
474 # We enforce that some progress has been made or a known failure. | 431 # We enforce that some progress has been made or a known failure. |
475 if len(file_list) == previous_list_len and not IsKnownFailure(): | 432 if len(file_list) == previous_list_len and not IsKnownFailure(): |
476 # No known svn error was found and no progress, bail out. | 433 # No known svn error was found and no progress, bail out. |
477 raise | 434 raise |
478 print "Sleeping 15 seconds and retrying...." | 435 print "Sleeping 15 seconds and retrying...." |
479 time.sleep(15) | 436 time.sleep(15) |
480 continue | 437 continue |
481 break | 438 break |
482 | 439 |
483 @staticmethod | 440 @staticmethod |
484 def RunAndFilterOutput(args, | 441 def RunAndFilterOutput(args, **kwargs): |
485 in_directory, | 442 """Wrapper for gclient_utils.SubprocessCallAndFilter().""" |
486 print_messages, | 443 return gclient_utils.SubprocessCallAndFilter([SVN.COMMAND] + args, **kwargs) |
487 print_stdout, | |
488 filter_fn, | |
489 stdout=None): | |
490 """Runs a command, optionally outputting to stdout. | |
491 | |
492 stdout is passed line-by-line to the given filter_fn function. If | |
493 print_stdout is true, it is also printed to sys.stdout as in Run. | |
494 | |
495 Args: | |
496 args: A sequence of command line parameters to be passed. | |
497 in_directory: The directory where svn is to be run. | |
498 print_messages: Whether to print status messages to stdout about | |
499 which commands are being run. | |
500 print_stdout: Whether to forward program's output to stdout. | |
501 filter_fn: A function taking one argument (a string) which will be | |
502 passed each line (with the ending newline character removed) of | |
503 program's output for filtering. | |
504 | |
505 Raises: | |
506 gclient_utils.Error: An error occurred while running the command. | |
507 """ | |
508 command = [SVN.COMMAND] | |
509 command.extend(args) | |
510 gclient_utils.SubprocessCallAndFilter(command, | |
511 in_directory, | |
512 print_messages, | |
513 print_stdout, | |
514 filter_fn=filter_fn, | |
515 stdout=stdout) | |
516 | 444 |
517 @staticmethod | 445 @staticmethod |
518 def CaptureInfo(relpath, in_directory=None, print_error=True): | 446 def CaptureInfo(relpath, in_directory=None, print_error=True): |
519 """Returns a dictionary from the svn info output for the given file. | 447 """Returns a dictionary from the svn info output for the given file. |
520 | 448 |
521 Args: | 449 Args: |
522 relpath: The directory where the working copy resides relative to | 450 relpath: The directory where the working copy resides relative to |
523 the directory given by in_directory. | 451 the directory given by in_directory. |
524 in_directory: The directory where svn is to be run. | 452 in_directory: The directory where svn is to be run. |
525 """ | 453 """ |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
934 if not SVN.current_version: | 862 if not SVN.current_version: |
935 SVN.current_version = SVN.Capture(['--version']).split()[2] | 863 SVN.current_version = SVN.Capture(['--version']).split()[2] |
936 current_version_list = map(only_int, SVN.current_version.split('.')) | 864 current_version_list = map(only_int, SVN.current_version.split('.')) |
937 for min_ver in map(int, min_version.split('.')): | 865 for min_ver in map(int, min_version.split('.')): |
938 ver = current_version_list.pop(0) | 866 ver = current_version_list.pop(0) |
939 if ver < min_ver: | 867 if ver < min_ver: |
940 return (False, SVN.current_version) | 868 return (False, SVN.current_version) |
941 elif ver > min_ver: | 869 elif ver > min_ver: |
942 return (True, SVN.current_version) | 870 return (True, SVN.current_version) |
943 return (True, SVN.current_version) | 871 return (True, SVN.current_version) |
OLD | NEW |