diff --git a/gclient_scm.py b/gclient_scm.py index 3a3bd1a7b..d69a1d3f4 100644 --- a/gclient_scm.py +++ b/gclient_scm.py @@ -749,16 +749,31 @@ class SVNWrapper(SCMWrapper): def updatesingle(self, options, args, file_list): checkout_path = os.path.join(self._root_dir, self.relpath) filename = args.pop() - if not os.path.exists(checkout_path): - # Create an empty checkout and then update the one file we want. Future - # operations will only apply to the one file we checked out. - command = ["checkout", "--depth", "empty", self.url, checkout_path] + if scm.SVN.AssertVersion("1.5")[0]: + if not os.path.exists(os.path.join(checkout_path, '.svn')): + # Create an empty checkout and then update the one file we want. Future + # operations will only apply to the one file we checked out. + command = ["checkout", "--depth", "empty", self.url, checkout_path] + scm.SVN.Run(command, self._root_dir) + if os.path.exists(os.path.join(checkout_path, filename)): + os.remove(os.path.join(checkout_path, filename)) + command = ["update", filename] + scm.SVN.RunAndGetFileList(options, command, checkout_path, file_list) + # After the initial checkout, we can use update as if it were any other + # dep. + self.update(options, args, file_list) + else: + # If the installed version of SVN doesn't support --depth, fallback to + # just exporting the file. This has the downside that revision + # information is not stored next to the file, so we will have to + # re-export the file every time we sync. + if not os.path.exists(checkout_path): + os.makedirs(checkout_path) + command = ["export", os.path.join(self.url, filename), + os.path.join(checkout_path, filename)] + if options.revision: + command.extend(['--revision', str(options.revision)]) scm.SVN.Run(command, self._root_dir) - command = ["update", filename] - scm.SVN.RunAndGetFileList(options, command, checkout_path, file_list) - # After the initial checkout, we can use update as if it were any other - # dep. - self.update(options, args, file_list) def revert(self, options, args, file_list): """Reverts local modifications. Subversion specific. diff --git a/scm.py b/scm.py index 7c18f1660..87514beac 100644 --- a/scm.py +++ b/scm.py @@ -293,6 +293,7 @@ class GIT(object): class SVN(object): COMMAND = "svn" + current_version = None @staticmethod def Run(args, in_directory): @@ -765,3 +766,22 @@ class SVN(object): break directory = parent return GetCasedPath(directory) + + @staticmethod + def AssertVersion(min_version): + """Asserts svn's version is at least min_version.""" + def only_int(val): + if val.isdigit(): + return int(val) + else: + return 0 + if not SVN.current_version: + SVN.current_version = SVN.Capture(['--version']).split()[2] + current_version_list = map(only_int, SVN.current_version.split('.')) + for min_ver in map(int, min_version.split('.')): + ver = current_version_list.pop(0) + if ver < min_ver: + return (False, SVN.current_version) + elif ver > min_ver: + return (True, SVN.current_version) + return (True, SVN.current_version) diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py index 46e553605..fb2ea42e7 100755 --- a/tests/gclient_scm_test.py +++ b/tests/gclient_scm_test.py @@ -274,8 +274,17 @@ class SVNWrapperTestCase(BaseTestCase): 'URL': self.url, 'Revision': 42, } + + # Checks to make sure that we support svn co --depth. + gclient_scm.scm.SVN.current_version = None + gclient_scm.scm.SVN.Capture(['--version'] + ).AndReturn('svn, version 1.5.1 (r32289)') + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.svn') + ).AndReturn(False) + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, 'DEPS') + ).AndReturn(False) + # When checking out a single file, we issue an svn checkout and svn update. - gclient_scm.os.path.exists(base_path).AndReturn(False) files_list = self.mox.CreateMockAnything() gclient_scm.scm.SVN.Run( ['checkout', '--depth', 'empty', self.url, base_path], self.root_dir) @@ -284,7 +293,7 @@ class SVNWrapperTestCase(BaseTestCase): # Now we fall back on scm.update(). gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.git') - ).AndReturn(False) + ).AndReturn(False) gclient_scm.os.path.exists(base_path).AndReturn(True) gclient_scm.scm.SVN.CaptureInfo( gclient_scm.os.path.join(base_path, "."), '.' @@ -297,14 +306,87 @@ class SVNWrapperTestCase(BaseTestCase): relpath=self.relpath) scm.updatesingle(options, ['DEPS'], files_list) - def testUpdateSingleUpdate(self): + def testUpdateSingleCheckoutSVN14(self): options = self.Options(verbose=True) base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) file_info = { 'URL': self.url, 'Revision': 42, } + + # Checks to make sure that we support svn co --depth. + gclient_scm.scm.SVN.current_version = None + gclient_scm.scm.SVN.Capture(['--version'] + ).AndReturn('svn, version 1.4.4 (r25188)') + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path) + ).AndReturn(True) + + # When checking out a single file with svn 1.4, we use svn export + files_list = self.mox.CreateMockAnything() + gclient_scm.scm.SVN.Run( + ['export', gclient_scm.os.path.join(self.url, 'DEPS'), + gclient_scm.os.path.join(base_path, 'DEPS')], self.root_dir) + + self.mox.ReplayAll() + scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir, + relpath=self.relpath) + scm.updatesingle(options, ['DEPS'], files_list) + + def testUpdateSingleCheckoutSVNUpgrade(self): + options = self.Options(verbose=True) + base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) + file_info = { + 'URL': self.url, + 'Revision': 42, + } + + # Checks to make sure that we support svn co --depth. + gclient_scm.scm.SVN.current_version = None + gclient_scm.scm.SVN.Capture(['--version'] + ).AndReturn('svn, version 1.5.1 (r32289)') + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.svn') + ).AndReturn(False) + # If DEPS already exists, assume we're upgrading from svn1.4, so delete + # the old DEPS file. + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, 'DEPS') + ).AndReturn(True) + gclient_scm.os.remove(gclient_scm.os.path.join(base_path, 'DEPS')) + + # When checking out a single file, we issue an svn checkout and svn update. + files_list = self.mox.CreateMockAnything() + gclient_scm.scm.SVN.Run( + ['checkout', '--depth', 'empty', self.url, base_path], self.root_dir) + gclient_scm.scm.SVN.RunAndGetFileList(options, ['update', 'DEPS'], + gclient_scm.os.path.join(self.root_dir, self.relpath), files_list) + + # Now we fall back on scm.update(). + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.git') + ).AndReturn(False) gclient_scm.os.path.exists(base_path).AndReturn(True) + gclient_scm.scm.SVN.CaptureInfo( + gclient_scm.os.path.join(base_path, "."), '.' + ).AndReturn(file_info) + gclient_scm.scm.SVN.CaptureInfo(file_info['URL'], '.').AndReturn(file_info) + print("\n_____ %s at 42" % self.relpath) + + self.mox.ReplayAll() + scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir, + relpath=self.relpath) + scm.updatesingle(options, ['DEPS'], files_list) + + def testUpdateSingleUpdate(self): + options = self.Options(verbose=True) + base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) + file_info = { + 'URL': self.url, + 'Revision': 42, + } + # Checks to make sure that we support svn co --depth. + gclient_scm.scm.SVN.current_version = None + gclient_scm.scm.SVN.Capture(['--version'] + ).AndReturn('svn, version 1.5.1 (r32289)') + gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.svn') + ).AndReturn(True) # Now we fall back on scm.update(). files_list = self.mox.CreateMockAnything() diff --git a/tests/scm_unittest.py b/tests/scm_unittest.py index 699039ebe..c27002a04 100755 --- a/tests/scm_unittest.py +++ b/tests/scm_unittest.py @@ -146,10 +146,11 @@ class SVNTestCase(BaseSCMTestCase): def testMembersChanged(self): self.mox.ReplayAll() members = [ - 'COMMAND', 'Capture', 'CaptureBaseRevision', 'CaptureHeadRevision', - 'CaptureInfo', 'CaptureStatus', 'DiffItem', 'GenerateDiff', - 'GetCheckoutRoot', 'GetEmail', 'GetFileProperty', 'IsMoved', - 'ReadSimpleAuth', 'Run', 'RunAndFilterOutput', 'RunAndGetFileList', + 'COMMAND', 'AssertVersion', 'Capture', 'CaptureBaseRevision', + 'CaptureHeadRevision', 'CaptureInfo', 'CaptureStatus', + 'current_version', 'DiffItem', 'GenerateDiff', 'GetCheckoutRoot', + 'GetEmail', 'GetFileProperty', 'IsMoved', 'ReadSimpleAuth', 'Run', + 'RunAndFilterOutput', 'RunAndGetFileList', ] # If this test fails, you should add the relevant test. self.compareMembers(scm.SVN, members)