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

Side by Side Diff: gclient.py

Issue 115244: Revert 15861 because of... (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.2" 67 __version__ = "0.3.1"
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, fail_status=None): 400 def SubprocessCall(command, in_directory, out, 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, fail_status) 408 SubprocessCallAndCapture(command, in_directory, out, fail_status)
409 409
410 410
411 def SubprocessCallAndCapture(command, in_directory, fail_status=None, 411 def SubprocessCallAndCapture(command, in_directory, out, 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("\n________ running \'%s\' in \'%s\'" 426 print >> out, ("\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
(...skipping 30 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(args, in_directory): 478 def RunSVN(options, 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) 491 SubprocessCall(c, in_directory, options.stdout)
492 492
493 493
494 def CaptureSVN(args, in_directory): 494 def CaptureSVN(options, 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, 511 return subprocess.Popen(c, cwd=in_directory, shell=(sys.platform == 'win32'),
512 cwd=in_directory,
513 shell=(sys.platform == 'win32'),
514 stdout=subprocess.PIPE).communicate()[0] 512 stdout=subprocess.PIPE).communicate()[0]
515 513
516 514
517 def RunSVNAndGetFileList(args, in_directory, file_list): 515 def RunSVNAndGetFileList(options, args, in_directory, file_list):
518 """Runs svn checkout, update, or status, output to stdout. 516 """Runs svn checkout, update, or status, output to stdout.
519 517
520 The first item in args must be either "checkout", "update", or "status". 518 The first item in args must be either "checkout", "update", or "status".
521 519
522 svn's stdout is parsed to collect a list of files checked out or updated. 520 svn's stdout is parsed to collect a list of files checked out or updated.
523 These files are appended to file_list. svn's stdout is also printed to 521 These files are appended to file_list. svn's stdout is also printed to
524 sys.stdout as in RunSVN. 522 sys.stdout as in RunSVN.
525 523
526 Args: 524 Args:
527 args: A sequence of command line parameters to be passed to svn. 525 args: A sequence of command line parameters to be passed to svn.
(...skipping 19 matching lines...) Expand all
547 # args[0] must be a supported command. This will blow up if it's something 545 # args[0] must be a supported command. This will blow up if it's something
548 # else, which is good. Note that the patterns are only effective when 546 # else, which is good. Note that the patterns are only effective when
549 # these commands are used in their ordinary forms, the patterns are invalid 547 # these commands are used in their ordinary forms, the patterns are invalid
550 # for "svn status --show-updates", for example. 548 # for "svn status --show-updates", for example.
551 pattern = { 549 pattern = {
552 'checkout': update_pattern, 550 'checkout': update_pattern,
553 'status': status_pattern, 551 'status': status_pattern,
554 'update': update_pattern, 552 'update': update_pattern,
555 }[args[0]] 553 }[args[0]]
556 554
557 SubprocessCallAndCapture(command, 555 SubprocessCallAndCapture(command, in_directory, options.stdout,
558 in_directory, 556 pattern=pattern, capture_list=file_list)
559 pattern=pattern,
560 capture_list=file_list)
561 557
562 558
563 def CaptureSVNInfo(relpath, in_directory=None): 559 def CaptureSVNInfo(options, relpath, in_directory):
564 """Returns a dictionary from the svn info output for the given file. 560 """Returns a dictionary from the svn info output for the given file.
565 561
566 Args: 562 Args:
567 relpath: The directory where the working copy resides relative to 563 relpath: The directory where the working copy resides relative to
568 the directory given by in_directory. 564 the directory given by in_directory.
569 in_directory: The directory where svn is to be run. 565 in_directory: The directory where svn is to be run.
570 """ 566 """
571 output = CaptureSVN(["info", "--xml", relpath], in_directory) 567 dom = ParseXML(CaptureSVN(options, ["info", "--xml", relpath], in_directory))
572 dom = ParseXML(output)
573 result = {} 568 result = {}
574 if dom: 569 if dom:
575 def C(item, f): 570 def C(item, f):
576 if item is not None: return f(item) 571 if item is not None: return f(item)
577 # /info/entry/ 572 # /info/entry/
578 # url 573 # url
579 # reposityory/(root|uuid) 574 # reposityory/(root|uuid)
580 # wc-info/(schedule|depth) 575 # wc-info/(schedule|depth)
581 # commit/(author|date) 576 # commit/(author|date)
582 # str() the results because they may be returned as Unicode, which 577 # str() the results because they may be returned as Unicode, which
583 # interferes with the higher layers matching up things in the deps 578 # interferes with the higher layers matching up things in the deps
584 # dictionary. 579 # dictionary.
585 # TODO(maruel): Fix at higher level instead (!) 580 # TODO(maruel): Fix at higher level instead (!)
586 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str) 581 result['Repository Root'] = C(GetNamedNodeText(dom, 'root'), str)
587 result['URL'] = C(GetNamedNodeText(dom, 'url'), str) 582 result['URL'] = C(GetNamedNodeText(dom, 'url'), str)
588 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str) 583 result['UUID'] = C(GetNamedNodeText(dom, 'uuid'), str)
589 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'), 584 result['Revision'] = C(GetNodeNamedAttributeText(dom, 'entry', 'revision'),
590 int) 585 int)
591 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'), 586 result['Node Kind'] = C(GetNodeNamedAttributeText(dom, 'entry', 'kind'),
592 str) 587 str)
593 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str) 588 result['Schedule'] = C(GetNamedNodeText(dom, 'schedule'), str)
594 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str) 589 result['Path'] = C(GetNodeNamedAttributeText(dom, 'entry', 'path'), str)
595 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str) 590 result['Copied From URL'] = C(GetNamedNodeText(dom, 'copy-from-url'), str)
596 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str) 591 result['Copied From Rev'] = C(GetNamedNodeText(dom, 'copy-from-rev'), str)
597 return result 592 return result
598 593
599 594
600 def CaptureSVNHeadRevision(url): 595 def CaptureSVNHeadRevision(options, url):
601 """Get the head revision of a SVN repository. 596 """Get the head revision of a SVN repository.
602 597
603 Returns: 598 Returns:
604 Int head revision 599 Int head revision
605 """ 600 """
606 info = CaptureSVN(["info", "--xml", url], os.getcwd()) 601 info = CaptureSVN(options, ["info", "--xml", url], os.getcwd())
607 dom = xml.dom.minidom.parseString(info) 602 dom = xml.dom.minidom.parseString(info)
608 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision')) 603 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision'))
609 604
610 605
611 class FileStatus: 606 class FileStatus:
612 def __init__(self, path, text_status, props, lock, history): 607 def __init__(self, path, text_status, props, lock, history):
613 self.path = path 608 self.path = path
614 self.text_status = text_status 609 self.text_status = text_status
615 self.props = props 610 self.props = props
616 self.lock = lock 611 self.lock = lock
617 self.history = history 612 self.history = history
618 613
619 def __str__(self): 614 def __str__(self):
620 # Emulate svn status 1.5 output. 615 # Emulate svn status 1.5 output.
621 return (self.text_status + self.props + self.lock + self.history + ' ' + 616 return (self.text_status + self.props + self.lock + self.history + ' ' +
622 self.path) 617 self.path)
623 618
624 619
625 def CaptureSVNStatus(path): 620 def CaptureSVNStatus(options, path):
626 """Runs 'svn status' on an existing path. 621 """Runs 'svn status' on an existing path.
627 622
628 Args: 623 Args:
629 path: The directory to run svn status. 624 path: The directory to run svn status.
630 625
631 Returns: 626 Returns:
632 An array of FileStatus corresponding to the emulated output of 'svn status' 627 An array of FileStatus corresponding to the emulated output of 'svn status'
633 version 1.5.""" 628 version 1.5."""
634 dom = ParseXML(CaptureSVN(["status", "--xml"], path)) 629 dom = ParseXML(CaptureSVN(options, ["status", "--xml"], path))
635 results = [] 630 results = []
636 if dom: 631 if dom:
637 # /status/target/entry/(wc-status|commit|author|date) 632 # /status/target/entry/(wc-status|commit|author|date)
638 for target in dom.getElementsByTagName('target'): 633 for target in dom.getElementsByTagName('target'):
639 base_path = target.getAttribute('path') 634 base_path = target.getAttribute('path')
640 for entry in target.getElementsByTagName('entry'): 635 for entry in target.getElementsByTagName('entry'):
641 file = entry.getAttribute('path') 636 file = entry.getAttribute('path')
642 wc_status = entry.getElementsByTagName('wc-status') 637 wc_status = entry.getElementsByTagName('wc-status')
643 assert len(wc_status) == 1 638 assert len(wc_status) == 1
644 # Emulate svn 1.5 status ouput... 639 # Emulate svn 1.5 status ouput...
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 721
727 if not command in commands: 722 if not command in commands:
728 raise Error('Unknown command %s' % command) 723 raise Error('Unknown command %s' % command)
729 724
730 return commands[command](options, args, file_list) 725 return commands[command](options, args, file_list)
731 726
732 def cleanup(self, options, args, file_list): 727 def cleanup(self, options, args, file_list):
733 """Cleanup working copy.""" 728 """Cleanup working copy."""
734 command = ['cleanup'] 729 command = ['cleanup']
735 command.extend(args) 730 command.extend(args)
736 RunSVN(command, os.path.join(self._root_dir, self.relpath)) 731 RunSVN(options, command, os.path.join(self._root_dir, self.relpath))
737 732
738 def diff(self, options, args, file_list): 733 def diff(self, options, args, file_list):
739 # NOTE: This function does not currently modify file_list. 734 # NOTE: This function does not currently modify file_list.
740 command = ['diff'] 735 command = ['diff']
741 command.extend(args) 736 command.extend(args)
742 RunSVN(command, os.path.join(self._root_dir, self.relpath)) 737 RunSVN(options, command, os.path.join(self._root_dir, self.relpath))
743 738
744 def update(self, options, args, file_list): 739 def update(self, options, args, file_list):
745 """Runs SCM to update or transparently checkout the working copy. 740 """Runs SCM to update or transparently checkout the working copy.
746 741
747 All updated files will be appended to file_list. 742 All updated files will be appended to file_list.
748 743
749 Raises: 744 Raises:
750 Error: if can't get URL for relative path. 745 Error: if can't get URL for relative path.
751 """ 746 """
752 # Only update if git is not controlling the directory. 747 # Only update if git is not controlling the directory.
753 git_path = os.path.join(self._root_dir, self.relpath, '.git') 748 git_path = os.path.join(self._root_dir, self.relpath, '.git')
754 if options.path_exists(git_path): 749 if options.path_exists(git_path):
755 print("________ found .git directory; skipping %s" % self.relpath) 750 print >> options.stdout, (
751 "________ found .git directory; skipping %s" % self.relpath)
756 return 752 return
757 753
758 if args: 754 if args:
759 raise Error("Unsupported argument(s): %s" % ",".join(args)) 755 raise Error("Unsupported argument(s): %s" % ",".join(args))
760 756
761 url = self.url 757 url = self.url
762 components = url.split("@") 758 components = url.split("@")
763 revision = None 759 revision = None
764 forced_revision = False 760 forced_revision = False
765 if options.revision: 761 if options.revision:
766 # Override the revision number. 762 # Override the revision number.
767 url = '%s@%s' % (components[0], str(options.revision)) 763 url = '%s@%s' % (components[0], str(options.revision))
768 revision = int(options.revision) 764 revision = int(options.revision)
769 forced_revision = True 765 forced_revision = True
770 elif len(components) == 2: 766 elif len(components) == 2:
771 revision = int(components[1]) 767 revision = int(components[1])
772 forced_revision = True 768 forced_revision = True
773 769
774 rev_str = "" 770 rev_str = ""
775 if revision: 771 if revision:
776 rev_str = ' at %d' % revision 772 rev_str = ' at %d' % revision
777 773
778 if not options.path_exists(os.path.join(self._root_dir, self.relpath)): 774 if not options.path_exists(os.path.join(self._root_dir, self.relpath)):
779 # We need to checkout. 775 # We need to checkout.
780 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)] 776 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)]
781 if revision: 777 if revision:
782 command.extend(['--revision', str(revision)]) 778 command.extend(['--revision', str(revision)])
783 RunSVNAndGetFileList(command, self._root_dir, file_list) 779 RunSVNAndGetFileList(options, command, self._root_dir, file_list)
784 return 780 return
785 781
786 # Get the existing scm url and the revision number of the current checkout. 782 # Get the existing scm url and the revision number of the current checkout.
787 from_info = CaptureSVNInfo(os.path.join(self._root_dir, self.relpath, '.'), 783 from_info = CaptureSVNInfo(options,
784 os.path.join(self._root_dir, self.relpath, '.'),
788 '.') 785 '.')
789 786
790 if options.manually_grab_svn_rev: 787 if options.manually_grab_svn_rev:
791 # Retrieve the current HEAD version because svn is slow at null updates. 788 # Retrieve the current HEAD version because svn is slow at null updates.
792 if not revision: 789 if not revision:
793 from_info_live = CaptureSVNInfo(from_info['URL'], '.') 790 from_info_live = CaptureSVNInfo(options, from_info['URL'], '.')
794 revision = int(from_info_live['Revision']) 791 revision = int(from_info_live['Revision'])
795 rev_str = ' at %d' % revision 792 rev_str = ' at %d' % revision
796 793
797 if from_info['URL'] != components[0]: 794 if from_info['URL'] != components[0]:
798 to_info = CaptureSVNInfo(url, '.') 795 to_info = CaptureSVNInfo(options, url, '.')
799 if from_info['Repository Root'] != to_info['Repository Root']: 796 if from_info['Repository Root'] != to_info['Repository Root']:
800 # We have different roots, so check if we can switch --relocate. 797 # We have different roots, so check if we can switch --relocate.
801 # Subversion only permits this if the repository UUIDs match. 798 # Subversion only permits this if the repository UUIDs match.
802 if from_info['UUID'] != to_info['UUID']: 799 if from_info['UUID'] != to_info['UUID']:
803 raise Error("Can't switch the checkout to %s; UUID don't match. That " 800 raise Error("Can't switch the checkout to %s; UUID don't match. That "
804 "simply means in theory, gclient should verify you don't " 801 "simply means in theory, gclient should verify you don't "
805 "have a local change, remove the old checkout and do a " 802 "have a local change, remove the old checkout and do a "
806 "fresh new checkout of the new repo. Contributions are " 803 "fresh new checkout of the new repo. Contributions are "
807 "welcome." % url) 804 "welcome." % url)
808 805
809 # Perform the switch --relocate, then rewrite the from_url 806 # Perform the switch --relocate, then rewrite the from_url
810 # to reflect where we "are now." (This is the same way that 807 # to reflect where we "are now." (This is the same way that
811 # Subversion itself handles the metadata when switch --relocate 808 # Subversion itself handles the metadata when switch --relocate
812 # is used.) This makes the checks below for whether we 809 # is used.) This makes the checks below for whether we
813 # can update to a revision or have to switch to a different 810 # can update to a revision or have to switch to a different
814 # branch work as expected. 811 # branch work as expected.
815 # TODO(maruel): TEST ME ! 812 # TODO(maruel): TEST ME !
816 command = ["switch", "--relocate", 813 command = ["switch", "--relocate",
817 from_info['Repository Root'], 814 from_info['Repository Root'],
818 to_info['Repository Root'], 815 to_info['Repository Root'],
819 self.relpath] 816 self.relpath]
820 RunSVN(command, self._root_dir) 817 RunSVN(options, command, self._root_dir)
821 from_info['URL'] = from_info['URL'].replace( 818 from_info['URL'] = from_info['URL'].replace(
822 from_info['Repository Root'], 819 from_info['Repository Root'],
823 to_info['Repository Root']) 820 to_info['Repository Root'])
824 821
825 # If the provided url has a revision number that matches the revision 822 # If the provided url has a revision number that matches the revision
826 # number of the existing directory, then we don't need to bother updating. 823 # number of the existing directory, then we don't need to bother updating.
827 if not options.force and from_info['Revision'] == revision: 824 if not options.force and from_info['Revision'] == revision:
828 if options.verbose or not forced_revision: 825 if options.verbose or not forced_revision:
829 print("\n_____ %s%s" % (self.relpath, rev_str)) 826 print >>options.stdout, ("\n_____ %s%s" % (
827 self.relpath, rev_str))
830 return 828 return
831 829
832 command = ["update", os.path.join(self._root_dir, self.relpath)] 830 command = ["update", os.path.join(self._root_dir, self.relpath)]
833 if revision: 831 if revision:
834 command.extend(['--revision', str(revision)]) 832 command.extend(['--revision', str(revision)])
835 RunSVNAndGetFileList(command, self._root_dir, file_list) 833 RunSVNAndGetFileList(options, command, self._root_dir, file_list)
836 834
837 def revert(self, options, args, file_list): 835 def revert(self, options, args, file_list):
838 """Reverts local modifications. Subversion specific. 836 """Reverts local modifications. Subversion specific.
839 837
840 All reverted files will be appended to file_list, even if Subversion 838 All reverted files will be appended to file_list, even if Subversion
841 doesn't know about them. 839 doesn't know about them.
842 """ 840 """
843 path = os.path.join(self._root_dir, self.relpath) 841 path = os.path.join(self._root_dir, self.relpath)
844 if not os.path.isdir(path): 842 if not os.path.isdir(path):
845 # svn revert won't work if the directory doesn't exist. It needs to 843 # svn revert won't work if the directory doesn't exist. It needs to
846 # checkout instead. 844 # checkout instead.
847 print("\n_____ %s is missing, synching instead" % self.relpath) 845 print >>options.stdout, ("\n_____ %s is missing, synching instead" %
846 self.relpath)
848 # Don't reuse the args. 847 # Don't reuse the args.
849 return self.update(options, [], file_list) 848 return self.update(options, [], file_list)
850 849
851 files = CaptureSVNStatus(path) 850 files = CaptureSVNStatus(options, path)
852 # Batch the command. 851 # Batch the command.
853 files_to_revert = [] 852 files_to_revert = []
854 for file in files: 853 for file in files:
855 file_path = os.path.join(path, file.path) 854 file_path = os.path.join(path, file.path)
856 print(file_path) 855 print >>options.stdout, file_path
857 # Unversioned file or unexpected unversioned file. 856 # Unversioned file or unexpected unversioned file.
858 if file.text_status in ('?', '~'): 857 if file.text_status in ('?', '~'):
859 # Remove extraneous file. Also remove unexpected unversioned 858 # Remove extraneous file. Also remove unexpected unversioned
860 # directories. svn won't touch them but we want to delete these. 859 # directories. svn won't touch them but we want to delete these.
861 file_list.append(file_path) 860 file_list.append(file_path)
862 try: 861 try:
863 os.remove(file_path) 862 os.remove(file_path)
864 except EnvironmentError: 863 except EnvironmentError:
865 RemoveDirectory(file_path) 864 RemoveDirectory(file_path)
866 865
867 if file.text_status != '?': 866 if file.text_status != '?':
868 # For any other status, svn revert will work. 867 # For any other status, svn revert will work.
869 file_list.append(file_path) 868 file_list.append(file_path)
870 files_to_revert.append(file.path) 869 files_to_revert.append(file.path)
871 870
872 # Revert them all at once. 871 # Revert them all at once.
873 if files_to_revert: 872 if files_to_revert:
874 accumulated_paths = [] 873 accumulated_paths = []
875 accumulated_length = 0 874 accumulated_length = 0
876 command = ['revert'] 875 command = ['revert']
877 for p in files_to_revert: 876 for p in files_to_revert:
878 # Some shell have issues with command lines too long. 877 # Some shell have issues with command lines too long.
879 if accumulated_length and accumulated_length + len(p) > 3072: 878 if accumulated_length and accumulated_length + len(p) > 3072:
880 RunSVN(command + accumulated_paths, 879 RunSVN(options, command + accumulated_paths,
881 os.path.join(self._root_dir, self.relpath)) 880 os.path.join(self._root_dir, self.relpath))
882 accumulated_paths = [] 881 accumulated_paths = []
883 accumulated_length = 0 882 accumulated_length = 0
884 else: 883 else:
885 accumulated_paths.append(p) 884 accumulated_paths.append(p)
886 accumulated_length += len(p) 885 accumulated_length += len(p)
887 if accumulated_paths: 886 if accumulated_paths:
888 RunSVN(command + accumulated_paths, 887 RunSVN(options, command + accumulated_paths,
889 os.path.join(self._root_dir, self.relpath)) 888 os.path.join(self._root_dir, self.relpath))
890 889
891 def status(self, options, args, file_list): 890 def status(self, options, args, file_list):
892 """Display status information.""" 891 """Display status information."""
893 path = os.path.join(self._root_dir, self.relpath) 892 path = os.path.join(self._root_dir, self.relpath)
894 command = ['status'] 893 command = ['status']
895 command.extend(args) 894 command.extend(args)
896 if not os.path.isdir(path): 895 if not os.path.isdir(path):
897 # svn status won't work if the directory doesn't exist. 896 # svn status won't work if the directory doesn't exist.
898 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " 897 print >> options.stdout, (
899 "does not exist." 898 "\n________ couldn't run \'%s\' in \'%s\':\nThe directory "
900 % (' '.join(command), path)) 899 "does not exist."
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(command, path, file_list) 903 RunSVNAndGetFileList(options, 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, fail_status=2) 1184 SubprocessCall(command, self._root_dir, self._options.stdout,
1185 fail_status=2)
1185 1186
1186 def _RunHooks(self, command, file_list, is_using_git): 1187 def _RunHooks(self, command, file_list, is_using_git):
1187 """Evaluates all hooks, running actions as needed. 1188 """Evaluates all hooks, running actions as needed.
1188 """ 1189 """
1189 # Hooks only run for these command types. 1190 # Hooks only run for these command types.
1190 if not command in ('update', 'revert', 'runhooks'): 1191 if not command in ('update', 'revert', 'runhooks'):
1191 return 1192 return
1192 1193
1193 # Get any hooks from the .gclient file. 1194 # Get any hooks from the .gclient file.
1194 hooks = self.GetVar("hooks", []) 1195 hooks = self.GetVar("hooks", [])
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1317 self._RunHooks(command, file_list, is_using_git) 1318 self._RunHooks(command, file_list, is_using_git)
1318 1319
1319 if command == 'update': 1320 if command == 'update':
1320 # notify the user if there is an orphaned entry in their working copy. 1321 # notify the user if there is an orphaned entry in their working copy.
1321 # TODO(darin): we should delete this directory manually if it doesn't 1322 # TODO(darin): we should delete this directory manually if it doesn't
1322 # have any changes in it. 1323 # have any changes in it.
1323 prev_entries = self._ReadEntries() 1324 prev_entries = self._ReadEntries()
1324 for entry in prev_entries: 1325 for entry in prev_entries:
1325 e_dir = os.path.join(self._root_dir, entry) 1326 e_dir = os.path.join(self._root_dir, entry)
1326 if entry not in entries and self._options.path_exists(e_dir): 1327 if entry not in entries and self._options.path_exists(e_dir):
1327 if CaptureSVNStatus(e_dir): 1328 if CaptureSVNStatus(self._options, e_dir):
1328 # There are modified files in this entry 1329 # There are modified files in this entry
1329 entries[entry] = None # Keep warning until removed. 1330 entries[entry] = None # Keep warning until removed.
1330 print("\nWARNING: \"%s\" is no longer part of this client. " 1331 print >> self._options.stdout, (
1331 "It is recommended that you manually remove it.\n") % entry 1332 "\nWARNING: \"%s\" is no longer part of this client. "
1333 "It is recommended that you manually remove it.\n") % entry
1332 else: 1334 else:
1333 # Delete the entry 1335 # Delete the entry
1334 print("\n________ deleting \'%s\' " + 1336 print >> self._options.stdout, ("\n________ deleting \'%s\' " +
1335 "in \'%s\'") % (entry, self._root_dir) 1337 "in \'%s\'") % (entry, self._root_dir)
1336 RemoveDirectory(e_dir) 1338 RemoveDirectory(e_dir)
1337 # record the current list of entries for next time 1339 # record the current list of entries for next time
1338 self._SaveEntries(entries) 1340 self._SaveEntries(entries)
1339 1341
1340 def PrintRevInfo(self): 1342 def PrintRevInfo(self):
1341 """Output revision info mapping for the client and its dependencies. This 1343 """Output revision info mapping for the client and its dependencies. This
1342 allows the capture of a overall "revision" for the source tree that can 1344 allows the capture of a overall "revision" for the source tree that can
1343 be used to reproduce the same tree in the future. The actual output 1345 be used to reproduce the same tree in the future. The actual output
1344 contains enough information (source paths, svn server urls and revisions) 1346 contains enough information (source paths, svn server urls and revisions)
1345 that it can be used either to generate external svn commands (without 1347 that it can be used either to generate external svn commands (without
(...skipping 28 matching lines...) Expand all
1374 entries_deps_content = {} 1376 entries_deps_content = {}
1375 1377
1376 # Inner helper to generate base url and rev tuple (including honoring 1378 # Inner helper to generate base url and rev tuple (including honoring
1377 # |revision_overrides|) 1379 # |revision_overrides|)
1378 def GetURLAndRev(name, original_url): 1380 def GetURLAndRev(name, original_url):
1379 if original_url.find("@") < 0: 1381 if original_url.find("@") < 0:
1380 if revision_overrides.has_key(name): 1382 if revision_overrides.has_key(name):
1381 return (original_url, int(revision_overrides[name])) 1383 return (original_url, int(revision_overrides[name]))
1382 else: 1384 else:
1383 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1385 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1384 return (original_url, CaptureSVNHeadRevision(original_url)) 1386 return (original_url, CaptureSVNHeadRevision(self._options,
1387 original_url))
1385 else: 1388 else:
1386 url_components = original_url.split("@") 1389 url_components = original_url.split("@")
1387 if revision_overrides.has_key(name): 1390 if revision_overrides.has_key(name):
1388 return (url_components[0], int(revision_overrides[name])) 1391 return (url_components[0], int(revision_overrides[name]))
1389 else: 1392 else:
1390 return (url_components[0], int(url_components[1])) 1393 return (url_components[0], int(url_components[1]))
1391 1394
1392 # Run on the base solutions first. 1395 # Run on the base solutions first.
1393 for solution in solutions: 1396 for solution in solutions:
1394 name = solution["name"] 1397 name = solution["name"]
1395 if name in entries: 1398 if name in entries:
1396 raise Error("solution %s specified more than once" % name) 1399 raise Error("solution %s specified more than once" % name)
1397 (url, rev) = GetURLAndRev(name, solution["url"]) 1400 (url, rev) = GetURLAndRev(name, solution["url"])
1398 entries[name] = "%s@%d" % (url, rev) 1401 entries[name] = "%s@%d" % (url, rev)
1399 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1402 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1400 entries_deps_content[name] = CaptureSVN( 1403 entries_deps_content[name] = CaptureSVN(
1404 self._options,
1401 ["cat", 1405 ["cat",
1402 "%s/%s@%d" % (url, 1406 "%s/%s@%d" % (url,
1403 self._options.deps_file, 1407 self._options.deps_file,
1404 rev)], 1408 rev)],
1405 os.getcwd()) 1409 os.getcwd())
1406 1410
1407 # Process the dependencies next (sort alphanumerically to ensure that 1411 # Process the dependencies next (sort alphanumerically to ensure that
1408 # containing directories get populated first and for readability) 1412 # containing directories get populated first and for readability)
1409 deps = self._ParseAllDeps(entries, entries_deps_content) 1413 deps = self._ParseAllDeps(entries, entries_deps_content)
1410 deps_to_process = deps.keys() 1414 deps_to_process = deps.keys()
1411 deps_to_process.sort() 1415 deps_to_process.sort()
1412 1416
1413 # First pass for direct dependencies. 1417 # First pass for direct dependencies.
1414 for d in deps_to_process: 1418 for d in deps_to_process:
1415 if type(deps[d]) == str: 1419 if type(deps[d]) == str:
1416 (url, rev) = GetURLAndRev(d, deps[d]) 1420 (url, rev) = GetURLAndRev(d, deps[d])
1417 entries[d] = "%s@%d" % (url, rev) 1421 entries[d] = "%s@%d" % (url, rev)
1418 1422
1419 # Second pass for inherited deps (via the From keyword) 1423 # Second pass for inherited deps (via the From keyword)
1420 for d in deps_to_process: 1424 for d in deps_to_process:
1421 if type(deps[d]) != str: 1425 if type(deps[d]) != str:
1422 deps_parent_url = entries[deps[d].module_name] 1426 deps_parent_url = entries[deps[d].module_name]
1423 if deps_parent_url.find("@") < 0: 1427 if deps_parent_url.find("@") < 0:
1424 raise Error("From %s missing revisioned url" % deps[d].module_name) 1428 raise Error("From %s missing revisioned url" % deps[d].module_name)
1425 deps_parent_url_components = deps_parent_url.split("@") 1429 deps_parent_url_components = deps_parent_url.split("@")
1426 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset) 1430 # TODO(aharper): SVN/SCMWrapper cleanup (non-local commandset)
1427 deps_parent_content = CaptureSVN( 1431 deps_parent_content = CaptureSVN(
1432 self._options,
1428 ["cat", 1433 ["cat",
1429 "%s/%s@%s" % (deps_parent_url_components[0], 1434 "%s/%s@%s" % (deps_parent_url_components[0],
1430 self._options.deps_file, 1435 self._options.deps_file,
1431 deps_parent_url_components[1])], 1436 deps_parent_url_components[1])],
1432 os.getcwd()) 1437 os.getcwd())
1433 sub_deps = self._ParseSolutionDeps( 1438 sub_deps = self._ParseSolutionDeps(
1434 deps[d].module_name, 1439 deps[d].module_name,
1435 FileRead(os.path.join(self._root_dir, 1440 FileRead(os.path.join(self._root_dir,
1436 deps[d].module_name, 1441 deps[d].module_name,
1437 self._options.deps_file)), 1442 self._options.deps_file)),
1438 {}) 1443 {})
1439 (url, rev) = GetURLAndRev(d, sub_deps[d]) 1444 (url, rev) = GetURLAndRev(d, sub_deps[d])
1440 entries[d] = "%s@%d" % (url, rev) 1445 entries[d] = "%s@%d" % (url, rev)
1441 1446
1442 print(";".join(["%s,%s" % (x, entries[x]) for x in sorted(entries.keys())])) 1447 print ";".join(["%s,%s" % (x, entries[x]) for x in sorted(entries.keys())])
1443 1448
1444 1449
1445 ## gclient commands. 1450 ## gclient commands.
1446 1451
1447 1452
1448 def DoCleanup(options, args): 1453 def DoCleanup(options, args):
1449 """Handle the cleanup subcommand. 1454 """Handle the cleanup subcommand.
1450 1455
1451 Raises: 1456 Raises:
1452 Error: if client isn't configured properly. 1457 Error: if client isn't configured properly.
1453 """ 1458 """
1454 client = options.gclient.LoadCurrentConfig(options) 1459 client = options.gclient.LoadCurrentConfig(options)
1455 if not client: 1460 if not client:
1456 raise Error("client not configured; see 'gclient config'") 1461 raise Error("client not configured; see 'gclient config'")
1457 if options.verbose: 1462 if options.verbose:
1458 # Print out the .gclient file. This is longer than if we just printed the 1463 # Print out the .gclient file. This is longer than if we just printed the
1459 # client dict, but more legible, and it might contain helpful comments. 1464 # client dict, but more legible, and it might contain helpful comments.
1460 print(client.ConfigContent()) 1465 print >>options.stdout, client.ConfigContent()
1461 options.verbose = True 1466 options.verbose = True
1462 return client.RunOnDeps('cleanup', args) 1467 return client.RunOnDeps('cleanup', args)
1463 1468
1464 1469
1465 def DoConfig(options, args): 1470 def DoConfig(options, args):
1466 """Handle the config subcommand. 1471 """Handle the config subcommand.
1467 1472
1468 Args: 1473 Args:
1469 options: If options.spec set, a string providing contents of config file. 1474 options: If options.spec set, a string providing contents of config file.
1470 args: The command line args. If spec is not set, 1475 args: The command line args. If spec is not set,
(...skipping 22 matching lines...) Expand all
1493 client.SaveConfig() 1498 client.SaveConfig()
1494 1499
1495 1500
1496 def DoHelp(options, args): 1501 def DoHelp(options, args):
1497 """Handle the help subcommand giving help for another subcommand. 1502 """Handle the help subcommand giving help for another subcommand.
1498 1503
1499 Raises: 1504 Raises:
1500 Error: if the command is unknown. 1505 Error: if the command is unknown.
1501 """ 1506 """
1502 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT: 1507 if len(args) == 1 and args[0] in COMMAND_USAGE_TEXT:
1503 print(COMMAND_USAGE_TEXT[args[0]]) 1508 print >>options.stdout, COMMAND_USAGE_TEXT[args[0]]
1504 else: 1509 else:
1505 raise Error("unknown subcommand '%s'; see 'gclient help'" % args[0]) 1510 raise Error("unknown subcommand '%s'; see 'gclient help'" % args[0])
1506 1511
1507 1512
1508 def DoStatus(options, args): 1513 def DoStatus(options, args):
1509 """Handle the status subcommand. 1514 """Handle the status subcommand.
1510 1515
1511 Raises: 1516 Raises:
1512 Error: if client isn't configured properly. 1517 Error: if client isn't configured properly.
1513 """ 1518 """
1514 client = options.gclient.LoadCurrentConfig(options) 1519 client = options.gclient.LoadCurrentConfig(options)
1515 if not client: 1520 if not client:
1516 raise Error("client not configured; see 'gclient config'") 1521 raise Error("client not configured; see 'gclient config'")
1517 if options.verbose: 1522 if options.verbose:
1518 # Print out the .gclient file. This is longer than if we just printed the 1523 # Print out the .gclient file. This is longer than if we just printed the
1519 # client dict, but more legible, and it might contain helpful comments. 1524 # client dict, but more legible, and it might contain helpful comments.
1520 print(client.ConfigContent()) 1525 print >>options.stdout, client.ConfigContent()
1521 options.verbose = True 1526 options.verbose = True
1522 return client.RunOnDeps('status', args) 1527 return client.RunOnDeps('status', args)
1523 1528
1524 1529
1525 def DoUpdate(options, args): 1530 def DoUpdate(options, args):
1526 """Handle the update and sync subcommands. 1531 """Handle the update and sync subcommands.
1527 1532
1528 Raises: 1533 Raises:
1529 Error: if client isn't configured properly. 1534 Error: if client isn't configured properly.
1530 """ 1535 """
(...skipping 18 matching lines...) Expand all
1549 if not has_key: 1554 if not has_key:
1550 handle = urllib.urlopen(s['safesync_url']) 1555 handle = urllib.urlopen(s['safesync_url'])
1551 rev = handle.read().strip() 1556 rev = handle.read().strip()
1552 handle.close() 1557 handle.close()
1553 if len(rev): 1558 if len(rev):
1554 options.revisions.append(s['name']+'@'+rev) 1559 options.revisions.append(s['name']+'@'+rev)
1555 1560
1556 if options.verbose: 1561 if options.verbose:
1557 # Print out the .gclient file. This is longer than if we just printed the 1562 # Print out the .gclient file. This is longer than if we just printed the
1558 # client dict, but more legible, and it might contain helpful comments. 1563 # client dict, but more legible, and it might contain helpful comments.
1559 print(client.ConfigContent()) 1564 print >>options.stdout, client.ConfigContent()
1560 return client.RunOnDeps('update', args) 1565 return client.RunOnDeps('update', args)
1561 1566
1562 1567
1563 def DoDiff(options, args): 1568 def DoDiff(options, args):
1564 """Handle the diff subcommand. 1569 """Handle the diff subcommand.
1565 1570
1566 Raises: 1571 Raises:
1567 Error: if client isn't configured properly. 1572 Error: if client isn't configured properly.
1568 """ 1573 """
1569 client = options.gclient.LoadCurrentConfig(options) 1574 client = options.gclient.LoadCurrentConfig(options)
1570 if not client: 1575 if not client:
1571 raise Error("client not configured; see 'gclient config'") 1576 raise Error("client not configured; see 'gclient config'")
1572 if options.verbose: 1577 if options.verbose:
1573 # Print out the .gclient file. This is longer than if we just printed the 1578 # Print out the .gclient file. This is longer than if we just printed the
1574 # client dict, but more legible, and it might contain helpful comments. 1579 # client dict, but more legible, and it might contain helpful comments.
1575 print(client.ConfigContent()) 1580 print >>options.stdout, client.ConfigContent()
1576 options.verbose = True 1581 options.verbose = True
1577 return client.RunOnDeps('diff', args) 1582 return client.RunOnDeps('diff', args)
1578 1583
1579 1584
1580 def DoRevert(options, args): 1585 def DoRevert(options, args):
1581 """Handle the revert subcommand. 1586 """Handle the revert subcommand.
1582 1587
1583 Raises: 1588 Raises:
1584 Error: if client isn't configured properly. 1589 Error: if client isn't configured properly.
1585 """ 1590 """
1586 client = options.gclient.LoadCurrentConfig(options) 1591 client = options.gclient.LoadCurrentConfig(options)
1587 if not client: 1592 if not client:
1588 raise Error("client not configured; see 'gclient config'") 1593 raise Error("client not configured; see 'gclient config'")
1589 return client.RunOnDeps('revert', args) 1594 return client.RunOnDeps('revert', args)
1590 1595
1591 1596
1592 def DoRunHooks(options, args): 1597 def DoRunHooks(options, args):
1593 """Handle the runhooks subcommand. 1598 """Handle the runhooks subcommand.
1594 1599
1595 Raises: 1600 Raises:
1596 Error: if client isn't configured properly. 1601 Error: if client isn't configured properly.
1597 """ 1602 """
1598 client = options.gclient.LoadCurrentConfig(options) 1603 client = options.gclient.LoadCurrentConfig(options)
1599 if not client: 1604 if not client:
1600 raise Error("client not configured; see 'gclient config'") 1605 raise Error("client not configured; see 'gclient config'")
1601 if options.verbose: 1606 if options.verbose:
1602 # Print out the .gclient file. This is longer than if we just printed the 1607 # Print out the .gclient file. This is longer than if we just printed the
1603 # client dict, but more legible, and it might contain helpful comments. 1608 # client dict, but more legible, and it might contain helpful comments.
1604 print(client.ConfigContent()) 1609 print >>options.stdout, client.ConfigContent()
1605 return client.RunOnDeps('runhooks', args) 1610 return client.RunOnDeps('runhooks', args)
1606 1611
1607 1612
1608 def DoRevInfo(options, args): 1613 def DoRevInfo(options, args):
1609 """Handle the revinfo subcommand. 1614 """Handle the revinfo subcommand.
1610 1615
1611 Raises: 1616 Raises:
1612 Error: if client isn't configured properly. 1617 Error: if client isn't configured properly.
1613 """ 1618 """
1614 client = options.gclient.LoadCurrentConfig(options) 1619 client = options.gclient.LoadCurrentConfig(options)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1693 1698
1694 if len(argv) < 3 and command == "help": 1699 if len(argv) < 3 and command == "help":
1695 option_parser.print_help() 1700 option_parser.print_help()
1696 return 0 1701 return 0
1697 1702
1698 # Files used for configuration and state saving. 1703 # Files used for configuration and state saving.
1699 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient") 1704 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient")
1700 options.entries_filename = ".gclient_entries" 1705 options.entries_filename = ".gclient_entries"
1701 options.deps_file = "DEPS" 1706 options.deps_file = "DEPS"
1702 1707
1708 # These are overridded when testing. They are not externally visible.
1709 options.stdout = sys.stdout
1703 options.path_exists = os.path.exists 1710 options.path_exists = os.path.exists
1704 options.gclient = GClient 1711 options.gclient = GClient
1705 options.scm_wrapper = SCMWrapper 1712 options.scm_wrapper = SCMWrapper
1706 options.platform = sys.platform 1713 options.platform = sys.platform
1707 return DispatchCommand(command, options, args) 1714 return DispatchCommand(command, options, args)
1708 1715
1709 1716
1710 if "__main__" == __name__: 1717 if "__main__" == __name__:
1711 try: 1718 try:
1712 result = Main(sys.argv) 1719 result = Main(sys.argv)
1713 except Error, e: 1720 except Error, e:
1714 print >> sys.stderr, "Error: %s" % str(e) 1721 print "Error: %s" % str(e)
1715 result = 1 1722 result = 1
1716 sys.exit(result) 1723 sys.exit(result)
1717 1724
1718 # vim: ts=2:sw=2:tw=80:et: 1725 # 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