| 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 |