Commit eb2756df authored by cmp@chromium.org's avatar cmp@chromium.org

Add a --unmanaged flag to gclient config to allow the main solution to be unmanaged by the scm.

The dependencies will continue to be managed. A new flag is present in the .gclient file to control this behavior.

Review URL: http://codereview.chromium.org/7918027

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@102002 0039d316-1c4b-4281-b951-d872f2087c98
parent 68988975
......@@ -139,7 +139,7 @@ class GClientKeywords(object):
class Dependency(GClientKeywords, gclient_utils.WorkItem):
"""Object that represents a dependency checkout."""
def __init__(self, parent, name, url, safesync_url, custom_deps,
def __init__(self, parent, name, url, safesync_url, managed, custom_deps,
custom_vars, deps_file, should_process):
# Warning: this function can be called from any thread. Both
# self.dependencies and self.requirements are read and modified from
......@@ -157,6 +157,13 @@ class Dependency(GClientKeywords, gclient_utils.WorkItem):
self.url = url
# These are only set in .gclient and not in DEPS files.
# 'managed' determines whether or not this dependency is synced/updated by
# gclient after gclient checks it out initially. The difference between
# 'managed' and 'should_process' (defined below) is that the user specifies
# 'managed' via the --unmanaged command-line flag or a .gclient config,
# where 'should_process' is dynamically set by gclient if it goes over its
# recursion limit and controls gclient's behavior so it does not misbehave.
self.managed = managed
self.custom_vars = custom_vars or {}
self.custom_deps = custom_deps or {}
self.deps_hooks = []
......@@ -402,7 +409,7 @@ class Dependency(GClientKeywords, gclient_utils.WorkItem):
'Dependency %s specified more than once:\n %s\nvs\n %s' %
(name, tree[name].hierarchy(), self.hierarchy()))
self.dependencies.append(Dependency(self, name, url, None, None, None,
self.deps_file, should_process))
None, self.deps_file, should_process))
logging.debug('Loaded: %s' % str(self))
# Arguments number differs from overridden method
......@@ -662,6 +669,7 @@ solutions = [
{ "name" : "%(solution_name)s",
"url" : "%(solution_url)s",
"deps_file" : "%(deps_file)s",
"managed" : %(managed)s,
"custom_deps" : {
},
"safesync_url": "%(safesync_url)s",
......@@ -673,6 +681,7 @@ solutions = [
{ "name" : "%(solution_name)s",
"url" : "%(solution_url)s",
"deps_file" : "%(deps_file)s",
"managed" : %(managed)s,
"custom_deps" : {
%(solution_deps)s },
"safesync_url": "%(safesync_url)s",
......@@ -689,8 +698,8 @@ solutions = [
# Do not change previous behavior. Only solution level and immediate DEPS
# are processed.
self._recursion_limit = 2
Dependency.__init__(self, None, None, None, None, None, None, 'unused',
True)
Dependency.__init__(self, None, None, None, None, True, None, None,
'unused', True)
self._options = options
if options.deps_os:
enforced_os = options.deps_os.split(',')
......@@ -719,6 +728,7 @@ solutions = [
self.dependencies.append(Dependency(
self, s['name'], s['url'],
s.get('safesync_url', None),
s.get('managed', True),
s.get('custom_deps', {}),
s.get('custom_vars', {}),
s.get('deps_file', 'DEPS'),
......@@ -748,12 +758,13 @@ solutions = [
return client
def SetDefaultConfig(self, solution_name, deps_file, solution_url,
safesync_url):
safesync_url, managed=True):
self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
'solution_name': solution_name,
'solution_url': solution_url,
'deps_file': deps_file,
'safesync_url' : safesync_url,
'managed': managed,
})
def _SaveEntries(self):
......@@ -799,13 +810,14 @@ solutions = [
# Do not check safesync_url if one or more --revision flag is specified.
if not self._options.revisions:
for s in self.dependencies:
if not s.safesync_url:
continue
handle = urllib.urlopen(s.safesync_url)
rev = handle.read().strip()
handle.close()
if len(rev):
self._options.revisions.append('%s@%s' % (s.name, rev))
if not s.managed:
self._options.revisions.append('%s@unmanaged' % s.name)
elif s.safesync_url:
handle = urllib.urlopen(s.safesync_url)
rev = handle.read().strip()
handle.close()
if len(rev):
self._options.revisions.append('%s@%s' % (s.name, rev))
if not self._options.revisions:
return revision_overrides
solutions_names = [s.name for s in self.dependencies]
......@@ -929,6 +941,7 @@ solutions = [
'solution_url': d.url,
'deps_file': d.deps_file,
'safesync_url' : d.safesync_url or '',
'managed': d.managed,
'solution_deps': ''.join(custom_deps),
}
# Print the snapshot configuration file
......@@ -1048,6 +1061,11 @@ URL.
parser.add_option('--deps-file', default='DEPS',
help='overrides the default name for the DEPS file for the'
'main solutions and all sub-dependencies')
parser.add_option('--unmanaged', action='store_true', default=False,
help='overrides the default behavior to make it possible '
'to have the main solution untouched by gclient '
'(gclient will check out unmanaged dependencies but '
'will never sync them)')
parser.add_option('--git-deps', action='store_true',
help='sets the deps file to ".DEPS.git" instead of "DEPS"')
(options, args) = parser.parse_args(args)
......@@ -1073,7 +1091,8 @@ URL.
safesync_url = ''
if len(args) > 1:
safesync_url = args[1]
client.SetDefaultConfig(name, deps_file, base_url, safesync_url)
client.SetDefaultConfig(name, deps_file, base_url, safesync_url,
managed=not options.unmanaged)
client.SaveConfig()
return 0
......
......@@ -174,9 +174,13 @@ class GitWrapper(SCMWrapper):
url, deps_revision = gclient_utils.SplitUrlRevision(self.url)
rev_str = ""
revision = deps_revision
managed = True
if options.revision:
# Override the revision number.
revision = str(options.revision)
if revision == 'unmanaged':
revision = None
managed = False
if not revision:
revision = default_rev
......@@ -218,6 +222,10 @@ class GitWrapper(SCMWrapper):
print('')
return
if not managed:
print ('________ unmanaged solution; skipping %s' % self.relpath)
return
if not os.path.exists(os.path.join(self.checkout_path, '.git')):
raise gclient_utils.Error('\n____ %s%s\n'
'\tPath is not a git repo. No .git dir.\n'
......@@ -735,14 +743,19 @@ class SVNWrapper(SCMWrapper):
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.
revision = str(options.revision)
if revision:
forced_revision = True
# Reconstruct the url.
url = '%s@%s' % (url, revision)
rev_str = ' at %s' % revision
if revision != 'unmanaged':
forced_revision = True
# Reconstruct the url.
url = '%s@%s' % (url, revision)
rev_str = ' at %s' % revision
else:
managed = False
revision = None
else:
forced_revision = False
rev_str = ''
......@@ -754,6 +767,10 @@ class SVNWrapper(SCMWrapper):
self._RunAndGetFileList(command, options, file_list, self._root_dir)
return
if not managed:
print ('________ unmanaged solution; skipping %s' % self.relpath)
return
# Get the existing scm url and the revision number of the current checkout.
try:
from_info = scm.SVN.CaptureInfo(os.path.join(self.checkout_path, '.'))
......
......@@ -442,8 +442,8 @@ class SVNWrapperTestCase(BaseTestCase):
('________ found .hg directory; skipping %s\n' % self.relpath))
class GitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils,
unittest.TestCase):
class BaseGitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils,
unittest.TestCase):
"""This class doesn't use pymox."""
class OptionsObject(object):
def __init__(self, verbose=False, revision=None):
......@@ -543,6 +543,8 @@ from :3
unittest.TestCase.tearDown(self)
rmtree(self.root_dir)
class ManagedGitWrapperTestCase(BaseGitWrapperTestCase):
def testDir(self):
members = [
'FullUrlForRelativeUrl', 'GetRevisionDate', 'RunCommand',
......@@ -823,6 +825,64 @@ from :3
self.assertEquals(rev_info, '069c602044c5388d2d15c3f875b057c852003458')
class UnmanagedGitWrapperTestCase(BaseGitWrapperTestCase):
def testUpdateCheckout(self):
if not self.enabled:
return
options = self.Options(verbose=True)
root_dir = gclient_scm.os.path.realpath(tempfile.mkdtemp())
relpath = 'foo'
base_path = join(root_dir, relpath)
url = join(self.base_path, '.git')
try:
scm = gclient_scm.CreateSCM(url=url, root_dir=root_dir,
relpath=relpath)
file_list = []
options.revision = 'unmanaged'
scm.update(options, (), file_list)
self.assertEquals(len(file_list), 2)
self.assert_(gclient_scm.os.path.isfile(join(base_path, 'a')))
self.assertEquals(scm.revinfo(options, (), None),
'069c602044c5388d2d15c3f875b057c852003458')
finally:
rmtree(root_dir)
msg1 = (
"\n_____ foo at refs/heads/master\n\n"
"________ running 'git clone -b master --verbose %s %s' in '%s'\n"
"Initialized empty Git repository in %s\n") % (
join(self.root_dir, '.', '.git'),
join(root_dir, 'foo'),
root_dir,
join(gclient_scm.os.path.realpath(root_dir), 'foo', '.git') + '/')
msg2 = (
"\n_____ foo at refs/heads/master\n\n"
"________ running 'git clone -b master --verbose %s %s' in '%s'\n"
"Cloning into %s...\ndone.\n") % (
join(self.root_dir, '.', '.git'),
join(root_dir, 'foo'),
root_dir,
join(gclient_scm.os.path.realpath(root_dir), 'foo'))
out = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = self._old_stdout
self.assertTrue(out in (msg1, msg2), (out, msg1, msg2))
def testUpdateUpdate(self):
if not self.enabled:
return
options = self.Options()
expected_file_list = []
scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
relpath=self.relpath)
file_list = []
options.revision = 'unmanaged'
scm.update(options, (), file_list)
self.assertEquals(file_list, expected_file_list)
self.assertEquals(scm.revinfo(options, (), None),
'069c602044c5388d2d15c3f875b057c852003458')
self.checkstdout('________ unmanaged solution; skipping .\n')
if __name__ == '__main__':
if '-v' in sys.argv:
logging.basicConfig(
......
......@@ -200,6 +200,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "src",\n'
' "url" : "%strunk/src",\n'
' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' },\n'
' "safesync_url": "",\n'
......@@ -211,6 +212,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "src",\n'
' "url" : "%srepo_1",\n'
' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' },\n'
' "safesync_url": "",\n'
......@@ -222,6 +224,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "foo",\n'
' "url" : "foo",\n'
' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' },\n'
' "safesync_url": "faa",\n'
......@@ -233,6 +236,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "foo",\n'
' "url" : "foo",\n'
' "deps_file" : "blah",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' },\n'
' "safesync_url": "",\n'
......@@ -687,6 +691,7 @@ class GClientSmokeSVN(GClientSmokeBase):
' { "name" : "src",\n'
' "url" : "%(base)s/src",\n'
' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' "foo/bar": None,\n'
' "invalid": None,\n'
......@@ -713,6 +718,7 @@ class GClientSmokeSVN(GClientSmokeBase):
' { "name" : "src",\n'
' "url" : "%(base)s/src",\n'
' "deps_file" : "DEPS.alt",\n'
' "managed" : True,\n'
' "custom_deps" : {\n'
' "src/other2": \'%(base)s/other@2\',\n'
' },\n'
......
......@@ -199,7 +199,7 @@ class GclientTest(trial_dir.TestCase):
# Invalid urls causes pain when specifying requirements. Make sure it's
# auto-fixed.
d = gclient.Dependency(
None, 'name', 'proto://host/path/@revision', None, None,
None, 'name', 'proto://host/path/@revision', None, None, None,
None, '', True)
self.assertEquals('proto://host/path@revision', d.url)
......@@ -210,23 +210,25 @@ class GclientTest(trial_dir.TestCase):
options, _ = parser.parse_args([])
obj = gclient.GClient('foo', options)
obj.dependencies.append(
gclient.Dependency(obj, 'foo', 'url', None, None, None, 'DEPS', True))
gclient.Dependency(obj, 'foo', 'url', None, None, None, None, 'DEPS',
True))
obj.dependencies.append(
gclient.Dependency(obj, 'bar', 'url', None, None, None, 'DEPS', True))
gclient.Dependency(obj, 'bar', 'url', None, None, None, None, 'DEPS',
True))
obj.dependencies[0].dependencies.append(
gclient.Dependency(
obj.dependencies[0], 'foo/dir1', 'url', None, None, None, 'DEPS',
True))
obj.dependencies[0], 'foo/dir1', 'url', None, None, None, None,
'DEPS', True))
obj.dependencies[0].dependencies.append(
gclient.Dependency(
obj.dependencies[0], 'foo/dir2',
gclient.GClientKeywords.FromImpl('bar'), None, None, None, 'DEPS',
True))
gclient.GClientKeywords.FromImpl('bar'), None, None, None, None,
'DEPS', True))
obj.dependencies[0].dependencies.append(
gclient.Dependency(
obj.dependencies[0], 'foo/dir3',
gclient.GClientKeywords.FileImpl('url'), None, None, None, 'DEPS',
True))
gclient.GClientKeywords.FileImpl('url'), None, None, None, None,
'DEPS', True))
obj.dependencies[0]._file_list.append('foo')
self.assertEquals(434, len(str(obj)), '%d\n%s' % (len(str(obj)), str(obj)))
......
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