OLD | NEW |
1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Gclient-specific SCM-specific operations.""" | 5 """Gclient-specific SCM-specific operations.""" |
6 | 6 |
7 import logging | 7 import logging |
8 import os | 8 import os |
9 import posixpath | 9 import posixpath |
10 import re | 10 import re |
(...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 (args[0], sp.returncode)) | 663 (args[0], sp.returncode)) |
664 if output is not None: | 664 if output is not None: |
665 return output.strip() | 665 return output.strip() |
666 | 666 |
667 | 667 |
668 class SVNWrapper(SCMWrapper): | 668 class SVNWrapper(SCMWrapper): |
669 """ Wrapper for SVN """ | 669 """ Wrapper for SVN """ |
670 | 670 |
671 def cleanup(self, options, args, file_list): | 671 def cleanup(self, options, args, file_list): |
672 """Cleanup working copy.""" | 672 """Cleanup working copy.""" |
673 scm.SVN.Run(['cleanup'] + args, | 673 self._Run(['cleanup'] + args, options) |
674 cwd=os.path.join(self._root_dir, self.relpath)) | |
675 | 674 |
676 def diff(self, options, args, file_list): | 675 def diff(self, options, args, file_list): |
677 # NOTE: This function does not currently modify file_list. | 676 # NOTE: This function does not currently modify file_list. |
678 path = os.path.join(self._root_dir, self.relpath) | 677 path = os.path.join(self._root_dir, self.relpath) |
679 if not os.path.isdir(path): | 678 if not os.path.isdir(path): |
680 raise gclient_utils.Error('Directory %s is not present.' % path) | 679 raise gclient_utils.Error('Directory %s is not present.' % path) |
681 scm.SVN.Run(['diff'] + args, cwd=path) | 680 self._Run(['diff'] + args, options) |
682 | 681 |
683 def export(self, options, args, file_list): | 682 def export(self, options, args, file_list): |
684 """Export a clean directory tree into the given path.""" | 683 """Export a clean directory tree into the given path.""" |
685 assert len(args) == 1 | 684 assert len(args) == 1 |
686 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) | 685 export_path = os.path.abspath(os.path.join(args[0], self.relpath)) |
687 try: | 686 try: |
688 os.makedirs(export_path) | 687 os.makedirs(export_path) |
689 except OSError: | 688 except OSError: |
690 pass | 689 pass |
691 assert os.path.exists(export_path) | 690 assert os.path.exists(export_path) |
692 scm.SVN.Run(['export', '--force', '.', export_path], | 691 self._Run(['export', '--force', '.', export_path], options) |
693 cwd=os.path.join(self._root_dir, self.relpath)) | |
694 | 692 |
695 def pack(self, options, args, file_list): | 693 def pack(self, options, args, file_list): |
696 """Generates a patch file which can be applied to the root of the | 694 """Generates a patch file which can be applied to the root of the |
697 repository.""" | 695 repository.""" |
698 path = os.path.join(self._root_dir, self.relpath) | 696 path = os.path.join(self._root_dir, self.relpath) |
699 if not os.path.isdir(path): | 697 if not os.path.isdir(path): |
700 raise gclient_utils.Error('Directory %s is not present.' % path) | 698 raise gclient_utils.Error('Directory %s is not present.' % path) |
701 command = ['svn', 'diff', '-x', '--ignore-eol-style'] | 699 command = ['svn', 'diff', '-x', '--ignore-eol-style'] |
702 command.extend(args) | 700 command.extend(args) |
703 | 701 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
738 url = '%s@%s' % (url, revision) | 736 url = '%s@%s' % (url, revision) |
739 rev_str = ' at %s' % revision | 737 rev_str = ' at %s' % revision |
740 else: | 738 else: |
741 forced_revision = False | 739 forced_revision = False |
742 rev_str = '' | 740 rev_str = '' |
743 | 741 |
744 if not os.path.exists(checkout_path): | 742 if not os.path.exists(checkout_path): |
745 # We need to checkout. | 743 # We need to checkout. |
746 command = ['checkout', url, checkout_path] | 744 command = ['checkout', url, checkout_path] |
747 command = self._AddAdditionalUpdateFlags(command, options, revision) | 745 command = self._AddAdditionalUpdateFlags(command, options, revision) |
748 scm.SVN.RunAndGetFileList(options.verbose, command, self._root_dir, | 746 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
749 file_list) | |
750 return | 747 return |
751 | 748 |
752 # Get the existing scm url and the revision number of the current checkout. | 749 # Get the existing scm url and the revision number of the current checkout. |
753 from_info = scm.SVN.CaptureInfo(os.path.join(checkout_path, '.'), '.') | 750 from_info = scm.SVN.CaptureInfo(os.path.join(checkout_path, '.'), '.') |
754 if not from_info: | 751 if not from_info: |
755 raise gclient_utils.Error(('Can\'t update/checkout %r if an unversioned ' | 752 raise gclient_utils.Error(('Can\'t update/checkout %r if an unversioned ' |
756 'directory is present. Delete the directory ' | 753 'directory is present. Delete the directory ' |
757 'and try again.') % | 754 'and try again.') % |
758 checkout_path) | 755 checkout_path) |
759 | 756 |
760 # Look for locked directories. | 757 # Look for locked directories. |
761 dir_info = scm.SVN.CaptureStatus(os.path.join(checkout_path, '.')) | 758 dir_info = scm.SVN.CaptureStatus(os.path.join(checkout_path, '.')) |
762 if [True for d in dir_info if d[0][2] == 'L' and d[1] == checkout_path]: | 759 if [True for d in dir_info if d[0][2] == 'L' and d[1] == checkout_path]: |
763 # The current directory is locked, clean it up. | 760 # The current directory is locked, clean it up. |
764 scm.SVN.Run(['cleanup'], cwd=checkout_path) | 761 self._Run(['cleanup'], options) |
765 | 762 |
766 # Retrieve the current HEAD version because svn is slow at null updates. | 763 # Retrieve the current HEAD version because svn is slow at null updates. |
767 if options.manually_grab_svn_rev and not revision: | 764 if options.manually_grab_svn_rev and not revision: |
768 from_info_live = scm.SVN.CaptureInfo(from_info['URL'], '.') | 765 from_info_live = scm.SVN.CaptureInfo(from_info['URL'], '.') |
769 revision = str(from_info_live['Revision']) | 766 revision = str(from_info_live['Revision']) |
770 rev_str = ' at %s' % revision | 767 rev_str = ' at %s' % revision |
771 | 768 |
772 if from_info['URL'] != base_url: | 769 if from_info['URL'] != base_url: |
773 # The repository url changed, need to switch. | 770 # The repository url changed, need to switch. |
774 to_info = scm.SVN.CaptureInfo(url, '.') | 771 to_info = scm.SVN.CaptureInfo(url, '.') |
(...skipping 11 matching lines...) Expand all Loading... |
786 # to reflect where we "are now." (This is the same way that | 783 # to reflect where we "are now." (This is the same way that |
787 # Subversion itself handles the metadata when switch --relocate | 784 # Subversion itself handles the metadata when switch --relocate |
788 # is used.) This makes the checks below for whether we | 785 # is used.) This makes the checks below for whether we |
789 # can update to a revision or have to switch to a different | 786 # can update to a revision or have to switch to a different |
790 # branch work as expected. | 787 # branch work as expected. |
791 # TODO(maruel): TEST ME ! | 788 # TODO(maruel): TEST ME ! |
792 command = ['switch', '--relocate', | 789 command = ['switch', '--relocate', |
793 from_info['Repository Root'], | 790 from_info['Repository Root'], |
794 to_info['Repository Root'], | 791 to_info['Repository Root'], |
795 self.relpath] | 792 self.relpath] |
796 scm.SVN.Run(command, cwd=self._root_dir) | 793 self._Run(command, options, cwd=self._root_dir) |
797 from_info['URL'] = from_info['URL'].replace( | 794 from_info['URL'] = from_info['URL'].replace( |
798 from_info['Repository Root'], | 795 from_info['Repository Root'], |
799 to_info['Repository Root']) | 796 to_info['Repository Root']) |
800 else: | 797 else: |
801 if not options.force and not options.reset: | 798 if not options.force and not options.reset: |
802 # Look for local modifications but ignore unversioned files. | 799 # Look for local modifications but ignore unversioned files. |
803 for status in scm.SVN.CaptureStatus(checkout_path): | 800 for status in scm.SVN.CaptureStatus(checkout_path): |
804 if status[0] != '?': | 801 if status[0] != '?': |
805 raise gclient_utils.Error( | 802 raise gclient_utils.Error( |
806 ('Can\'t switch the checkout to %s; UUID don\'t match and ' | 803 ('Can\'t switch the checkout to %s; UUID don\'t match and ' |
807 'there is local changes in %s. Delete the directory and ' | 804 'there is local changes in %s. Delete the directory and ' |
808 'try again.') % (url, checkout_path)) | 805 'try again.') % (url, checkout_path)) |
809 # Ok delete it. | 806 # Ok delete it. |
810 print('\n_____ switching %s to a new checkout' % self.relpath) | 807 print('\n_____ switching %s to a new checkout' % self.relpath) |
811 gclient_utils.RemoveDirectory(checkout_path) | 808 gclient_utils.RemoveDirectory(checkout_path) |
812 # We need to checkout. | 809 # We need to checkout. |
813 command = ['checkout', url, checkout_path] | 810 command = ['checkout', url, checkout_path] |
814 command = self._AddAdditionalUpdateFlags(command, options, revision) | 811 command = self._AddAdditionalUpdateFlags(command, options, revision) |
815 scm.SVN.RunAndGetFileList(options.verbose, command, self._root_dir, | 812 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
816 file_list) | |
817 return | 813 return |
818 | 814 |
819 # If the provided url has a revision number that matches the revision | 815 # If the provided url has a revision number that matches the revision |
820 # number of the existing directory, then we don't need to bother updating. | 816 # number of the existing directory, then we don't need to bother updating. |
821 if not options.force and str(from_info['Revision']) == revision: | 817 if not options.force and str(from_info['Revision']) == revision: |
822 if options.verbose or not forced_revision: | 818 if options.verbose or not forced_revision: |
823 print('\n_____ %s%s' % (self.relpath, rev_str)) | 819 print('\n_____ %s%s' % (self.relpath, rev_str)) |
824 return | 820 return |
825 | 821 |
826 command = ['update', checkout_path] | 822 command = ['update', checkout_path] |
827 command = self._AddAdditionalUpdateFlags(command, options, revision) | 823 command = self._AddAdditionalUpdateFlags(command, options, revision) |
828 scm.SVN.RunAndGetFileList(options.verbose, command, self._root_dir, | 824 self._RunAndGetFileList(command, options, file_list, self._root_dir) |
829 file_list) | |
830 | 825 |
831 def updatesingle(self, options, args, file_list): | 826 def updatesingle(self, options, args, file_list): |
832 checkout_path = os.path.join(self._root_dir, self.relpath) | 827 checkout_path = os.path.join(self._root_dir, self.relpath) |
833 filename = args.pop() | 828 filename = args.pop() |
834 if scm.SVN.AssertVersion("1.5")[0]: | 829 if scm.SVN.AssertVersion("1.5")[0]: |
835 if not os.path.exists(os.path.join(checkout_path, '.svn')): | 830 if not os.path.exists(os.path.join(checkout_path, '.svn')): |
836 # Create an empty checkout and then update the one file we want. Future | 831 # Create an empty checkout and then update the one file we want. Future |
837 # operations will only apply to the one file we checked out. | 832 # operations will only apply to the one file we checked out. |
838 command = ["checkout", "--depth", "empty", self.url, checkout_path] | 833 command = ["checkout", "--depth", "empty", self.url, checkout_path] |
839 scm.SVN.Run(command, cwd=self._root_dir) | 834 self._Run(command, options, cwd=self._root_dir) |
840 if os.path.exists(os.path.join(checkout_path, filename)): | 835 if os.path.exists(os.path.join(checkout_path, filename)): |
841 os.remove(os.path.join(checkout_path, filename)) | 836 os.remove(os.path.join(checkout_path, filename)) |
842 command = ["update", filename] | 837 command = ["update", filename] |
843 scm.SVN.RunAndGetFileList(options.verbose, command, checkout_path, | 838 self._RunAndGetFileList(command, options, file_list) |
844 file_list) | |
845 # After the initial checkout, we can use update as if it were any other | 839 # After the initial checkout, we can use update as if it were any other |
846 # dep. | 840 # dep. |
847 self.update(options, args, file_list) | 841 self.update(options, args, file_list) |
848 else: | 842 else: |
849 # If the installed version of SVN doesn't support --depth, fallback to | 843 # If the installed version of SVN doesn't support --depth, fallback to |
850 # just exporting the file. This has the downside that revision | 844 # just exporting the file. This has the downside that revision |
851 # information is not stored next to the file, so we will have to | 845 # information is not stored next to the file, so we will have to |
852 # re-export the file every time we sync. | 846 # re-export the file every time we sync. |
853 if not os.path.exists(checkout_path): | 847 if not os.path.exists(checkout_path): |
854 os.makedirs(checkout_path) | 848 os.makedirs(checkout_path) |
855 command = ["export", os.path.join(self.url, filename), | 849 command = ["export", os.path.join(self.url, filename), |
856 os.path.join(checkout_path, filename)] | 850 os.path.join(checkout_path, filename)] |
857 command = self._AddAdditionalUpdateFlags(command, options, | 851 command = self._AddAdditionalUpdateFlags(command, options, |
858 options.revision) | 852 options.revision) |
859 scm.SVN.Run(command, cwd=self._root_dir) | 853 self._Run(command, options, cwd=self._root_dir) |
860 | 854 |
861 def revert(self, options, args, file_list): | 855 def revert(self, options, args, file_list): |
862 """Reverts local modifications. Subversion specific. | 856 """Reverts local modifications. Subversion specific. |
863 | 857 |
864 All reverted files will be appended to file_list, even if Subversion | 858 All reverted files will be appended to file_list, even if Subversion |
865 doesn't know about them. | 859 doesn't know about them. |
866 """ | 860 """ |
867 path = os.path.join(self._root_dir, self.relpath) | 861 path = os.path.join(self._root_dir, self.relpath) |
868 if not os.path.isdir(path): | 862 if not os.path.isdir(path): |
869 # svn revert won't work if the directory doesn't exist. It needs to | 863 # svn revert won't work if the directory doesn't exist. It needs to |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
912 gclient_utils.RemoveDirectory(file_path) | 906 gclient_utils.RemoveDirectory(file_path) |
913 else: | 907 else: |
914 logging.error('no idea what is %s.\nYou just found a bug in gclient' | 908 logging.error('no idea what is %s.\nYou just found a bug in gclient' |
915 ', please ping maruel@chromium.org ASAP!' % file_path) | 909 ', please ping maruel@chromium.org ASAP!' % file_path) |
916 except EnvironmentError: | 910 except EnvironmentError: |
917 logging.error('Failed to remove %s.' % file_path) | 911 logging.error('Failed to remove %s.' % file_path) |
918 | 912 |
919 try: | 913 try: |
920 # svn revert is so broken we don't even use it. Using | 914 # svn revert is so broken we don't even use it. Using |
921 # "svn up --revision BASE" achieve the same effect. | 915 # "svn up --revision BASE" achieve the same effect. |
922 scm.SVN.RunAndGetFileList(options.verbose, | 916 self._RunAndGetFileList(['update', '--revision', 'BASE'], options, |
923 ['update', '--revision', 'BASE'], path, | 917 file_list) |
924 file_list) | |
925 except OSError, e: | 918 except OSError, e: |
926 # Maybe the directory disapeared meanwhile. We don't want it to throw an | 919 # Maybe the directory disapeared meanwhile. We don't want it to throw an |
927 # exception. | 920 # exception. |
928 logging.error('Failed to update:\n%s' % str(e)) | 921 logging.error('Failed to update:\n%s' % str(e)) |
929 | 922 |
930 def revinfo(self, options, args, file_list): | 923 def revinfo(self, options, args, file_list): |
931 """Display revision""" | 924 """Display revision""" |
932 return scm.SVN.CaptureBaseRevision(self.checkout_path) | 925 return scm.SVN.CaptureBaseRevision(self.checkout_path) |
933 | 926 |
934 def runhooks(self, options, args, file_list): | 927 def runhooks(self, options, args, file_list): |
935 self.status(options, args, file_list) | 928 self.status(options, args, file_list) |
936 | 929 |
937 def status(self, options, args, file_list): | 930 def status(self, options, args, file_list): |
938 """Display status information.""" | 931 """Display status information.""" |
939 path = os.path.join(self._root_dir, self.relpath) | 932 path = os.path.join(self._root_dir, self.relpath) |
940 command = ['status'] | 933 command = ['status'] + args |
941 command.extend(args) | |
942 if not os.path.isdir(path): | 934 if not os.path.isdir(path): |
943 # svn status won't work if the directory doesn't exist. | 935 # svn status won't work if the directory doesn't exist. |
944 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " | 936 print("\n________ couldn't run \'%s\' in \'%s\':\nThe directory " |
945 "does not exist." | 937 "does not exist." |
946 % (' '.join(command), path)) | 938 % (' '.join(command), path)) |
947 # There's no file list to retrieve. | 939 # There's no file list to retrieve. |
948 else: | 940 else: |
949 scm.SVN.RunAndGetFileList(options.verbose, command, path, file_list) | 941 self._RunAndGetFileList(command, options, file_list) |
950 | 942 |
951 def FullUrlForRelativeUrl(self, url): | 943 def FullUrlForRelativeUrl(self, url): |
952 # Find the forth '/' and strip from there. A bit hackish. | 944 # Find the forth '/' and strip from there. A bit hackish. |
953 return '/'.join(self.url.split('/')[:4]) + url | 945 return '/'.join(self.url.split('/')[:4]) + url |
954 | 946 |
| 947 def _Run(self, args, options, **kwargs): |
| 948 """Runs a commands that goes to stdout.""" |
| 949 kwargs.setdefault('cwd', os.path.join(self._root_dir, self.relpath)) |
| 950 gclient_utils.CheckCallAndFilterAndHeader(['svn'] + args, |
| 951 always=options.verbose, stdout=options.stdout, **kwargs) |
| 952 |
| 953 def _RunAndGetFileList(self, args, options, file_list, cwd=None): |
| 954 """Runs a commands that goes to stdout and grabs the file listed.""" |
| 955 cwd = cwd or os.path.join(self._root_dir, self.relpath) |
| 956 scm.SVN.RunAndGetFileList(options.verbose, args, cwd=cwd, |
| 957 file_list=file_list, stdout=options.stdout) |
| 958 |
955 @staticmethod | 959 @staticmethod |
956 def _AddAdditionalUpdateFlags(command, options, revision): | 960 def _AddAdditionalUpdateFlags(command, options, revision): |
957 """Add additional flags to command depending on what options are set. | 961 """Add additional flags to command depending on what options are set. |
958 command should be a list of strings that represents an svn command. | 962 command should be a list of strings that represents an svn command. |
959 | 963 |
960 This method returns a new list to be used as a command.""" | 964 This method returns a new list to be used as a command.""" |
961 new_command = command[:] | 965 new_command = command[:] |
962 if revision: | 966 if revision: |
963 new_command.extend(['--revision', str(revision).strip()]) | 967 new_command.extend(['--revision', str(revision).strip()]) |
964 # --force was added to 'svn update' in svn 1.5. | 968 # --force was added to 'svn update' in svn 1.5. |
965 if ((options.force or options.manually_grab_svn_rev) and | 969 if ((options.force or options.manually_grab_svn_rev) and |
966 scm.SVN.AssertVersion("1.5")[0]): | 970 scm.SVN.AssertVersion("1.5")[0]): |
967 new_command.append('--force') | 971 new_command.append('--force') |
968 return new_command | 972 return new_command |
OLD | NEW |