|
|
|
#!/usr/bin/python
|
|
|
|
# Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
"""Unit tests for gclient_scm.py."""
|
|
|
|
|
|
|
|
# Import before super_mox to keep valid references.
|
|
|
|
from os import rename
|
|
|
|
from shutil import rmtree
|
|
|
|
from subprocess import Popen, PIPE, STDOUT
|
|
|
|
import tempfile
|
|
|
|
import __builtin__
|
|
|
|
|
|
|
|
# Fixes include path.
|
|
|
|
from super_mox import mox, SuperMoxBaseTestBase, SuperMoxTestBase
|
|
|
|
|
|
|
|
import gclient_scm
|
|
|
|
|
|
|
|
|
|
|
|
class GCBaseTestCase(SuperMoxTestBase):
|
|
|
|
# Like unittest's assertRaises, but checks for Gclient.Error.
|
|
|
|
def assertRaisesError(self, msg, fn, *args, **kwargs):
|
|
|
|
try:
|
|
|
|
fn(*args, **kwargs)
|
|
|
|
except gclient_scm.gclient_utils.Error, e:
|
|
|
|
self.assertEquals(e.args[0], msg)
|
|
|
|
else:
|
|
|
|
self.fail('%s not raised' % msg)
|
|
|
|
|
|
|
|
|
|
|
|
class BaseTestCase(GCBaseTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
GCBaseTestCase.setUp(self)
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileRead')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileWrite')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'SubprocessCall')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'RemoveDirectory')
|
|
|
|
self._CaptureSVNInfo = gclient_scm.scm.SVN.CaptureInfo
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Capture')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureInfo')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'CaptureStatus')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Run')
|
|
|
|
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'RunAndGetFileList')
|
|
|
|
self._scm_wrapper = gclient_scm.CreateSCM
|
|
|
|
|
|
|
|
|
|
|
|
class SVNWrapperTestCase(BaseTestCase):
|
|
|
|
class OptionsObject(object):
|
|
|
|
def __init__(self, test_case, verbose=False, revision=None):
|
|
|
|
self.verbose = verbose
|
|
|
|
self.revision = revision
|
|
|
|
self.manually_grab_svn_rev = True
|
|
|
|
self.deps_os = None
|
|
|
|
self.force = False
|
|
|
|
self.reset = False
|
|
|
|
self.nohooks = False
|
|
|
|
|
|
|
|
def Options(self, *args, **kwargs):
|
|
|
|
return self.OptionsObject(self, *args, **kwargs)
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
BaseTestCase.setUp(self)
|
|
|
|
self.root_dir = self.Dir()
|
|
|
|
self.args = self.Args()
|
|
|
|
self.url = self.Url()
|
|
|
|
self.relpath = 'asf'
|
|
|
|
|
|
|
|
def testDir(self):
|
|
|
|
members = [
|
|
|
|
'FullUrlForRelativeUrl', 'RunCommand',
|
|
|
|
'cleanup', 'diff', 'export', 'pack', 'relpath', 'revert',
|
|
|
|
'revinfo', 'runhooks', 'scm_name', 'status', 'update',
|
|
|
|
'updatesingle', 'url',
|
|
|
|
]
|
|
|
|
|
|
|
|
# If you add a member, be sure to add the relevant test!
|
|
|
|
self.compareMembers(self._scm_wrapper(), members)
|
|
|
|
|
|
|
|
def testUnsupportedSCM(self):
|
|
|
|
args = [self.url, self.root_dir, self.relpath]
|
|
|
|
kwargs = {'scm_name' : 'foo'}
|
|
|
|
exception_msg = 'Unsupported scm %(scm_name)s' % kwargs
|
|
|
|
self.assertRaisesError(exception_msg, self._scm_wrapper, *args, **kwargs)
|
|
|
|
|
|
|
|
def testSVNFullUrlForRelativeUrl(self):
|
|
|
|
self.url = 'svn://a/b/c/d'
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
self.assertEqual(scm.FullUrlForRelativeUrl('/crap'), 'svn://a/b/crap')
|
|
|
|
|
|
|
|
def testGITFullUrlForRelativeUrl(self):
|
|
|
|
self.url = 'git://a/b/c/d'
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
self.assertEqual(scm.FullUrlForRelativeUrl('/crap'), 'git://a/b/c/crap')
|
|
|
|
|
|
|
|
def testRunCommandException(self):
|
|
|
|
options = self.Options(verbose=False)
|
|
|
|
file_path = gclient_scm.os.path.join(self.root_dir, self.relpath, '.git')
|
|
|
|
gclient_scm.os.path.exists(file_path).AndReturn(False)
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
exception = "Unsupported argument(s): %s" % ','.join(self.args)
|
|
|
|
self.assertRaisesError(exception, scm.RunCommand,
|
|
|
|
'update', options, self.args)
|
|
|
|
|
|
|
|
def testRunCommandUnknown(self):
|
|
|
|
# TODO(maruel): if ever used.
|
|
|
|
pass
|
|
|
|
|
|
|
|
def testRevertMissing(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
gclient_scm.os.path.isdir(base_path).AndReturn(False)
|
|
|
|
# It'll to a checkout instead.
|
|
|
|
gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.git')
|
|
|
|
).AndReturn(False)
|
|
|
|
print("\n_____ %s is missing, synching instead" % self.relpath)
|
|
|
|
# Checkout.
|
|
|
|
gclient_scm.os.path.exists(base_path).AndReturn(False)
|
|
|
|
files_list = self.mox.CreateMockAnything()
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['checkout', self.url, base_path],
|
|
|
|
self.root_dir, files_list)
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
scm.revert(options, self.args, files_list)
|
|
|
|
|
|
|
|
def testRevertNone(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
gclient_scm.os.path.isdir(base_path).AndReturn(True)
|
|
|
|
gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn([])
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['update', '--revision', 'BASE'],
|
|
|
|
base_path, mox.IgnoreArg())
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
|
|
|
|
def testRevert2Files(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
gclient_scm.os.path.isdir(base_path).AndReturn(True)
|
|
|
|
items = [
|
|
|
|
('M ', 'a'),
|
|
|
|
('A ', 'b'),
|
|
|
|
]
|
|
|
|
file_path1 = gclient_scm.os.path.join(base_path, 'a')
|
|
|
|
file_path2 = gclient_scm.os.path.join(base_path, 'b')
|
|
|
|
gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
|
|
|
|
gclient_scm.os.path.exists(file_path1).AndReturn(True)
|
|
|
|
gclient_scm.os.path.isfile(file_path1).AndReturn(True)
|
|
|
|
gclient_scm.os.remove(file_path1)
|
|
|
|
gclient_scm.os.path.exists(file_path2).AndReturn(True)
|
|
|
|
gclient_scm.os.path.isfile(file_path2).AndReturn(True)
|
|
|
|
gclient_scm.os.remove(file_path2)
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['update', '--revision', 'BASE'],
|
|
|
|
base_path, mox.IgnoreArg())
|
|
|
|
print(gclient_scm.os.path.join(base_path, 'a'))
|
|
|
|
print(gclient_scm.os.path.join(base_path, 'b'))
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
|
|
|
|
def testRevertDirectory(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
gclient_scm.os.path.isdir(base_path).AndReturn(True)
|
|
|
|
items = [
|
|
|
|
('~ ', 'a'),
|
|
|
|
]
|
|
|
|
gclient_scm.scm.SVN.CaptureStatus(base_path).AndReturn(items)
|
|
|
|
file_path = gclient_scm.os.path.join(base_path, 'a')
|
|
|
|
print(file_path)
|
|
|
|
gclient_scm.os.path.exists(file_path).AndReturn(True)
|
|
|
|
gclient_scm.os.path.isfile(file_path).AndReturn(False)
|
|
|
|
gclient_scm.os.path.islink(file_path).AndReturn(False)
|
|
|
|
gclient_scm.os.path.isdir(file_path).AndReturn(True)
|
|
|
|
gclient_scm.gclient_utils.RemoveDirectory(file_path)
|
|
|
|
file_list1 = []
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['update', '--revision', 'BASE'],
|
|
|
|
base_path, mox.IgnoreArg())
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list2 = []
|
|
|
|
scm.revert(options, self.args, file_list2)
|
|
|
|
|
|
|
|
def testStatus(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
gclient_scm.os.path.isdir(base_path).AndReturn(True)
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['status'] + self.args,
|
|
|
|
base_path, []).AndReturn(None)
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
self.assertEqual(scm.status(options, self.args, file_list), None)
|
|
|
|
|
|
|
|
|
|
|
|
# TODO(maruel): TEST REVISIONS!!!
|
|
|
|
# TODO(maruel): TEST RELOCATE!!!
|
|
|
|
def testUpdateCheckout(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
file_info = gclient_scm.gclient_utils.PrintableObject()
|
|
|
|
file_info.root = 'blah'
|
|
|
|
file_info.url = self.url
|
|
|
|
file_info.uuid = 'ABC'
|
|
|
|
file_info.revision = 42
|
|
|
|
gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.git')
|
|
|
|
).AndReturn(False)
|
|
|
|
# Checkout.
|
|
|
|
gclient_scm.os.path.exists(base_path).AndReturn(False)
|
|
|
|
files_list = self.mox.CreateMockAnything()
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(options,
|
|
|
|
['checkout', self.url, base_path],
|
|
|
|
self.root_dir, files_list)
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
scm.update(options, (), files_list)
|
|
|
|
|
|
|
|
def testUpdateUpdate(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
options.force = True
|
|
|
|
options.nohooks = False
|
|
|
|
file_info = {
|
|
|
|
'Repository Root': 'blah',
|
|
|
|
'URL': self.url,
|
|
|
|
'UUID': 'ABC',
|
|
|
|
'Revision': 42,
|
|
|
|
}
|
|
|
|
gclient_scm.os.path.exists(gclient_scm.os.path.join(base_path, '.git')
|
|
|
|
).AndReturn(False)
|
|
|
|
# Checkout or update.
|
|
|
|
gclient_scm.os.path.exists(base_path).AndReturn(True)
|
|
|
|
gclient_scm.scm.SVN.CaptureInfo(
|
|
|
|
gclient_scm.os.path.join(base_path, "."), '.'
|
|
|
|
).AndReturn(file_info)
|
|
|
|
# Cheat a bit here.
|
|
|
|
gclient_scm.scm.SVN.CaptureInfo(file_info['URL'], '.').AndReturn(file_info)
|
|
|
|
additional_args = []
|
|
|
|
if options.manually_grab_svn_rev:
|
|
|
|
additional_args = ['--revision', str(file_info['Revision'])]
|
|
|
|
files_list = []
|
|
|
|
gclient_scm.scm.SVN.RunAndGetFileList(
|
|
|
|
options,
|
|
|
|
['update', base_path] + additional_args,
|
|
|
|
self.root_dir, files_list)
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
scm.update(options, (), files_list)
|
|
|
|
|
|
|
|
def testUpdateSingleCheckout(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)
|
|
|
|
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.
|
|
|
|
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 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()
|
|
|
|
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 testUpdateGit(self):
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
file_path = gclient_scm.os.path.join(self.root_dir, self.relpath, '.git')
|
|
|
|
gclient_scm.os.path.exists(file_path).AndReturn(True)
|
|
|
|
print("________ found .git directory; skipping %s" % self.relpath)
|
|
|
|
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, self.args, file_list)
|
|
|
|
|
|
|
|
|
|
|
|
class GitWrapperTestCase(BaseTestCase):
|
|
|
|
"""This class doesn't use pymox."""
|
|
|
|
class OptionsObject(object):
|
|
|
|
def __init__(self, test_case, verbose=False, revision=None):
|
|
|
|
self.verbose = verbose
|
|
|
|
self.revision = revision
|
|
|
|
self.manually_grab_svn_rev = True
|
|
|
|
self.deps_os = None
|
|
|
|
self.force = False
|
|
|
|
self.reset = False
|
|
|
|
self.nohooks = False
|
|
|
|
|
|
|
|
sample_git_import = """blob
|
|
|
|
mark :1
|
|
|
|
data 6
|
|
|
|
Hello
|
|
|
|
|
|
|
|
blob
|
|
|
|
mark :2
|
|
|
|
data 4
|
|
|
|
Bye
|
|
|
|
|
|
|
|
reset refs/heads/master
|
|
|
|
commit refs/heads/master
|
|
|
|
mark :3
|
|
|
|
author Bob <bob@example.com> 1253744361 -0700
|
|
|
|
committer Bob <bob@example.com> 1253744361 -0700
|
|
|
|
data 8
|
|
|
|
A and B
|
|
|
|
M 100644 :1 a
|
|
|
|
M 100644 :2 b
|
|
|
|
|
|
|
|
blob
|
|
|
|
mark :4
|
|
|
|
data 10
|
|
|
|
Hello
|
|
|
|
You
|
|
|
|
|
|
|
|
blob
|
|
|
|
mark :5
|
|
|
|
data 8
|
|
|
|
Bye
|
|
|
|
You
|
|
|
|
|
|
|
|
commit refs/heads/origin
|
|
|
|
mark :6
|
|
|
|
author Alice <alice@example.com> 1253744424 -0700
|
|
|
|
committer Alice <alice@example.com> 1253744424 -0700
|
|
|
|
data 13
|
|
|
|
Personalized
|
|
|
|
from :3
|
|
|
|
M 100644 :4 a
|
|
|
|
M 100644 :5 b
|
|
|
|
|
|
|
|
reset refs/heads/master
|
|
|
|
from :3
|
|
|
|
"""
|
|
|
|
def Options(self, *args, **kwargs):
|
|
|
|
return self.OptionsObject(self, *args, **kwargs)
|
|
|
|
|
|
|
|
def CreateGitRepo(self, git_import, path):
|
|
|
|
"""Do it for real."""
|
|
|
|
try:
|
|
|
|
Popen(['git', 'init'], stdout=PIPE, stderr=STDOUT,
|
|
|
|
cwd=path).communicate()
|
|
|
|
except OSError:
|
|
|
|
# git is not available, skip this test.
|
|
|
|
return False
|
|
|
|
Popen(['git', 'fast-import'], stdin=PIPE, stdout=PIPE, stderr=STDOUT,
|
|
|
|
cwd=path).communicate(input=git_import)
|
|
|
|
Popen(['git', 'checkout'], stdout=PIPE, stderr=STDOUT,
|
|
|
|
cwd=path).communicate()
|
|
|
|
Popen(['git', 'remote', 'add', '-f', 'origin', '.'], stdout=PIPE,
|
|
|
|
stderr=STDOUT, cwd=path).communicate()
|
|
|
|
Popen(['git', 'checkout', '-b', 'new', 'origin/master'], stdout=PIPE,
|
|
|
|
stderr=STDOUT, cwd=path).communicate()
|
|
|
|
Popen(['git', 'push', 'origin', 'origin/origin:origin/master'], stdout=PIPE,
|
|
|
|
stderr=STDOUT, cwd=path).communicate()
|
|
|
|
Popen(['git', 'config', '--unset', 'remote.origin.fetch'], stdout=PIPE,
|
|
|
|
stderr=STDOUT, cwd=path).communicate()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.args = self.Args()
|
|
|
|
self.url = 'git://foo'
|
|
|
|
self.root_dir = tempfile.mkdtemp()
|
|
|
|
self.relpath = '.'
|
|
|
|
self.base_path = gclient_scm.os.path.join(self.root_dir, self.relpath)
|
|
|
|
self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
|
|
|
|
SuperMoxBaseTestBase.setUp(self)
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
SuperMoxBaseTestBase.tearDown(self)
|
|
|
|
rmtree(self.root_dir)
|
|
|
|
|
|
|
|
def testDir(self):
|
|
|
|
members = [
|
|
|
|
'FullUrlForRelativeUrl', 'RunCommand',
|
|
|
|
'cleanup', 'diff', 'export', 'pack', 'relpath', 'revert',
|
|
|
|
'revinfo', 'runhooks', 'scm_name', 'status', 'update', 'url',
|
|
|
|
]
|
|
|
|
|
|
|
|
# If you add a member, be sure to add the relevant test!
|
|
|
|
self.compareMembers(gclient_scm.CreateSCM(url=self.url), members)
|
|
|
|
|
|
|
|
def testRevertMissing(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'a')
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, None, file_list)
|
|
|
|
gclient_scm.os.remove(file_path)
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [file_path])
|
|
|
|
file_list = []
|
|
|
|
scm.diff(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [])
|
|
|
|
|
|
|
|
def testRevertNone(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, None, file_list)
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [])
|
|
|
|
self.assertEquals(scm.revinfo(options, self.args, None),
|
|
|
|
'a7142dc9f0009350b96a11f372b6ea658592aa95')
|
|
|
|
|
|
|
|
|
|
|
|
def testRevertModified(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, None, file_list)
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'a')
|
|
|
|
open(file_path, 'a').writelines('touched\n')
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [file_path])
|
|
|
|
file_list = []
|
|
|
|
scm.diff(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [])
|
|
|
|
self.assertEquals(scm.revinfo(options, self.args, None),
|
|
|
|
'a7142dc9f0009350b96a11f372b6ea658592aa95')
|
|
|
|
|
|
|
|
def testRevertNew(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, None, file_list)
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'c')
|
|
|
|
f = open(file_path, 'w')
|
|
|
|
f.writelines('new\n')
|
|
|
|
f.close()
|
|
|
|
Popen(['git', 'add', 'c'], stdout=PIPE,
|
|
|
|
stderr=STDOUT, cwd=self.base_path).communicate()
|
|
|
|
file_list = []
|
|
|
|
scm.revert(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [file_path])
|
|
|
|
file_list = []
|
|
|
|
scm.diff(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [])
|
|
|
|
self.assertEquals(scm.revinfo(options, self.args, None),
|
|
|
|
'a7142dc9f0009350b96a11f372b6ea658592aa95')
|
|
|
|
|
|
|
|
def testStatusNew(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'a')
|
|
|
|
open(file_path, 'a').writelines('touched\n')
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.status(options, self.args, file_list)
|
|
|
|
self.assertEquals(file_list, [file_path])
|
|
|
|
|
|
|
|
def testStatus2New(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
expected_file_list = []
|
|
|
|
for f in ['a', 'b']:
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, f)
|
|
|
|
open(file_path, 'a').writelines('touched\n')
|
|
|
|
expected_file_list.extend([file_path])
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.status(options, self.args, file_list)
|
|
|
|
expected_file_list = [gclient_scm.os.path.join(self.base_path, x)
|
|
|
|
for x in ['a', 'b']]
|
|
|
|
self.assertEquals(sorted(file_list), expected_file_list)
|
|
|
|
|
|
|
|
def testUpdateCheckout(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options(verbose=True)
|
|
|
|
root_dir = tempfile.mkdtemp()
|
|
|
|
relpath = 'foo'
|
|
|
|
base_path = gclient_scm.os.path.join(root_dir, relpath)
|
|
|
|
url = gclient_scm.os.path.join(self.root_dir, self.relpath, '.git')
|
|
|
|
try:
|
|
|
|
scm = gclient_scm.CreateSCM(url=url, root_dir=root_dir,
|
|
|
|
relpath=relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, (), file_list)
|
|
|
|
self.assertEquals(len(file_list), 2)
|
|
|
|
self.assert_(gclient_scm.os.path.isfile(
|
|
|
|
gclient_scm.os.path.join(base_path, 'a')))
|
|
|
|
self.assertEquals(scm.revinfo(options, (), None),
|
|
|
|
'069c602044c5388d2d15c3f875b057c852003458')
|
|
|
|
finally:
|
|
|
|
rmtree(root_dir)
|
|
|
|
|
|
|
|
def testUpdateUpdate(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
expected_file_list = [gclient_scm.os.path.join(self.base_path, x)
|
|
|
|
for x in ['a', 'b']]
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_list = []
|
|
|
|
scm.update(options, (), file_list)
|
|
|
|
self.assertEquals(file_list, expected_file_list)
|
|
|
|
self.assertEquals(scm.revinfo(options, (), None),
|
|
|
|
'a7142dc9f0009350b96a11f372b6ea658592aa95')
|
|
|
|
|
|
|
|
def testUpdateUnstagedConflict(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'b')
|
|
|
|
f = open(file_path, 'w').writelines('conflict\n')
|
|
|
|
exception = (
|
|
|
|
"error: Your local changes to 'b' would be overwritten by merge. "
|
|
|
|
"Aborting.\n"
|
|
|
|
"Please, commit your changes or stash them before you can merge.\n")
|
|
|
|
self.assertRaisesError(exception, scm.update, options, (), [])
|
|
|
|
|
|
|
|
def testUpdateConflict(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
file_path = gclient_scm.os.path.join(self.base_path, 'b')
|
|
|
|
f = open(file_path, 'w').writelines('conflict\n')
|
|
|
|
scm._Run(['commit', '-am', 'test'])
|
|
|
|
self.mox.StubOutWithMock(__builtin__, 'raw_input')
|
|
|
|
__builtin__.raw_input.__call__(mox.StrContains('Cannot fast-forward merge, '
|
|
|
|
'attempt to rebase? (y)es / '
|
|
|
|
'(q)uit / (s)kip : ')
|
|
|
|
).AndReturn('y')
|
|
|
|
self.mox.ReplayAll()
|
|
|
|
exception = \
|
|
|
|
'Conflict while rebasing this branch.\n' \
|
|
|
|
'Fix the conflict and run gclient again.\n' \
|
|
|
|
"See 'man git-rebase' for details.\n"
|
|
|
|
self.assertRaisesError(exception, scm.update, options, (), [])
|
|
|
|
exception = \
|
|
|
|
'\n____ . at refs/heads/master\n' \
|
gclient_scm.py: Make working with git more reliable
I found including a git repo in my DEPS file to be unreliable, esp
since I pinning to a specific commit. Whenever I changed the commit
in the DEPS file, gclient would attempt to do a rebase and this was
failing due to how rebase was being invoked.
While investigating the problem, I decided it might be better to take
a different approach. Namely, when cloning gclient should just checkout
the working tree to a detached HEAD. In this way, gclient can more
easily determine if the user has made any changes in the cloned repo.
Future updates (as long as there are no changes) become a much simpler
operation w/no need to invoke rebase.
This is a series of five commits, but sadly, git cl will squash them
into this single review. Here are the original commit messages:
commit 8cd2213f006a6f4b3f6b8c448a1362b9410d47f1
Author: Jay Soffian <jaysoffian@gmail.com>
Date: Wed Apr 14 18:29:18 2010 -0400
Use rev-parse to determine current branch
Git branch is a so-called porcelain and its output cannot be relied upon;
use git rev-parse instead.
gclient_scm.py | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
commit 1a09e04554acfa2671f9588ee9eef0bdbe677ed2
Author: Jay Soffian <jaysoffian@gmail.com>
Date: Wed Apr 14 22:16:53 2010 -0400
Detached HEAD does not always imply rebasing; use an _IsRebasing()
function instead.
gclient_scm.py | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
commit 45308a58c3f1e30b760f13abe3a6288267265fa8
Author: Jay Soffian <jaysoffian@gmail.com>
Date: Wed Apr 14 22:19:10 2010 -0400
Clarify comments to use common git terminology
gclient_scm.py | 14 ++++++++------
1 files changed, 8 insertions(+), 6 deletions(-)
commit 5e5a661b7dd9c83b2c9c35950f3267d15b7e840a
Author: Jay Soffian <jaysoffian@gmail.com>
Date: Tue May 4 12:15:40 2010 -0400
Make CaptureStatus use GetUpstreamBranch() instead of assuming 'origin'
scm.py | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
commit 42a8bfebd2e1b1be01025c1324d75920ac6eb0e1
Author: Jay Soffian <jaysoffian@gmail.com>
Date: Wed Apr 14 22:19:29 2010 -0400
Use a detached HEAD when checking out a tag or commit
After cloning, if a tag or commit was specified, leave a detached HEAD. This way
we can reliably detect if the user changed the working tree (since HEAD would no
longer be detached). Further, this simplifies the code path when the dependency
is updated to a new tag/commit. As long as HEAD is detached when we update, we
simply checkout whatever we fetched w/o needing to worry about rebasing.
gclient_scm.py | 126 +++++++++++++++++++++++++++++++-------------
tests/gclient_scm_test.py | 6 +--
2 files changed, 91 insertions(+), 41 deletions(-)
Review URL: http://codereview.chromium.org/1652007
Patch from Jay Soffian <jaysoffian@gmail.com>.
git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@48722 0039d316-1c4b-4281-b951-d872f2087c98
15 years ago
|
|
|
'\tYou have unstaged changes.\n' \
|
|
|
|
'\tPlease commit, stash, or reset.\n'
|
|
|
|
self.assertRaisesError(exception, scm.update, options, (), [])
|
|
|
|
|
|
|
|
def testUpdateNotGit(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
git_path = gclient_scm.os.path.join(self.base_path, '.git')
|
|
|
|
rename(git_path, git_path + 'foo')
|
|
|
|
exception = \
|
|
|
|
'\n____ . at refs/heads/master\n' \
|
|
|
|
'\tPath is not a git repo. No .git dir.\n' \
|
|
|
|
'\tTo resolve:\n' \
|
|
|
|
'\t\trm -rf .\n' \
|
|
|
|
'\tAnd run gclient sync again\n'
|
|
|
|
self.assertRaisesError(exception, scm.update, options, (), [])
|
|
|
|
|
|
|
|
def testRevinfo(self):
|
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
options = self.Options()
|
|
|
|
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
|
|
|
|
relpath=self.relpath)
|
|
|
|
rev_info = scm.revinfo(options, (), None)
|
|
|
|
self.assertEquals(rev_info, '069c602044c5388d2d15c3f875b057c852003458')
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import unittest
|
|
|
|
unittest.main()
|
|
|
|
|
|
|
|
# vim: ts=2:sw=2:tw=80:et:
|