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 |