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

Side by Side Diff: gclient.py

Issue 113278: Simplify some functions by removing the options.stdout mock. Fix the unit tes... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 11 years, 7 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
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright 2008 Google Inc. All Rights Reserved. 3 # Copyright 2008 Google Inc. All Rights Reserved.
4 # 4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License. 6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at 7 # You may obtain a copy of the License at
8 # 8 #
9 # http://www.apache.org/licenses/LICENSE-2.0 9 # http://www.apache.org/licenses/LICENSE-2.0
10 # 10 #
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 to run the command. 57 to run the command.
58 58
59 Example: 59 Example:
60 hooks = [ 60 hooks = [
61 { "pattern": "\\.(gif|jpe?g|pr0n|png)$", 61 { "pattern": "\\.(gif|jpe?g|pr0n|png)$",
62 "action": ["python", "image_indexer.py", "--all"]}, 62 "action": ["python", "image_indexer.py", "--all"]},
63 ] 63 ]
64 """ 64 """
65 65
66 __author__ = "darinf@gmail.com (Darin Fisher)" 66 __author__ = "darinf@gmail.com (Darin Fisher)"
67 __version__ = "0.3.1" 67 __version__ = "0.3.2"
68 68
69 import errno 69 import errno
70 import optparse 70 import optparse
71 import os 71 import os
72 import re 72 import re
73 import stat 73 import stat
74 import subprocess 74 import subprocess
75 import sys 75 import sys
76 import time 76 import time
77 import urlparse 77 import urlparse
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 try: 390 try:
391 os.rmdir(file_path) 391 os.rmdir(file_path)
392 except OSError, e: 392 except OSError, e:
393 if e.errno != errno.EACCES or sys.platform != 'win32': 393 if e.errno != errno.EACCES or sys.platform != 'win32':
394 raise 394 raise
395 print 'Failed to remove %s: trying again' % file_path 395 print 'Failed to remove %s: trying again' % file_path
396 time.sleep(0.1) 396 time.sleep(0.1)
397 os.rmdir(file_path) 397 os.rmdir(file_path)
398 398
399 399
400 def SubprocessCall(command, in_directory, out, fail_status=None): 400 def SubprocessCall(command, in_directory, fail_status=None):
401 """Runs command, a list, in directory in_directory. 401 """Runs command, a list, in directory in_directory.
402 402
403 This function wraps SubprocessCallAndCapture, but does not perform the 403 This function wraps SubprocessCallAndCapture, but does not perform the
404 capturing functions. See that function for a more complete usage 404 capturing functions. See that function for a more complete usage
405 description. 405 description.
406 """ 406 """
407 # Call subprocess and capture nothing: 407 # Call subprocess and capture nothing:
408 SubprocessCallAndCapture(command, in_directory, out, fail_status) 408 SubprocessCallAndCapture(command, in_directory, fail_status)
409 409
410 410
411 def SubprocessCallAndCapture(command, in_directory, out, fail_status=None, 411 def SubprocessCallAndCapture(command, in_directory, fail_status=None,
412 pattern=None, capture_list=None): 412 pattern=None, capture_list=None):
413 """Runs command, a list, in directory in_directory. 413 """Runs command, a list, in directory in_directory.
414 414
415 A message indicating what is being done, as well as the command's stdout, 415 A message indicating what is being done, as well as the command's stdout,
416 is printed to out. 416 is printed to out.
417 417
418 If a pattern is specified, any line in the output matching pattern will have 418 If a pattern is specified, any line in the output matching pattern will have
419 its first match group appended to capture_list. 419 its first match group appended to capture_list.
420 420
421 If the command fails, as indicated by a nonzero exit status, gclient will 421 If the command fails, as indicated by a nonzero exit status, gclient will
422 exit with an exit status of fail_status. If fail_status is None (the 422 exit with an exit status of fail_status. If fail_status is None (the
423 default), gclient will raise an Error exception. 423 default), gclient will raise an Error exception.
424 """ 424 """
425 425
426 print >> out, ("\n________ running \'%s\' in \'%s\'" 426 print("\n________ running \'%s\' in \'%s\'"
427 % (' '.join(command), in_directory)) 427 % (' '.join(command), in_directory))
428 428
429 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the 429 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the
430 # executable, but shell=True makes subprocess on Linux fail when it's called 430 # executable, but shell=True makes subprocess on Linux fail when it's called
431 # with a list because it only tries to execute the first item in the list. 431 # with a list because it only tries to execute the first item in the list.
432 kid = subprocess.Popen(command, bufsize=0, cwd=in_directory, 432 kid = subprocess.Popen(command, bufsize=0, cwd=in_directory,
433 shell=(sys.platform == 'win32'), stdout=subprocess.PIPE) 433 shell=(sys.platform == 'win32'), stdout=subprocess.PIPE)
434 434
435 if pattern: 435 if pattern:
436 compiled_pattern = re.compile(pattern) 436 compiled_pattern = re.compile(pattern)
437 437
438 # Also, we need to forward stdout to prevent weird re-ordering of output. 438 # Also, we need to forward stdout to prevent weird re-ordering of output.
439 # This has to be done on a per byte basis to make sure it is not buffered: 439 # This has to be done on a per byte basis to make sure it is not buffered:
440 # normally buffering is done for each line, but if svn requests input, no 440 # normally buffering is done for each line, but if svn requests input, no
441 # end-of-line character is output after the prompt and it would not show up. 441 # end-of-line character is output after the prompt and it would not show up.
442 in_byte = kid.stdout.read(1) 442 in_byte = kid.stdout.read(1)
443 in_line = "" 443 in_line = ""
444 while in_byte: 444 while in_byte:
445 if in_byte != "\r": 445 if in_byte != "\r":
446 out.write(in_byte) 446 sys.stdout.write(in_byte)
447 in_line += in_byte 447 in_line += in_byte
448 if in_byte == "\n" and pattern: 448 if in_byte == "\n" and pattern:
449 match = compiled_pattern.search(in_line[:-1]) 449 match = compiled_pattern.search(in_line[:-1])
450 if match: 450 if match:
451 capture_list.append(match.group(1)) 451 capture_list.append(match.group(1))
452 in_line = "" 452 in_line = ""
453 in_byte = kid.stdout.read(1) 453 in_byte = kid.stdout.read(1)
454 rv = kid.wait() 454 rv = kid.wait()
455 455
456 if rv: 456 if rv:
(...skipping 11 matching lines...) Expand all
468 |entries| is a list of paths to check.""" 468 |entries| is a list of paths to check."""
469 for path in paths: 469 for path in paths:
470 if os.path.exists(os.path.join(root, path, '.git')): 470 if os.path.exists(os.path.join(root, path, '.git')):
471 return True 471 return True
472 return False 472 return False
473 473
474 # ----------------------------------------------------------------------------- 474 # -----------------------------------------------------------------------------
475 # SVN utils: 475 # SVN utils:
476 476
477 477
478 def RunSVN(options, args, in_directory): 478 def RunSVN(args, in_directory):
479 """Runs svn, sending output to stdout. 479 """Runs svn, sending output to stdout.
480 480
481 Args: 481 Args:
482 args: A sequence of command line parameters to be passed to svn. 482 args: A sequence of command line parameters to be passed to svn.
483 in_directory: The directory where svn is to be run. 483 in_directory: The directory where svn is to be run.
484 484
485 Raises: 485 Raises:
486 Error: An error occurred while running the svn command. 486 Error: An error occurred while running the svn command.
487 """ 487 """
488 c = [SVN_COMMAND] 488 c = [SVN_COMMAND]
489 c.extend(args) 489 c.extend(args)
490 490
491 SubprocessCall(c, in_directory, options.stdout) 491 SubprocessCall(c, in_directory)
492 492
493 493
494 def CaptureSVN(options, args, in_directory): 494 def CaptureSVN(args, in_directory):
495 """Runs svn, capturing output sent to stdout as a string. 495 """Runs svn, capturing output sent to stdout as a string.
496 496
497 Args: 497 Args:
498 args: A sequence of command line parameters to be passed to svn. 498 args: A sequence of command line parameters to be passed to svn.
499 in_directory: The directory where svn is to be run. 499 in_directory: The directory where svn is to be run.
500 500
501 Returns: 501 Returns:
502 The output sent to stdout as a string. 502 The output sent to stdout as a string.
503 """ 503 """
504 c = [SVN_COMMAND] 504 c = [SVN_COMMAND]
505 c.extend(args) 505 c.extend(args)
506 506
507 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for 507 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for
508 # the svn.exe executable, but shell=True makes subprocess on Linux fail 508 # the svn.exe executable, but shell=True makes subprocess on Linux fail
509 # when it's called with a list because it only tries to execute the 509 # when it's called with a list because it only tries to execute the
510 # first string ("svn"). 510 # first string ("svn").
511 return subprocess.Popen(c, cwd=in_directory, shell=(sys.platform == 'win32'), 511 return subprocess.Popen(c,
512 cwd=in_directory,
513 shell=(sys.platform == 'win32'),
512 stdout=subprocess.PIPE).communicate()[0] 514 stdout=subprocess.PIPE).communicate()[0]
513 515
514 516
515 def RunSVNAndGetFileList(options, args, in_directory, file_list): 517 def RunSVNAndGetFileList(args, in_directory, file_list):
516 """Runs svn checkout, update, or status, output to stdout. 518 """Runs svn checkout, update, or status, output to stdout.
517 519
518 The first item in args must be either "checkout", "update", or "status". 520 The first item in args must be either "checkout", "update", or "status".
519 521
520 svn's stdout is parsed to collect a list of files checked out or updated. 522 svn's stdout is parsed to collect a list of files checked out or updated.
521 These files are appended to file_list. svn's stdout is also printed to 523 These files are appended to file_list. svn's stdout is also printed to
522 sys.stdout as in RunSVN. 524 sys.stdout as in RunSVN.
523 525
524 Args: 526 Args:
525 args: A sequence of command line parameters to be passed to svn. 527 args: A sequence of command line parameters to be passed to svn.
(...skipping 19 matching lines...) Expand all
545 # args[0] must be a supported command. This will blow up if it's something 547 # args[0] must be a supported command. This will blow up if it's something
546 # else, which is good. Note that the patterns are only effective when 548 # else, which is good. Note that the patterns are only effective when
547 # these commands are used in their ordinary forms, the patterns are invalid 549 # these commands are used in their ordinary forms, the patterns are invalid
548 # for "svn status --show-updates", for example. 550 # for "svn status --show-updates", for example.
549 pattern = { 551 pattern = {
550 'checkout': update_pattern, 552 'checkout': update_pattern,
551 'status': status_pattern, 553 'status': status_pattern,
552 'update': update_pattern, 554 'update': update_pattern,
553 }[args[0]] 555 }[args[0]]
554 556
555 SubprocessCallAndCapture(command, in_directory, options.stdout, 557 SubprocessCallAndCapture(command,
556 pattern=pattern, capture_list=file_list) 558 in_directory,
559 pattern=pattern,
560 capture_list=file_list)
557 561
558 562
559 def CaptureSVNInfo(options, relpath, in_directory): 563 def CaptureSVNInfo(relpath, in_directory=None):
560 """Returns a dictionary from the svn info output for the given file. 564 """Returns a dictionary from the svn info output for the given file.
561 565
562 Args: 566 Args:
563 relpath: The directory where the working copy resides relative to 567 relpath: The directory where the working copy resides relative to
564 the directory given by in_directory. 568 the directory given by in_directory.
565 in_directory: The directory where svn is to be run. 569 in_directory: The directory where svn is to be run.
566 """ 570 """
567 dom = ParseXML(CaptureSVN(options, ["info", "--xml", relpath], in_directory)) 571 output = CaptureSVN(["info", "--xml", relpath], in_directory)
572 dom = ParseXML(output)
568 result = {} 573 result = {}
569 if dom: 574 if dom:
570 def C(item, f): 575 def C(item, f):
571 if item is not None: return f(item) 576 if item is not None: return f(item)
572 # /info/entry/ 577 # /info/entry/
573 # url 578 # url
574 # reposityory/(root|uuid) 579 # reposityory/(root|uuid)
575 # wc-info/(schedule|depth) 580 # wc-info/(schedule|depth)
576 # commit/(author|date) 581 # commit/(author|date)
577 # str() the results because they may be returned as Unicode, which 582 # str() the results because they may be returned as Unicode, which
578 # interferes with the higher layers matching up things in the deps 583 # interferes with the higher layers matching up things in the deps
579 # dictionary. 584 # dictionary.
580 # TODO(maruel): Fix at higher level instead (!) 585 # TODO(maruel): Fix at higher level instead (!)
581 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str) 586 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
582 result['URL'] = C(GetNamedNodeText(dom, 'url'), str) 587 result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
583 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str) 588 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
584 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'), 589 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'),
585 int) 590 int)
586 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'), 591 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
587 str) 592 str)
588 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str) 593 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
589 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str) 594 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
590 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str) 595 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
591 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str) 596 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
592 return result 597 return result
593 598
594 599
595 def CaptureSVNHeadRevision(options, url): 600 def CaptureSVNHeadRevision(url):
596 """Get the head revision of a SVN repository. 601 """Get the head revision of a SVN repository.
597 602
598 Returns: 603 Returns:
599 Int head revision 604 Int head revision
600 """ 605 """
601 info = CaptureSVN(options, ["info", "--xml", url], os.getcwd()) 606 info = CaptureSVN(["info", "--xml", url], os.getcwd())
602 dom = xml.dom.minidom.parseString(info) 607 dom = xml.dom.minidom.parseString(info)
603 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision')) 608 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision'))
604 609
605 610
606 class FileStatus: 611 class FileStatus:
607 def __init__(self, path, text_status, props, lock, history): 612 def __init__(self, path, text_status, props, lock, history):
608 self.path = path 613 self.path = path
609 self.text_status = text_status 614 self.text_status = text_status
610 self.props = props 615 self.props = props
611 self.lock = lock 616 self.lock = lock
612 self.history = history 617 self.history = history
613 618
614 def __str__(self): 619 def __str__(self):
615 # Emulate svn status 1.5 output. 620 # Emulate svn status 1.5 output.
616 return (self.text_status + self.props + self.lock + self.history + ' ' + 621 return (self.text_status + self.props + self.lock + self.history + ' ' +
617 self.path) 622 self.path)
618 623
619 624
620 def CaptureSVNStatus(options, path): 625 def CaptureSVNStatus(path):
621 """Runs 'svn status' on an existing path. 626 """Runs 'svn status' on an existing path.
622 627
623 Args: 628 Args:
624 path: The directory to run svn status. 629 path: The directory to run svn status.
625 630
626 Returns: 631 Returns:
627 An array of FileStatus corresponding to the emulated output of 'svn status' 632 An array of FileStatus corresponding to the emulated output of 'svn status'
628 version 1.5.""" 633 version 1.5."""
629 dom = ParseXML(CaptureSVN(options, ["status", "--xml"], path)) 634 dom = ParseXML(CaptureSVN(["status", "--xml"], path))
630 results = [] 635 results = []
631 if dom: 636 if dom:
632 # /status/target/entry/(wc-status|commit|author|date) 637 # /status/target/entry/(wc-status|commit|author|date)
633 for target in dom.getElementsByTagName('target'): 638 for target in dom.getElementsByTagName('target'):
634 base_path = target.getAttribute('path') 639 base_path = target.getAttribute('path')
635 for entry in target.getElementsByTagName('entry'): 640 for entry in target.getElementsByTagName('entry'):
636 file = entry.getAttribute('path') 641 file = entry.getAttribute('path')
637 wc_status = entry.getElementsByTagName('wc-status') 642 wc_status = entry.getElementsByTagName('wc-status')
638 assert len(wc_status) == 1 643 assert len(wc_status) == 1
639 # Emulate svn 1.5 status ouput... 644 # Emulate svn 1.5 status ouput...
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 726
722 if not command in commands: 727 if not command in commands:
723 raise Error('Unknown command %s' % command) 728 raise Error('Unknown command %s' % command)
724 729
725 return commands[command](options, args, file_list) 730 return commands[command](options, args, file_list)
726 731
727 def cleanup(self, options, args, file_list): 732 def cleanup(self, options, args, file_list):
728 """Cleanup working copy.""" 733 """Cleanup working copy."""
729 command = ['cleanup'] 734 command = ['cleanup']
730 command.extend(args) 735 command.extend(args)
731 RunSVN(options, command, os.path.join(self._root_dir, self.relpath)) 736 RunSVN(command, os.path.join(self._root_dir, self.relpath))
732 737
733 def diff(self, options, args, file_list): 738 def diff(self, options, args, file_list):
734 # NOTE: This function does not currently modify file_list. 739 # NOTE: This function does not currently modify file_list.
735 command = ['diff'] 740 command = ['diff']
736 command.extend(args) 741 command.extend(args)
737 RunSVN(options, command, os.path.join(self._root_dir, self.relpath)) 742 RunSVN(command, os.path.join(self._root_dir, self.relpath))
738 743
739 def update(self, options, args, file_list): 744 def update(self, options, args, file_list):
740 """Runs SCM to update or transparently checkout the working copy. 745 """Runs SCM to update or transparently checkout the working copy.
741 746
742 All updated files will be appended to file_list. 747 All updated files will be appended to file_list.
743 748
744 Raises: 749 Raises:
745 Error: if can't get URL for relative path. 750 Error: if can't get URL for relative path.
746 """ 751 """
747 # Only update if git is not controlling the directory. 752 # Only update if git is not controlling the directory.
748 git_path = os.path.join(self._root_dir, self.relpath, '.git') 753 git_path = os.path.join(self._root_dir, self.relpath, '.git')
749 if options.path_exists(git_path): 754 if options.path_exists(git_path):
750 print >> options.stdout, ( 755 print("________ found .git directory; skipping %s" % self.relpath)
751 "________ found .git directory; skipping %s" % self.relpath)
752 return 756 return
753 757
754 if args: 758 if args:
755 raise Error("Unsupported argument(s): %s" % ",".join(args)) 759 raise Error("Unsupported argument(s): %s" % ",".join(args))
756 760
757 url = self.url 761 url = self.url
758 components = url.split("@") 762 components = url.split("@")
759 revision = None 763 revision = None
760 forced_revision = False 764 forced_revision = False
761 if options.revision: 765 if options.revision:
762 # Override the revision number. 766 # Override the revision number.
763 url = '%s@%s' % (components[0], str(options.revision)) 767 url = '%s@%s' % (components[0], str(options.revision))
764 revision = int(options.revision) 768 revision = int(options.revision)
765 forced_revision = True 769 forced_revision = True
766 elif len(components) == 2: 770 elif len(components) == 2:
767 revision = int(components[1]) 771 revision = int(components[1])
768 forced_revision = True 772 forced_revision = True
769 773
770 rev_str = "" 774 rev_str = ""
771 if revision: 775 if revision:
772 rev_str = ' at %d' % revision 776 rev_str = ' at %d' % revision
773 777
774 if not options.path_exists(os.path.join(self._root_dir, self.relpath)): 778 if not options.path_exists(os.path.join(self._root_dir, self.relpath)):
775 # We need to checkout. 779 # We need to checkout.
776 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)] 780 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)]
777 if revision: 781 if revision:
778 command.extend(['--revision', str(revision)]) 782 command.extend(['--revision', str(revision)])
779 RunSVNAndGetFileList(options, command, self._root_dir, file_list) 783 RunSVNAndGetFileList(command, self._root_dir, file_list)
780 return 784 return
781 785
782 # Get the existing scm url and the revision number of the current checkout. 786 # Get the existing scm url and the revision number of the current checkout.
783 from_info = CaptureSVNInfo(options, 787 from_info = CaptureSVNInfo(os.path.join(self._root_dir, self.relpath, '.'),
784 os.path.join(self._root_dir, self.relpath, '.'),
785 '.') 788 '.')
786 789
787 if options.manually_grab_svn_rev: 790 if options.manually_grab_svn_rev:
788 # Retrieve the current HEAD version because svn is slow at null updates. 791 # Retrieve the current HEAD version because svn is slow at null updates.
789 if not revision: 792 if not revision:
790 from_info_live = CaptureSVNInfo(options, from_info['URL'], '.') 793 from_info_live = CaptureSVNInfo(from_info['URL'], '.')
791 revision = int(from_info_live['Revision']) 794 revision = int(from_info_live['Revision'])
792 rev_str = ' at %d' % revision 795 rev_str = ' at %d' % revision
793 796
794 if from_info['URL'] != components[0]: 797 if from_info['URL'] != components[0]:
795 to_info = CaptureSVNInfo(options, url, '.') 798 to_info = CaptureSVNInfo(url, '.')
796 if from_info['Repository Root'] != to_info['Repository Root']: 799 if from_info['Repository Root'] != to_info['Repository Root']:
797 # We have different roots, so check if we can switch --relocate. 800 # We have different roots, so check if we can switch --relocate.
798 # Subversion only permits this if the repository UUIDs match. 801 # Subversion only permits this if the repository UUIDs match.
799 if from_info['UUID'] != to_info['UUID']: 802 if from_info['UUID'] != to_info['UUID']:
800 raise Error("Can't switch the checkout to %s; UUID don't match. That " 803 raise Error("Can't switch the checkout to %s; UUID don't match. That "
801 "simply means in theory, gclient should verify you don't " 804 "simply means in theory, gclient should verify you don't "
802 "have a local change, remove the old checkout and do a " 805 "have a local change, remove the old checkout and do a "
803 "fresh new checkout of the new repo. Contributions are " 806 "fresh new checkout of the new repo. Contributions are "
804 "welcome." % url) 807 "welcome." % url)
805 808
806 # Perform the switch --relocate, then rewrite the from_url 809 # Perform the switch --relocate, then rewrite the from_url
807 # to reflect where we "are now." (This is the same way that 810 # to reflect where we "are now." (This is the same way that
808 # Subversion itself handles the metadata when switch --relocate 811 # Subversion itself handles the metadata when switch --relocate
809 # is used.) This makes the checks below for whether we 812 # is used.) This makes the checks below for whether we
810 # can update to a revision or have to switch to a different 813 # can update to a revision or have to switch to a different
811 # branch work as expected. 814 # branch work as expected.
812 # TODO(maruel): TEST ME ! 815 # TODO(maruel): TEST ME !
813 command = ["switch", "--relocate", 816 command = ["switch", "--relocate",
814 from_info['Repository Root'], 817 from_info['Repository Root'],
815 to_info['Repository Root'], 818 to_info['Repository Root'],
816 self.relpath] 819 self.relpath]
817 RunSVN(options, command, self._root_dir) 820 RunSVN(command, self._root_dir)
818 from_info['URL'] = from_info['URL'].replace( 821 from_info['URL'] = from_info['URL'].replace(
819 from_info['Repository Root'], 822 from_info['Repository Root'],
820 to_info['Repository Root']) 823 to_info['Repository Root'])
821 824
822 # If the provided url has a revision number that matches the revision 825 # If the provided url has a revision number that matches the revision
823 # number of the existing directory, then we don't need to bother updating. 826 # number of the existing directory, then we don't need to bother updating.
824 if not options.force and from_info['Revision'] == revision: 827 if not options.force and from_info['Revision'] == revision:
825 if options.verbose or not forced_revision: 828 if options.verbose or not forced_revision:
826 print >>options.stdout, ("\n_____ %s%s" % ( 829 print("\n_____ %s%s" % (self.relpath, rev_str))
827 self.relpath, rev_str))
828 return 830 return
829 831
830 command = ["update", os.path.join(self._root_dir, self.relpath)] 832 command = ["update", os.path.join(self._root_dir, self.relpath)]
831 if revision: 833 if revision:
832 command.extend(['--revision', str(revision)]) 834 command.extend(['--revision', str(revision)])
833 RunSVNAndGetFileList(options, command, self._root_dir, file_list) 835 RunSVNAndGetFileList(command, self._root_dir, file_list)
834 836
835 def revert(self, options, args, file_list): 837 def revert(self, options, args, file_list):
836 """Reverts local modifications. Subversion specific. 838 """Reverts local modifications. Subversion specific.
837 839
838 All reverted files will be appended to file_list, even if Subversion 840 All reverted files will be appended to file_list, even if Subversion
839 doesn't know about them. 841 doesn't know about them.
840 """ 842 """
841 path = os.path.join(self._root_dir, self.relpath) 843 path = os.path.join(self._root_dir, self.relpath)
842 if not os.path.isdir(path): 844 if not os.path.isdir(path):
843 # svn revert won't work if the directory doesn't exist. It needs to 845 # svn revert won't work if the directory doesn't exist. It needs to
844 # checkout instead. 846 # checkout instead.
845 print >>options.stdout, ("\n_____ %s is missing, synching instead" % 847 print("\n_____ %s is missing, synching instead" % self.relpath)
846 self.relpath)
847 # Don't reuse the args. 848 # Don't reuse the args.
848 return self.update(options, [], file_list) 849 return self.update(options, [], file_list)
849 850
850 files = CaptureSVNStatus(options, path) 851 files = CaptureSVNStatus(path)
851 # Batch the command. 852 # Batch the command.
852 files_to_revert = [] 853 files_to_revert = []
853 for file in files: 854 for file in files:
854 file_path = os.path.join(path, file.path) 855 file_path = os.path.join(path, file.path)
855 print >>options.stdout, file_path 856 print(file_path)
856 # Unversioned file or unexpected unversioned file. 857 # Unversioned file or unexpected unversioned file.
857 if file.text_status in ('?', '~'): 858 if file.text_status in ('?', '~'):
858 # Remove extraneous file. Also remove unexpected unversioned 859 # Remove extraneous file. Also remove unexpected unversioned
859 # directories. svn won't touch them but we want to delete these. 860 # directories. svn won't touch them but we want to delete these.
860 file_list.append(file_path) 861 file_list.append(file_path)
861 try: 862 try:
862 os.remove(file_path) 863 os.remove(file_path)
863 except EnvironmentError: 864 except EnvironmentError:
864 RemoveDirectory(file_path) 865 RemoveDirectory(file_path)
865 866
866 if file.text_status != '?': 867 if file.text_status != '?':
867 # For any other status, svn revert will work. 868 # For any other status, svn revert will work.
868 file_list.append(file_path) 869 file_list.append(file_path)
869 files_to_revert.append(file.path) 870 files_to_revert.append(file.path)
870 871
871 # Revert them all at once. 872 # Revert them all at once.
872 if files_to_revert: 873 if files_to_revert:
873 accumulated_paths = [] 874 accumulated_paths = []
874 accumulated_length = 0 875 accumulated_length = 0
875 command = ['revert'] 876 command = ['revert']
876 for p in files_to_revert: 877 for p in files_to_revert:
877 # Some shell have issues with command lines too long. 878 # Some shell have issues with command lines too long.
878 if accumulated_length and accumulated_length + len(p) > 3072: 879 if accumulated_length and accumulated_length + len(p) > 3072:
879 RunSVN(options, command + accumulated_paths, 880 RunSVN(command + accumulated_paths,
880 os.path.join(self._root_dir, self.relpath)) 881 os.path.join(self._root_dir, self.relpath))
881 accumulated_paths = [] 882 accumulated_paths = []
882 accumulated_length = 0 883 accumulated_length = 0
883 else: 884 else:
884 accumulated_paths.append(p) 885 accumulated_paths.append(p)
885 accumulated_length += len(p) 886 accumulated_length += len(p)
886 if accumulated_paths: 887 if accumulated_paths:
887 RunSVN(options, command + accumulated_paths, 888 RunSVN(command + accumulated_paths,
888 os.path.join(self._root_dir, self.relpath)) 889 os.path.join(self._root_dir, self.relpath))
889 890
890 def status(self, options, args, file_list): 891 def status(self, options, args, file_list):
891 """Display status information.""" 892 """Display status information."""
892 path = os.path.join(self._root_dir, self.relpath) 893 path = os.path.join(self._root_dir, self.relpath)
893 command = ['status'] 894 command = ['status']
894 command.extend(args) 895 command.extend(args)
895 if not os.path.isdir(path): 896 if not os.path.isdir(path):
896 # svn status won't work if the directory doesn't exist. 897 # svn status won't work if the directory doesn't exist.
897 print >> options.stdout, ( 898 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory "
898 "\n________ couldn't run \'%s\' in \'%s\':\nThe directory " 899 "does not exist."
899 "does not exist." 900 % (' '.join(command), path))
900 % (' '.join(command), path))
901 # There's no file list to retrieve. 901 # There's no file list to retrieve.
902 else: 902 else:
903 RunSVNAndGetFileList(options, command, path, file_list) 903 RunSVNAndGetFileList(command, path, file_list)
904 904
905 905
906 ## GClient implementation. 906 ## GClient implementation.
907 907
908 908
909 class GClient(object): 909 class GClient(object):
910 """Object that represent a gclient checkout.""" 910 """Object that represent a gclient checkout."""
911 911
912 supported_commands = [ 912 supported_commands = [
913 'cleanup', 'diff', 'revert', 'status', 'update', 'runhooks' 913 'cleanup', 'diff', 'revert', 'status', 'update', 'runhooks'
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
1174 command = hook_dict['action'][:] 1174 command = hook_dict['action'][:]
1175 if command[0] == 'python': 1175 if command[0] == 'python':
1176 # If the hook specified "python" as the first item, the action is a 1176 # If the hook specified "python" as the first item, the action is a
1177 # Python script. Run it by starting a new copy of the same 1177 # Python script. Run it by starting a new copy of the same
1178 # interpreter. 1178 # interpreter.
1179 command[0] = sys.executable 1179 command[0] = sys.executable
1180 1180
1181 # Use a discrete exit status code of 2 to indicate that a hook action 1181 # Use a discrete exit status code of 2 to indicate that a hook action
1182 # failed. Users of this script may wish to treat hook action failures 1182 # failed. Users of this script may wish to treat hook action failures
1183 # differently from VC failures. 1183 # differently from VC failures.
1184 SubprocessCall(command, self._root_dir, self._options.stdout, 1184 SubprocessCall(command, self._root_dir, fail_status=2)
1185 fail_status=2)
1186 1185
1187 def _RunHooks(self, command, file_list, is_using_git): 1186 def _RunHooks(self, command, file_list, is_using_git):
1188 """Evaluates all hooks, running actions as needed. 1187 """Evaluates all hooks, running actions as needed.
1189 """ 1188 """
1190 # Hooks only run for these command types. 1189 # Hooks only run for these command types.
1191 if not command in ('update', 'revert', 'runhooks'): 1190 if not command in ('update', 'revert', 'runhooks'):
1192 return 1191 return
1193 1192
1194 # Get any hooks from the .gclient file. 1193 # Get any hooks from the .gclient file.
1195 hooks = self.GetVar("hooks", []) 1194 hooks = self.GetVar("hooks", [])
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1318 self._RunHooks(command, file_list, is_using_git) 1317 self._RunHooks(command, file_list, is_using_git)
1319 1318
1320 if command == 'update': 1319 if command == 'update':
1321 # notify the user if there is an orphaned entry in their working copy. 1320 # notify the user if there is an orphaned entry in their working copy.
1322 # TODO(darin): we should delete this directory manually if it doesn't 1321 # TODO(darin): we should delete this directory manually if it doesn't
1323 # have any changes in it. 1322 # have any changes in it.
1324 prev_entries = self._ReadEntries() 1323 prev_entries = self._ReadEntries()
1325 for entry in prev_entries: 1324 for entry in prev_entries:
1326 e_dir = os.path.join(self._root_dir, entry) 1325 e_dir = os.path.join(self._root_dir, entry)
1327 if entry not in entries and self._options.path_exists(e_dir): 1326 if entry not in entries and self._options.path_exists(e_dir):
1328 if CaptureSVNStatus(self._options, e_dir): 1327 if CaptureSVNStatus(e_dir):
1329 # There are modified files in this entry 1328 # There are modified files in this entry
1330 entries[entry] = None # Keep warning until removed. 1329 entries[entry] = None # Keep warning until removed.
1331 print >> self._options.stdout, ( 1330 print("\nWARNING: \"%s\" is no longer part of this client. "
1332 "\nWARNING: \"%s\" is no longer part of this client. " 1331 "It is recommended that you manually remove it.\n") % entry
1333 "It is recommended that you manually remove it.\n") % entry
1334 else: 1332 else:
1335 # Delete the entry 1333 # Delete the entry
1336 print >> self._options.stdout, ("\n________ deleting \'%s\' " + 1334 print("\n________ deleting \'%s\' " +
1337 "in \'%s\'") % (entry, self._root_dir) 1335 "in \'%s\'") % (entry, self._root_dir)
1338 RemoveDirectory(e_dir) 1336 RemoveDirectory(e_dir)
1339 # record the current list of entries for next time 1337 # record the current list of entries for next time
1340 self._SaveEntries(entries) 1338 self._SaveEntries(entries)
1341 1339
1342 def PrintRevInfo(self): 1340 def PrintRevInfo(self):
1343 """Output revision info mapping for the client and its dependencies. This 1341 """Output revision info mapping for the client and its dependencies. This
1344 allows the capture of a overall "revision" for the source tree that can 1342 allows the capture of a overall "revision" for the source tree that can
1345 be used to reproduce the same tree in the future. The actual output 1343 be used to reproduce the same tree in the future. The actual output
1346 contains enough information (source paths, svn server urls and revisions) 1344 contains enough information (source paths, svn server urls and revisions)
1347 that it can be used either to generate external svn commands (without 1345 that it can be used either to generate external svn commands (without
(...skipping 28 matching lines...) Expand all
1376 entries_deps_content = {} 1374 entries_deps_content = {}
1377 1375
1378 # Inner helper to generate base url and rev tuple (including honoring 1376 # Inner helper to generate base url and rev tuple (including honoring
1379 # |revision_overrides|) 1377 # |revision_overrides|)
1380 def GetURLAndRev(name, original_url): 1378 def GetURLAndRev(name, original_url):
1381 if original_url.find("@") < 0: 1379 if original_url.find("@") < 0:
1382 if revision_overrides.has_key(name): 1380 if revision_overrides.has_key(name):
1383 return (original_url, int(revision_overrides[name])) 1381 return (original_url, int(revision_overrides[name]))
1384 else: 1382 else:
1385 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1383 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1386 return (original_url, CaptureSVNHeadRevision(self._options, 1384 return (original_url, CaptureSVNHeadRevision(original_url))
1387 original_url))
1388 else: 1385 else:
1389 url_components = original_url.split("@") 1386 url_components = original_url.split("@")
1390 if revision_overrides.has_key(name): 1387 if revision_overrides.has_key(name):
1391 return (url_components[0], int(revision_overrides[name])) 1388 return (url_components[0], int(revision_overrides[name]))
1392 else: 1389 else:
1393 return (url_components[0], int(url_components[1])) 1390 return (url_components[0], int(url_components[1]))
1394 1391
1395 # Run on the base solutions first. 1392 # Run on the base solutions first.
1396 for solution in solutions: 1393 for solution in solutions:
1397 name = solution["name"] 1394 name = solution["name"]
1398 if name in entries: 1395 if name in entries:
1399 raise Error("solution %s specified more than once" % name) 1396 raise Error("solution %s specified more than once" % name)
1400 (url, rev) = GetURLAndRev(name, solution["url"]) 1397 (url, rev) = GetURLAndRev(name, solution["url"])
1401 entries[name] = "%s@%d" % (url, rev) 1398 entries[name] = "%s@%d" % (url, rev)
1402 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1399 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1403 entries_deps_content[name] = CaptureSVN( 1400 entries_deps_content[name] = CaptureSVN(
1404 self._options,
1405 ["cat", 1401 ["cat",
1406 "%s/%s@%d" % (url, 1402 "%s/%s@%d" % (url,
1407 self._options.deps_file, 1403 self._options.deps_file,
1408 rev)], 1404 rev)],
1409 os.getcwd()) 1405 os.getcwd())
1410 1406
1411 # Process the dependencies next (sort alphanumerically to ensure that 1407 # Process the dependencies next (sort alphanumerically to ensure that
1412 # containing directories get populated first and for readability) 1408 # containing directories get populated first and for readability)
1413 deps = self._ParseAllDeps(entries, entries_deps_content) 1409 deps = self._ParseAllDeps(entries, entries_deps_content)
1414 deps_to_process = deps.keys() 1410 deps_to_process = deps.keys()
1415 deps_to_process.sort() 1411 deps_to_process.sort()
1416 1412
1417 # First pass for direct dependencies. 1413 # First pass for direct dependencies.
1418 for d in deps_to_process: 1414 for d in deps_to_process:
1419 if type(deps[d]) == str: 1415 if type(deps[d]) == str:
1420 (url, rev) = GetURLAndRev(d, deps[d]) 1416 (url, rev) = GetURLAndRev(d, deps[d])
1421 entries[d] = "%s@%d" % (url, rev) 1417 entries[d] = "%s@%d" % (url, rev)
1422 1418
1423 # Second pass for inherited deps (via the From keyword) 1419 # Second pass for inherited deps (via the From keyword)
1424 for d in deps_to_process: 1420 for d in deps_to_process:
1425 if type(deps[d]) != str: 1421 if type(deps[d]) != str:
1426 deps_parent_url = entries[deps[d].module_name] 1422 deps_parent_url = entries[deps[d].module_name]
1427 if deps_parent_url.find("@") < 0: 1423 if deps_parent_url.find("@") < 0:
1428 raise Error("From %s missing revisioned url" % deps[d].module_name) 1424 raise Error("From %s missing revisioned url" % deps[d].module_name)
1429 deps_parent_url_components = deps_parent_url.split("@") 1425 deps_parent_url_components = deps_parent_url.split("@")
1430 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1426 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1431 deps_parent_content = CaptureSVN( 1427 deps_parent_content = CaptureSVN(
1432 self._options,
1433 ["cat", 1428 ["cat",
1434 "%s/%s@%s" % (deps_parent_url_components[0], 1429 "%s/%s@%s" % (deps_parent_url_components[0],
1435 self._options.deps_file, 1430 self._options.deps_file,
1436 deps_parent_url_components[1])], 1431 deps_parent_url_components[1])],
1437 os.getcwd()) 1432 os.getcwd())
1438 sub_deps = self._ParseSolutionDeps( 1433 sub_deps = self._ParseSolutionDeps(
1439 deps[d].module_name, 1434 deps[d].module_name,
1440 FileRead(os.path.join(self._root_dir, 1435 FileRead(os.path.join(self._root_dir,
1441 deps[d].module_name, 1436 deps[d].module_name,
1442 self._options.deps_file)), 1437 self._options.deps_file)),
1443 {}) 1438 {})
1444 (url, rev) = GetURLAndRev(d, sub_deps[d]) 1439 (url, rev) = GetURLAndRev(d, sub_deps[d])
1445 entries[d] = "%s@%d" % (url, rev) 1440 entries[d] = "%s@%d" % (url, rev)
1446 1441
1447 print ";".join(["%s,%s" % (x, entries[x]) for x in sorted(entries.keys())]) 1442 print(";".join(["%s,%s" % (x, entries[x]) for x in sorted(entries.keys())]))
1448 1443
1449 1444
1450 ## gclient commands. 1445 ## gclient commands.
1451 1446
1452 1447
1453 def DoCleanup(options, args): 1448 def DoCleanup(options, args):
1454 """Handle the cleanup subcommand. 1449 """Handle the cleanup subcommand.
1455 1450
1456 Raises: 1451 Raises:
1457 Error: if client isn't configured properly. 1452 Error: if client isn't configured properly.
1458 """ 1453 """
1459 client = options.gclient.LoadCurrentConfig(options) 1454 client = options.gclient.LoadCurrentConfig(options)
1460 if not client: 1455 if not client:
1461 raise Error("client not configured; see 'gclient config'") 1456 raise Error("client not configured; see 'gclient config'")
1462 if options.verbose: 1457 if options.verbose:
1463 # Print out the .gclient file. This is longer than if we just printed the 1458 # Print out the .gclient file. This is longer than if we just printed the
1464 # client dict, but more legible, and it might contain helpful comments. 1459 # client dict, but more legible, and it might contain helpful comments.
1465 print >>options.stdout, client.ConfigContent() 1460 print(client.ConfigContent())
1466 options.verbose = True 1461 options.verbose = True
1467 return client.RunOnDeps('cleanup', args) 1462 return client.RunOnDeps('cleanup', args)
1468 1463
1469 1464
1470 def DoConfig(options, args): 1465 def DoConfig(options, args):
1471 """Handle the config subcommand. 1466 """Handle the config subcommand.
1472 1467
1473 Args: 1468 Args:
1474 options: If options.spec set, a string providing contents of config file. 1469 options: If options.spec set, a string providing contents of config file.
1475 args: The command line args. If spec is not set, 1470 args: The command line args. If spec is not set,
(...skipping 22 matching lines...) Expand all
1498 client.SaveConfig() 1493 client.SaveConfig()
1499 1494
1500 1495
1501 def DoHelp(options, args): 1496 def DoHelp(options, args):
1502 """Handle the help subcommand giving help for another subcommand. 1497 """Handle the help subcommand giving help for another subcommand.
1503 1498
1504 Raises: 1499 Raises:
1505 Error: if the command is unknown. 1500 Error: if the command is unknown.
1506 """ 1501 """
1507 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT: 1502 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT:
1508 print >>options.stdout, COMMAND_USAGE_TEXT[args[0]] 1503 print(COMMAND_USAGE_TEXT[args[0]])
1509 else: 1504 else:
1510 raise Error("unknown subcommand '%s'; see 'gclient help'" % args[0]) 1505 raise Error("unknown subcommand '%s'; see 'gclient help'" % args[0])
1511 1506
1512 1507
1513 def DoStatus(options, args): 1508 def DoStatus(options, args):
1514 """Handle the status subcommand. 1509 """Handle the status subcommand.
1515 1510
1516 Raises: 1511 Raises:
1517 Error: if client isn't configured properly. 1512 Error: if client isn't configured properly.
1518 """ 1513 """
1519 client = options.gclient.LoadCurrentConfig(options) 1514 client = options.gclient.LoadCurrentConfig(options)
1520 if not client: 1515 if not client:
1521 raise Error("client not configured; see 'gclient config'") 1516 raise Error("client not configured; see 'gclient config'")
1522 if options.verbose: 1517 if options.verbose:
1523 # Print out the .gclient file. This is longer than if we just printed the 1518 # Print out the .gclient file. This is longer than if we just printed the
1524 # client dict, but more legible, and it might contain helpful comments. 1519 # client dict, but more legible, and it might contain helpful comments.
1525 print >>options.stdout, client.ConfigContent() 1520 print(client.ConfigContent())
1526 options.verbose = True 1521 options.verbose = True
1527 return client.RunOnDeps('status', args) 1522 return client.RunOnDeps('status', args)
1528 1523
1529 1524
1530 def DoUpdate(options, args): 1525 def DoUpdate(options, args):
1531 """Handle the update and sync subcommands. 1526 """Handle the update and sync subcommands.
1532 1527
1533 Raises: 1528 Raises:
1534 Error: if client isn't configured properly. 1529 Error: if client isn't configured properly.
1535 """ 1530 """
(...skipping 18 matching lines...) Expand all
1554 if not has_key: 1549 if not has_key:
1555 handle = urllib.urlopen(s['safesync_url']) 1550 handle = urllib.urlopen(s['safesync_url'])
1556 rev = handle.read().strip() 1551 rev = handle.read().strip()
1557 handle.close() 1552 handle.close()
1558 if len(rev): 1553 if len(rev):
1559 options.revisions.append(s['name']+'@'+rev) 1554 options.revisions.append(s['name']+'@'+rev)
1560 1555
1561 if options.verbose: 1556 if options.verbose:
1562 # Print out the .gclient file. This is longer than if we just printed the 1557 # Print out the .gclient file. This is longer than if we just printed the
1563 # client dict, but more legible, and it might contain helpful comments. 1558 # client dict, but more legible, and it might contain helpful comments.
1564 print >>options.stdout, client.ConfigContent() 1559 print(client.ConfigContent())
1565 return client.RunOnDeps('update', args) 1560 return client.RunOnDeps('update', args)
1566 1561
1567 1562
1568 def DoDiff(options, args): 1563 def DoDiff(options, args):
1569 """Handle the diff subcommand. 1564 """Handle the diff subcommand.
1570 1565
1571 Raises: 1566 Raises:
1572 Error: if client isn't configured properly. 1567 Error: if client isn't configured properly.
1573 """ 1568 """
1574 client = options.gclient.LoadCurrentConfig(options) 1569 client = options.gclient.LoadCurrentConfig(options)
1575 if not client: 1570 if not client:
1576 raise Error("client not configured; see 'gclient config'") 1571 raise Error("client not configured; see 'gclient config'")
1577 if options.verbose: 1572 if options.verbose:
1578 # Print out the .gclient file. This is longer than if we just printed the 1573 # Print out the .gclient file. This is longer than if we just printed the
1579 # client dict, but more legible, and it might contain helpful comments. 1574 # client dict, but more legible, and it might contain helpful comments.
1580 print >>options.stdout, client.ConfigContent() 1575 print(client.ConfigContent())
1581 options.verbose = True 1576 options.verbose = True
1582 return client.RunOnDeps('diff', args) 1577 return client.RunOnDeps('diff', args)
1583 1578
1584 1579
1585 def DoRevert(options, args): 1580 def DoRevert(options, args):
1586 """Handle the revert subcommand. 1581 """Handle the revert subcommand.
1587 1582
1588 Raises: 1583 Raises:
1589 Error: if client isn't configured properly. 1584 Error: if client isn't configured properly.
1590 """ 1585 """
1591 client = options.gclient.LoadCurrentConfig(options) 1586 client = options.gclient.LoadCurrentConfig(options)
1592 if not client: 1587 if not client:
1593 raise Error("client not configured; see 'gclient config'") 1588 raise Error("client not configured; see 'gclient config'")
1594 return client.RunOnDeps('revert', args) 1589 return client.RunOnDeps('revert', args)
1595 1590
1596 1591
1597 def DoRunHooks(options, args): 1592 def DoRunHooks(options, args):
1598 """Handle the runhooks subcommand. 1593 """Handle the runhooks subcommand.
1599 1594
1600 Raises: 1595 Raises:
1601 Error: if client isn't configured properly. 1596 Error: if client isn't configured properly.
1602 """ 1597 """
1603 client = options.gclient.LoadCurrentConfig(options) 1598 client = options.gclient.LoadCurrentConfig(options)
1604 if not client: 1599 if not client:
1605 raise Error("client not configured; see 'gclient config'") 1600 raise Error("client not configured; see 'gclient config'")
1606 if options.verbose: 1601 if options.verbose:
1607 # Print out the .gclient file. This is longer than if we just printed the 1602 # Print out the .gclient file. This is longer than if we just printed the
1608 # client dict, but more legible, and it might contain helpful comments. 1603 # client dict, but more legible, and it might contain helpful comments.
1609 print >>options.stdout, client.ConfigContent() 1604 print(client.ConfigContent())
1610 return client.RunOnDeps('runhooks', args) 1605 return client.RunOnDeps('runhooks', args)
1611 1606
1612 1607
1613 def DoRevInfo(options, args): 1608 def DoRevInfo(options, args):
1614 """Handle the revinfo subcommand. 1609 """Handle the revinfo subcommand.
1615 1610
1616 Raises: 1611 Raises:
1617 Error: if client isn't configured properly. 1612 Error: if client isn't configured properly.
1618 """ 1613 """
1619 client = options.gclient.LoadCurrentConfig(options) 1614 client = options.gclient.LoadCurrentConfig(options)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1698 1693
1699 if len(argv) < 3 and command == "help": 1694 if len(argv) < 3 and command == "help":
1700 option_parser.print_help() 1695 option_parser.print_help()
1701 return 0 1696 return 0
1702 1697
1703 # Files used for configuration and state saving. 1698 # Files used for configuration and state saving.
1704 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient") 1699 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient")
1705 options.entries_filename = ".gclient_entries" 1700 options.entries_filename = ".gclient_entries"
1706 options.deps_file = "DEPS" 1701 options.deps_file = "DEPS"
1707 1702
1708 # These are overridded when testing. They are not externally visible.
1709 options.stdout = sys.stdout
1710 options.path_exists = os.path.exists 1703 options.path_exists = os.path.exists
1711 options.gclient = GClient 1704 options.gclient = GClient
1712 options.scm_wrapper = SCMWrapper 1705 options.scm_wrapper = SCMWrapper
1713 options.platform = sys.platform 1706 options.platform = sys.platform
1714 return DispatchCommand(command, options, args) 1707 return DispatchCommand(command, options, args)
1715 1708
1716 1709
1717 if "__main__" == __name__: 1710 if "__main__" == __name__:
1718 try: 1711 try:
1719 result = Main(sys.argv) 1712 result = Main(sys.argv)
1720 except Error, e: 1713 except Error, e:
1721 print "Error: %s" % str(e) 1714 print >> sys.stderr, "Error: %s" % str(e)
1722 result = 1 1715 result = 1
1723 sys.exit(result) 1716 sys.exit(result)
1724 1717
1725 # vim: ts=2:sw=2:tw=80:et: 1718 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | tests/gclient_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698