| OLD | NEW |
| 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 574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 | 585 |
| 586 Returns: | 586 Returns: |
| 587 Int head revision | 587 Int head revision |
| 588 """ | 588 """ |
| 589 info = CaptureSVN(options, ["info", "--xml", url], os.getcwd()) | 589 info = CaptureSVN(options, ["info", "--xml", url], os.getcwd()) |
| 590 dom = xml.dom.minidom.parseString(info) | 590 dom = xml.dom.minidom.parseString(info) |
| 591 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision')) | 591 return int(dom.getElementsByTagName('entry')[0].getAttribute('revision')) |
| 592 | 592 |
| 593 | 593 |
| 594 class FileStatus: | 594 class FileStatus: |
| 595 def __init__(self, path, text_status, props, history): | 595 def __init__(self, path, text_status, props, lock, history): |
| 596 self.path = path | 596 self.path = path |
| 597 self.text_status = text_status | 597 self.text_status = text_status |
| 598 self.props = props | 598 self.props = props |
| 599 self.lock = lock |
| 599 self.history = history | 600 self.history = history |
| 600 | 601 |
| 601 def __str__(self): | 602 def __str__(self): |
| 602 # Emulate svn status 1.5 output. | 603 # Emulate svn status 1.5 output. |
| 603 return (self.text_status + self.props + ' ' + self.history + ' ' + | 604 return (self.text_status + self.props + self.lock + self.history + ' ' + |
| 604 self.path) | 605 self.path) |
| 605 | 606 |
| 606 | 607 |
| 607 def CaptureSVNStatus(options, path): | 608 def CaptureSVNStatus(options, path): |
| 608 """Runs 'svn status' on an existing path. | 609 """Runs 'svn status' on an existing path. |
| 609 | 610 |
| 610 Args: | 611 Args: |
| 611 path: The directory to run svn status. | 612 path: The directory to run svn status. |
| 612 | 613 |
| 613 Returns: | 614 Returns: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 628 # Col 0 | 629 # Col 0 |
| 629 xml_item_status = wc_status[0].getAttribute('item') | 630 xml_item_status = wc_status[0].getAttribute('item') |
| 630 if xml_item_status == 'unversioned': | 631 if xml_item_status == 'unversioned': |
| 631 statuses[0] = '?' | 632 statuses[0] = '?' |
| 632 elif xml_item_status == 'modified': | 633 elif xml_item_status == 'modified': |
| 633 statuses[0] = 'M' | 634 statuses[0] = 'M' |
| 634 elif xml_item_status == 'added': | 635 elif xml_item_status == 'added': |
| 635 statuses[0] = 'A' | 636 statuses[0] = 'A' |
| 636 elif xml_item_status == 'conflicted': | 637 elif xml_item_status == 'conflicted': |
| 637 statuses[0] = 'C' | 638 statuses[0] = 'C' |
| 639 elif xml_item_status in ('incomplete', 'missing'): |
| 640 statuses[0] = '!' |
| 638 elif not xml_item_status: | 641 elif not xml_item_status: |
| 639 pass | 642 pass |
| 640 else: | 643 else: |
| 641 raise Exception('Unknown item status "%s"; please implement me!' % | 644 raise Exception('Unknown item status "%s"; please implement me!' % |
| 642 xml_item_status) | 645 xml_item_status) |
| 643 # Col 1 | 646 # Col 1 |
| 644 xml_props_status = wc_status[0].getAttribute('props') | 647 xml_props_status = wc_status[0].getAttribute('props') |
| 645 if xml_props_status == 'modified': | 648 if xml_props_status == 'modified': |
| 646 statuses[1] = 'M' | 649 statuses[1] = 'M' |
| 647 elif xml_props_status == 'conflicted': | 650 elif xml_props_status == 'conflicted': |
| 648 statuses[1] = 'C' | 651 statuses[1] = 'C' |
| 649 elif (not xml_props_status or xml_props_status == 'none' or | 652 elif (not xml_props_status or xml_props_status == 'none' or |
| 650 xml_props_status == 'normal'): | 653 xml_props_status == 'normal'): |
| 651 pass | 654 pass |
| 652 else: | 655 else: |
| 653 raise Exception('Unknown props status "%s"; please implement me!' % | 656 raise Exception('Unknown props status "%s"; please implement me!' % |
| 654 xml_props_status) | 657 xml_props_status) |
| 658 # Col 2 |
| 659 if wc_status[0].getAttribute('wc-locked') == 'true': |
| 660 statuses[2] = 'L' |
| 655 # Col 3 | 661 # Col 3 |
| 656 if wc_status[0].getAttribute('copied') == 'true': | 662 if wc_status[0].getAttribute('copied') == 'true': |
| 657 statuses[3] = '+' | 663 statuses[3] = '+' |
| 658 item = FileStatus(file, statuses[0], statuses[1], statuses[3]) | 664 item = FileStatus(file, statuses[0], statuses[1], statuses[2], |
| 665 statuses[3]) |
| 659 results.append(item) | 666 results.append(item) |
| 660 return results | 667 return results |
| 661 | 668 |
| 662 | 669 |
| 663 ### SCM abstraction layer | 670 ### SCM abstraction layer |
| 664 | 671 |
| 665 | 672 |
| 666 class SCMWrapper(object): | 673 class SCMWrapper(object): |
| 667 """Add necessary glue between all the supported SCM. | 674 """Add necessary glue between all the supported SCM. |
| 668 | 675 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 revision = int(components[1]) | 755 revision = int(components[1]) |
| 749 forced_revision = True | 756 forced_revision = True |
| 750 | 757 |
| 751 rev_str = "" | 758 rev_str = "" |
| 752 if revision: | 759 if revision: |
| 753 rev_str = ' at %d' % revision | 760 rev_str = ' at %d' % revision |
| 754 | 761 |
| 755 if not options.path_exists(os.path.join(self._root_dir, self.relpath)): | 762 if not options.path_exists(os.path.join(self._root_dir, self.relpath)): |
| 756 # We need to checkout. | 763 # We need to checkout. |
| 757 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)] | 764 command = ['checkout', url, os.path.join(self._root_dir, self.relpath)] |
| 765 if revision: |
| 766 command.extend(['--revision', str(revision)]) |
| 758 RunSVNAndGetFileList(options, command, self._root_dir, file_list) | 767 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 768 return |
| 759 | 769 |
| 760 # Get the existing scm url and the revision number of the current checkout. | 770 # Get the existing scm url and the revision number of the current checkout. |
| 761 from_info = CaptureSVNInfo(options, | 771 from_info = CaptureSVNInfo(options, |
| 762 os.path.join(self._root_dir, self.relpath, '.'), | 772 os.path.join(self._root_dir, self.relpath, '.'), |
| 763 '.') | 773 '.') |
| 764 | 774 |
| 765 if options.manually_grab_svn_rev: | 775 if options.manually_grab_svn_rev: |
| 766 # Retrieve the current HEAD version because svn is slow at null updates. | 776 # Retrieve the current HEAD version because svn is slow at null updates. |
| 767 if not revision: | 777 if not revision: |
| 768 from_info_live = CaptureSVNInfo(options, from_info.url, '.') | 778 from_info_live = CaptureSVNInfo(options, from_info.url, '.') |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 RunSVNAndGetFileList(options, command, self._root_dir, file_list) | 813 RunSVNAndGetFileList(options, command, self._root_dir, file_list) |
| 804 | 814 |
| 805 def revert(self, options, args, file_list): | 815 def revert(self, options, args, file_list): |
| 806 """Reverts local modifications. Subversion specific. | 816 """Reverts local modifications. Subversion specific. |
| 807 | 817 |
| 808 All reverted files will be appended to file_list, even if Subversion | 818 All reverted files will be appended to file_list, even if Subversion |
| 809 doesn't know about them. | 819 doesn't know about them. |
| 810 """ | 820 """ |
| 811 path = os.path.join(self._root_dir, self.relpath) | 821 path = os.path.join(self._root_dir, self.relpath) |
| 812 if not os.path.isdir(path): | 822 if not os.path.isdir(path): |
| 813 # We can't revert path that doesn't exist. | 823 # svn revert won't work if the directory doesn't exist. It needs to |
| 814 # TODO(maruel): Should we update instead? | 824 # checkout instead. |
| 815 if options.verbose: | 825 print >>options.stdout, ("\n_____ %s is missing, synching instead" % |
| 816 print >>options.stdout, ("\n_____ %s is missing, can't revert" % | 826 self.relpath) |
| 817 self.relpath) | 827 # Don't reuse the args. |
| 818 return | 828 return self.update(options, [], file_list) |
| 819 | 829 |
| 820 files = CaptureSVNStatus(options, path) | 830 files = CaptureSVNStatus(options, path) |
| 821 # Batch the command. | 831 # Batch the command. |
| 822 files_to_revert = [] | 832 files_to_revert = [] |
| 823 for file in files: | 833 for file in files: |
| 824 file_path = os.path.join(path, file.path) | 834 file_path = os.path.join(path, file.path) |
| 825 print >>options.stdout, file_path | 835 print >>options.stdout, file_path |
| 826 # Unversioned file or unexpected unversioned file. | 836 # Unversioned file or unexpected unversioned file. |
| 827 if file.text_status in ('?', '~'): | 837 if file.text_status in ('?', '~'): |
| 828 # Remove extraneous file. Also remove unexpected unversioned | 838 # Remove extraneous file. Also remove unexpected unversioned |
| (...skipping 23 matching lines...) Expand all Loading... |
| 852 accumulated_length = 0 | 862 accumulated_length = 0 |
| 853 else: | 863 else: |
| 854 accumulated_paths.append(p) | 864 accumulated_paths.append(p) |
| 855 accumulated_length += len(p) | 865 accumulated_length += len(p) |
| 856 if accumulated_paths: | 866 if accumulated_paths: |
| 857 RunSVN(options, command + accumulated_paths, | 867 RunSVN(options, command + accumulated_paths, |
| 858 os.path.join(self._root_dir, self.relpath)) | 868 os.path.join(self._root_dir, self.relpath)) |
| 859 | 869 |
| 860 def status(self, options, args, file_list): | 870 def status(self, options, args, file_list): |
| 861 """Display status information.""" | 871 """Display status information.""" |
| 872 path = os.path.join(self._root_dir, self.relpath) |
| 862 command = ['status'] | 873 command = ['status'] |
| 863 command.extend(args) | 874 command.extend(args) |
| 864 RunSVNAndGetFileList(options, command, | 875 if not os.path.isdir(path): |
| 865 os.path.join(self._root_dir, self.relpath), file_list) | 876 # svn status won't work if the directory doesn't exist. |
| 877 print >> options.stdout, ( |
| 878 "\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
| 879 "does not exist." |
| 880 % (' '.join(command), path)) |
| 881 # There's no file list to retrieve. |
| 882 else: |
| 883 RunSVNAndGetFileList(options, command, path, file_list) |
| 866 | 884 |
| 867 | 885 |
| 868 ## GClient implementation. | 886 ## GClient implementation. |
| 869 | 887 |
| 870 | 888 |
| 871 class GClient(object): | 889 class GClient(object): |
| 872 """Object that represent a gclient checkout.""" | 890 """Object that represent a gclient checkout.""" |
| 873 | 891 |
| 874 supported_commands = [ | 892 supported_commands = [ |
| 875 'cleanup', 'diff', 'revert', 'status', 'update', 'runhooks' | 893 'cleanup', 'diff', 'revert', 'status', 'update', 'runhooks' |
| (...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1678 | 1696 |
| 1679 if "__main__" == __name__: | 1697 if "__main__" == __name__: |
| 1680 try: | 1698 try: |
| 1681 result = Main(sys.argv) | 1699 result = Main(sys.argv) |
| 1682 except Error, e: | 1700 except Error, e: |
| 1683 print "Error: %s" % str(e) | 1701 print "Error: %s" % str(e) |
| 1684 result = 1 | 1702 result = 1 |
| 1685 sys.exit(result) | 1703 sys.exit(result) |
| 1686 | 1704 |
| 1687 # vim: ts=2:sw=2:tw=80:et: | 1705 # vim: ts=2:sw=2:tw=80:et: |
| OLD | NEW |