Commit 0a0e3106 authored by thakis@chromium.org's avatar thakis@chromium.org

Revert of If the destination directory doesn't contain the desired repo,...

Revert of If the destination directory doesn't contain the desired repo, delete it (https://codereview.chromium.org/61623008/)

Reason for revert:
This breaks `gclient sync` for me. Before this patch:
________ found .git directory; skipping src

After this patch:
Error: 1> Can't update/checkout /Volumes/MacintoshHD2/src/chrome-git/src if an unversioned directory is present. Delete the directory and try again.


Original issue's description:
> If the destination directory doesn't contain the desired repo, delete it
> 
> Basic functionality - this may not be in quite the right place.
> 
> Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=245404

TBR=iannucci@chromium.org,ilevy@chromium.org,cmp@chromium.org,maruel@chromium.org,morrita@chromium.org,borenet@google.com
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/141633005

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@245530 0039d316-1c4b-4281-b951-d872f2087c98
parent 69ae86a3
......@@ -87,7 +87,6 @@ import platform
import posixpath
import pprint
import re
import socket
import sys
import time
import urllib
......@@ -669,39 +668,6 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
command, options, parsed_url, self.parent.name, revision_overrides)
self._used_scm = gclient_scm.CreateSCM(
parsed_url, self.root.root_dir, self.name)
def enable_deletion_of_conflicting_checkouts():
"""Determines whether to enable new checkout deletion behavior.
Initially, enables the experimental functionality on a small set of
bots.
"""
# TODO(borenet): Remove this hack as soon as we've verified that it
# doesn't cause the bots to break.
return (os.environ.get('CHROME_HEADLESS') and
socket.gethostname() in ('vm859-m1', 'build1-m1', 'vm630-m1'))
# When updating, determine whether the destination directory contains a
# checkout of the desired repository. If not, avoid conflicts by
# deleting the directory before running the update.
if command == 'update' and enable_deletion_of_conflicting_checkouts():
logging.warning('Experimental deletion of mismatching checkouts '
'enabled.')
actual_remote_url = self._used_scm.GetRemoteURL(options)
url, _ = gclient_utils.SplitUrlRevision(parsed_url)
url = url.rstrip('/')
dest_dir = os.path.join(self.root.root_dir, self.name)
if os.path.isdir(dest_dir) and actual_remote_url != url:
if options.force:
logging.warning('%s does not contain a checkout of %s. Removing '
' %s' % (dest_dir, url, dest_dir))
gclient_utils.rmtree(dest_dir)
else:
raise gclient_utils.Error('%s does not contain a checkout of %s. '
'Please fix the solution manually or '
'run with --force to delete '
'automatically.' % (dest_dir, url))
self._got_revision = self._used_scm.RunCommand(command, options, args,
file_list)
if file_list:
......
......@@ -222,13 +222,6 @@ class GitWrapper(SCMWrapper):
def GetCheckoutRoot(self):
return scm.GIT.GetCheckoutRoot(self.checkout_path)
def GetRemoteURL(self, options, cwd=None):
try:
return self._Capture(['config', 'remote.%s.url' % self.remote],
cwd=cwd or self.checkout_path).rstrip()
except (OSError, subprocess2.CalledProcessError):
return None
def GetRevisionDate(self, _revision):
"""Returns the given revision's date in ISO-8601 format (which contains the
time zone)."""
......@@ -284,6 +277,22 @@ class GitWrapper(SCMWrapper):
gclient_utils.CheckCallAndFilter(cmd4, **kwargs)
def _FetchAndReset(self, revision, file_list, options):
"""Equivalent to git fetch; git reset."""
quiet = []
if not options.verbose:
quiet = ['--quiet']
self._UpdateBranchHeads(options, fetch=False)
fetch_cmd = [
'-c', 'core.deltaBaseCacheLimit=2g', 'fetch', self.remote, '--prune']
self._Run(fetch_cmd + quiet, options, retry=True)
self._Run(['reset', '--hard', revision] + quiet, options)
self.UpdateSubmoduleConfig()
if file_list is not None:
files = self._Capture(['ls-files']).splitlines()
file_list.extend([os.path.join(self.checkout_path, f) for f in files])
def update(self, options, args, file_list):
"""Runs git to update or transparently checkout the working copy.
......@@ -370,10 +379,35 @@ class GitWrapper(SCMWrapper):
'\tAnd run gclient sync again\n'
% (self.relpath, rev_str, self.relpath))
# See if the url has changed (the unittests use git://foo for the url, let
# that through).
current_url = self._Capture(['config', 'remote.%s.url' % self.remote])
return_early = False
# TODO(maruel): Delete url != 'git://foo' since it's just to make the
# unit test pass. (and update the comment above)
# Skip url auto-correction if remote.origin.gclient-auto-fix-url is set.
# This allows devs to use experimental repos which have a different url
# but whose branch(s) are the same as official repos.
if (current_url != url and
url != 'git://foo' and
subprocess2.capture(
['git', 'config', 'remote.%s.gclient-auto-fix-url' % self.remote],
cwd=self.checkout_path).strip() != 'False'):
print('_____ switching %s to a new upstream' % self.relpath)
# Make sure it's clean
self._CheckClean(rev_str)
# Switch over to the new upstream
self._Run(['remote', 'set-url', self.remote, url], options)
self._FetchAndReset(revision, file_list, options)
return_early = True
# Need to do this in the normal path as well as in the post-remote-switch
# path.
self._PossiblySwitchCache(url, options)
if return_early:
return self._Capture(['rev-parse', '--verify', 'HEAD'])
cur_branch = self._GetCurrentBranch()
# Cases:
......@@ -779,7 +813,8 @@ class GitWrapper(SCMWrapper):
# to relax this restriction in the future to allow for smarter cache
# repo update schemes (such as pulling the same repo, but from a
# different host).
existing_url = self.GetRemoteURL(options, cwd=folder)
existing_url = self._Capture(['config', 'remote.%s.url' % self.remote],
cwd=folder)
assert self._NormalizeGitURL(existing_url) == self._NormalizeGitURL(url)
if use_reference:
......@@ -1048,13 +1083,6 @@ class SVNWrapper(SCMWrapper):
def GetCheckoutRoot(self):
return scm.SVN.GetCheckoutRoot(self.checkout_path)
def GetRemoteURL(self, options):
try:
local_info = scm.SVN.CaptureLocalInfo([os.curdir], self.checkout_path)
except (OSError, subprocess2.CalledProcessError):
return None
return local_info.get('URL')
def GetRevisionDate(self, revision):
"""Returns the given revision's date in ISO-8601 format (which contains the
time zone)."""
......@@ -1094,12 +1122,25 @@ class SVNWrapper(SCMWrapper):
Raises:
Error: if can't get URL for relative path.
"""
# Only update if git or hg is not controlling the directory.
git_path = os.path.join(self.checkout_path, '.git')
if os.path.exists(git_path):
print('________ found .git directory; skipping %s' % self.relpath)
return
hg_path = os.path.join(self.checkout_path, '.hg')
if os.path.exists(hg_path):
print('________ found .hg directory; skipping %s' % self.relpath)
return
if args:
raise gclient_utils.Error("Unsupported argument(s): %s" % ",".join(args))
# revision is the revision to match. It is None if no revision is specified,
# i.e. the 'deps ain't pinned'.
url, revision = gclient_utils.SplitUrlRevision(self.url)
# Keep the original unpinned url for reference in case the repo is switched.
base_url = url
managed = True
if options.revision:
# Override the revision number.
......@@ -1254,6 +1295,53 @@ class SVNWrapper(SCMWrapper):
revision = str(from_info_live['Revision'])
rev_str = ' at %s' % revision
if from_info['URL'] != base_url:
# The repository url changed, need to switch.
try:
to_info = scm.SVN.CaptureRemoteInfo(url)
except (gclient_utils.Error, subprocess2.CalledProcessError):
# The url is invalid or the server is not accessible, it's safer to bail
# out right now.
raise gclient_utils.Error('This url is unreachable: %s' % url)
can_switch = ((from_info['Repository Root'] != to_info['Repository Root'])
and (from_info['UUID'] == to_info['UUID']))
if can_switch:
print('\n_____ relocating %s to a new checkout' % self.relpath)
# We have different roots, so check if we can switch --relocate.
# Subversion only permits this if the repository UUIDs match.
# Perform the switch --relocate, then rewrite the from_url
# to reflect where we "are now." (This is the same way that
# Subversion itself handles the metadata when switch --relocate
# is used.) This makes the checks below for whether we
# can update to a revision or have to switch to a different
# branch work as expected.
# TODO(maruel): TEST ME !
command = ['switch', '--relocate',
from_info['Repository Root'],
to_info['Repository Root'],
self.relpath]
self._Run(command, options, cwd=self._root_dir)
from_info['URL'] = from_info['URL'].replace(
from_info['Repository Root'],
to_info['Repository Root'])
else:
if not options.force and not options.reset:
# Look for local modifications but ignore unversioned files.
for status in scm.SVN.CaptureStatus(None, self.checkout_path):
if status[0][0] != '?':
raise gclient_utils.Error(
('Can\'t switch the checkout to %s; UUID don\'t match and '
'there is local changes in %s. Delete the directory and '
'try again.') % (url, self.checkout_path))
# Ok delete it.
print('\n_____ switching %s to a new checkout' % self.relpath)
gclient_utils.rmtree(self.checkout_path)
# We need to checkout.
command = ['checkout', url, self.checkout_path]
command = self._AddAdditionalUpdateFlags(command, options, revision)
self._RunAndGetFileList(command, options, file_list, self._root_dir)
return self.Svnversion()
# If the provided url has a revision number that matches the revision
# number of the existing directory, then we don't need to bother updating.
if not options.force and str(from_info['Revision']) == revision:
......@@ -1320,6 +1408,12 @@ class SVNWrapper(SCMWrapper):
return self.update(options, [], file_list)
if not os.path.isdir(os.path.join(self.checkout_path, '.svn')):
if os.path.isdir(os.path.join(self.checkout_path, '.git')):
print('________ found .git directory; skipping %s' % self.relpath)
return
if os.path.isdir(os.path.join(self.checkout_path, '.hg')):
print('________ found .hg directory; skipping %s' % self.relpath)
return
if not options.force:
raise gclient_utils.Error('Invalid checkout path, aborting')
print(
......
......@@ -102,7 +102,6 @@ class SVNWrapperTestCase(BaseTestCase):
'BinaryExists',
'FullUrlForRelativeUrl',
'GetCheckoutRoot',
'GetRemoteURL',
'GetRevisionDate',
'GetUsableRev',
'Svnversion',
......@@ -163,6 +162,8 @@ class SVNWrapperTestCase(BaseTestCase):
def testRunCommandException(self):
options = self.Options(verbose=False)
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
self.mox.ReplayAll()
scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
......@@ -182,6 +183,8 @@ class SVNWrapperTestCase(BaseTestCase):
gclient_scm.scm.SVN.Capture(['--version', '--quiet'], None
).AndReturn('1.5.1')
# It'll to a checkout instead.
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
# Checkout.
gclient_scm.os.path.exists(self.base_path).AndReturn(False)
parent = gclient_scm.os.path.dirname(self.base_path)
......@@ -209,7 +212,11 @@ class SVNWrapperTestCase(BaseTestCase):
options = self.Options(verbose=True, force=True)
gclient_scm.os.path.isdir(self.base_path).AndReturn(True)
gclient_scm.os.path.isdir(join(self.base_path, '.svn')).AndReturn(False)
gclient_scm.os.path.isdir(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.isdir(join(self.base_path, '.hg')).AndReturn(False)
# Checkout.
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(False)
parent = gclient_scm.os.path.dirname(self.base_path)
gclient_scm.os.path.exists(parent).AndReturn(False)
......@@ -334,6 +341,8 @@ class SVNWrapperTestCase(BaseTestCase):
file_info.url = self.url
file_info.uuid = 'ABC'
file_info.revision = 42
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
# Checkout.
gclient_scm.os.path.exists(self.base_path).AndReturn(False)
parent = gclient_scm.os.path.dirname(self.base_path)
......@@ -365,6 +374,8 @@ class SVNWrapperTestCase(BaseTestCase):
'UUID': 'ABC',
'Revision': 42,
}
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
# Checkout or update.
......@@ -409,6 +420,8 @@ class SVNWrapperTestCase(BaseTestCase):
'UUID': 'ABC',
'Revision': 42,
}
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
# Checkout or update.
......@@ -443,6 +456,8 @@ class SVNWrapperTestCase(BaseTestCase):
'UUID': 'ABC',
'Revision': 42,
}
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
# Checkout or update.
......@@ -507,6 +522,8 @@ class SVNWrapperTestCase(BaseTestCase):
file_list=files_list)
# Now we fall back on scm.update().
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
gclient_scm.scm.SVN._CaptureInfo([], dotted_path).AndReturn(file_info)
gclient_scm.scm.SVN._CaptureInfo([file_info['URL']], None
......@@ -575,6 +592,8 @@ class SVNWrapperTestCase(BaseTestCase):
file_list=files_list)
# Now we fall back on scm.update().
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
gclient_scm.scm.SVN._CaptureInfo(
[], join(self.base_path, ".")).AndReturn(file_info)
......@@ -609,6 +628,8 @@ class SVNWrapperTestCase(BaseTestCase):
# Now we fall back on scm.update().
files_list = self.mox.CreateMockAnything()
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(False)
gclient_scm.os.path.exists(self.base_path).AndReturn(True)
gclient_scm.scm.SVN._CaptureInfo(
[], join(self.base_path, '.')).AndReturn(file_info)
......@@ -624,6 +645,32 @@ class SVNWrapperTestCase(BaseTestCase):
scm.updatesingle(options, ['DEPS'], files_list)
self.checkstdout('\n_____ %s at 42\n' % self.relpath)
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)
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)
self.checkstdout(
('________ found .git directory; skipping %s\n' % self.relpath))
def testUpdateHg(self):
options = self.Options(verbose=True)
gclient_scm.os.path.exists(join(self.base_path, '.git')).AndReturn(False)
gclient_scm.os.path.exists(join(self.base_path, '.hg')).AndReturn(True)
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)
self.checkstdout(
('________ found .hg directory; skipping %s\n' % self.relpath))
def testGetUsableRevSVN(self):
# pylint: disable=E1101
options = self.Options(verbose=True)
......@@ -645,48 +692,6 @@ class SVNWrapperTestCase(BaseTestCase):
self.assertRaises(gclient_scm.gclient_utils.Error,
svn_scm.GetUsableRev, 'fake', options)
def testGetRemoteURL(self):
self.mox.UnsetStubs()
options = self.Options(verbose=True)
self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Capture', True)
svn_scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
relpath=self.relpath)
if svn_scm.relpath:
cwd = os.path.join(svn_scm._root_dir, svn_scm.relpath)
else:
cwd = svn_scm._root_dir
gclient_scm.scm.SVN.Capture(['info', '--xml', os.curdir], cwd).AndReturn(
"""<?xml version="1.0"?>
<info>
<entry
path="."
revision="1234"
kind="dir">
<url>%s</url>
<repository>
<root>https://dummy.repo.com/svn</root>
<uuid>FAKE</uuid>
</repository>
<wc-info>
<schedule>normal</schedule>
<depth>infinity</depth>
</wc-info>
<commit
revision="1234">
<author>fakedev@chromium.org</author>
<date>2013-11-14T15:08:21.757885Z</date>
</commit>
</entry>
</info>
""" % svn_scm.url)
self.mox.ReplayAll()
self.assertEquals(svn_scm.GetRemoteURL(options), self.url)
class BaseGitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils,
unittest.TestCase):
"""This class doesn't use pymox."""
......@@ -812,7 +817,6 @@ class ManagedGitWrapperTestCase(BaseGitWrapperTestCase):
'BinaryExists',
'FullUrlForRelativeUrl',
'GetCheckoutRoot',
'GetRemoteURL',
'GetRevisionDate',
'GetUsableRev',
'RunCommand',
......@@ -1181,18 +1185,6 @@ class ManagedGitWrapperTestCaseMox(BaseTestCase):
self.assertRaises(gclient_scm.gclient_utils.Error,
git_svn_scm.GetUsableRev, too_big, options)
def testGetRemoteURL(self):
options = self.Options(verbose=True)
self.mox.StubOutWithMock(gclient_scm.GitWrapper, '_Capture', True)
git_scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
relpath=self.relpath)
git_scm._Capture(['config', 'remote.origin.url'], cwd='/tmp/fake'
).AndReturn('%s\n' % git_scm.url)
self.mox.ReplayAll()
self.assertEquals(git_scm.GetRemoteURL(options), self.url)
class UnmanagedGitWrapperTestCase(BaseGitWrapperTestCase):
def testUpdateUpdate(self):
......
......@@ -13,7 +13,6 @@ This test assumes GClientSmokeBase.URL_BASE is valid.
import logging
import os
import re
import socket
import subprocess
import sys
import unittest
......@@ -777,7 +776,7 @@ class GClientSmokeSVN(GClientSmokeBase):
# Cripple src/third_party/foo and make sure gclient still succeeds.
gclient_utils.rmtree(join(third_party, 'foo', '.svn'))
self.assertEquals(0, self.gclient(cmd + ['--force'])[-1])
self.assertEquals(0, self.gclient(cmd)[-1])
class GClientSmokeSVNTransitive(GClientSmokeBase):
......@@ -1104,7 +1103,7 @@ class GClientSmokeGIT(GClientSmokeBase):
self.assertTree(tree)
# Pre-DEPS hooks run when syncing with --nohooks.
self.gclient(['sync', '--deps', 'mac', '--nohooks', '--force',
self.gclient(['sync', '--deps', 'mac', '--nohooks',
'--revision', 'src@' + self.githash('repo_5', 2)])
tree = self.mangle_git_tree(('repo_5@2', 'src'),
('repo_1@2', 'src/repo1'),
......@@ -1116,7 +1115,7 @@ class GClientSmokeGIT(GClientSmokeBase):
os.remove(join(self.root_dir, 'src', 'git_pre_deps_hooked'))
# Pre-DEPS hooks don't run with --noprehooks
self.gclient(['sync', '--deps', 'mac', '--noprehooks', '--force',
self.gclient(['sync', '--deps', 'mac', '--noprehooks',
'--revision', 'src@' + self.githash('repo_5', 2)])
tree = self.mangle_git_tree(('repo_5@2', 'src'),
('repo_1@2', 'src/repo1'),
......@@ -1344,81 +1343,6 @@ class GClientSmokeBoth(GClientSmokeBase):
self.assertEquals(sorted(entries), sorted(expected))
# TODO(borenet): Enable this at the same time that the guard is removed in
# gclient.
if (os.environ.get('CHROME_HEADLESS') and
socket.gethostname() in ('vm859-m1', 'build1-m1', 'vm630-m1')):
def testDeleteConflictingCheckout(self):
if not self.enabled:
return
# Create an initial svn checkout.
self.gclient(['config', '--spec',
'solutions=['
'{"name": "src",'
' "url": "' + self.svn_base + 'trunk/src"},'
']'
])
results = self.gclient(['sync', '--deps', 'mac'])
self.assertEqual(results[2], 0, 'Sync failed!')
# Verify that we have the expected svn checkout.
results = self.gclient(['revinfo', '--deps', 'mac'])
actual = results[0].splitlines()
expected = [
'src: %strunk/src' % self.svn_base,
'src/file/other: File("%strunk/other/DEPS")' % self.svn_base,
'src/other: %strunk/other' % self.svn_base,
'src/third_party/foo: %strunk/third_party/foo@1' % self.svn_base,
]
self.assertEquals(actual, expected)
# Change the desired checkout to git.
self.gclient(['config', '--spec',
'solutions=['
'{"name": "src",'
' "url": "' + self.git_base + 'repo_1"},'
']'
])
# Verify that the sync succeeds with --force.
results = self.gclient(['sync', '--deps', 'mac', '--force'])
self.assertEqual(results[2], 0, 'Sync failed!')
# Verify that we got the desired git checkout.
results = self.gclient(['revinfo', '--deps', 'mac'])
actual = results[0].splitlines()
expected = [
'src: %srepo_1' % self.git_base,
'src/repo2: %srepo_2@%s' % (self.git_base,
self.githash('repo_2', 1)[:7]),
'src/repo2/repo_renamed: %srepo_3' % self.git_base,
]
self.assertEquals(actual, expected)
# Change the desired checkout back to svn.
self.gclient(['config', '--spec',
'solutions=['
'{"name": "src",'
' "url": "' + self.svn_base + 'trunk/src"},'
']'
])
# Verify that the sync succeeds.
results = self.gclient(['sync', '--deps', 'mac', '--force'])
self.assertEqual(results[2], 0, 'Sync failed!')
# Verify that we have the expected svn checkout.
results = self.gclient(['revinfo', '--deps', 'mac'])
actual = results[0].splitlines()
expected = [
'src: %strunk/src' % self.svn_base,
'src/file/other: File("%strunk/other/DEPS")' % self.svn_base,
'src/other: %strunk/other' % self.svn_base,
'src/third_party/foo: %strunk/third_party/foo@1' % self.svn_base,
]
self.assertEquals(actual, expected)
class GClientSmokeFromCheckout(GClientSmokeBase):
# WebKit abuses this. It has a .gclient and a DEPS from a checkout.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment