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
experimental/szager/collated-output
cmp@chromium.org 14 years ago
parent 6898897529
commit eb2756dfc4

@ -139,7 +139,7 @@ class GClientKeywords(object):
class Dependency(GClientKeywords, gclient_utils.WorkItem): class Dependency(GClientKeywords, gclient_utils.WorkItem):
"""Object that represents a dependency checkout.""" """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): custom_vars, deps_file, should_process):
# Warning: this function can be called from any thread. Both # Warning: this function can be called from any thread. Both
# self.dependencies and self.requirements are read and modified from # self.dependencies and self.requirements are read and modified from
@ -157,6 +157,13 @@ class Dependency(GClientKeywords, gclient_utils.WorkItem):
self.url = url self.url = url
# These are only set in .gclient and not in DEPS files. # 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_vars = custom_vars or {}
self.custom_deps = custom_deps or {} self.custom_deps = custom_deps or {}
self.deps_hooks = [] self.deps_hooks = []
@ -402,7 +409,7 @@ class Dependency(GClientKeywords, gclient_utils.WorkItem):
'Dependency %s specified more than once:\n %s\nvs\n %s' % 'Dependency %s specified more than once:\n %s\nvs\n %s' %
(name, tree[name].hierarchy(), self.hierarchy())) (name, tree[name].hierarchy(), self.hierarchy()))
self.dependencies.append(Dependency(self, name, url, None, None, None, 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)) logging.debug('Loaded: %s' % str(self))
# Arguments number differs from overridden method # Arguments number differs from overridden method
@ -662,6 +669,7 @@ solutions = [
{ "name" : "%(solution_name)s", { "name" : "%(solution_name)s",
"url" : "%(solution_url)s", "url" : "%(solution_url)s",
"deps_file" : "%(deps_file)s", "deps_file" : "%(deps_file)s",
"managed" : %(managed)s,
"custom_deps" : { "custom_deps" : {
}, },
"safesync_url": "%(safesync_url)s", "safesync_url": "%(safesync_url)s",
@ -673,6 +681,7 @@ solutions = [
{ "name" : "%(solution_name)s", { "name" : "%(solution_name)s",
"url" : "%(solution_url)s", "url" : "%(solution_url)s",
"deps_file" : "%(deps_file)s", "deps_file" : "%(deps_file)s",
"managed" : %(managed)s,
"custom_deps" : { "custom_deps" : {
%(solution_deps)s }, %(solution_deps)s },
"safesync_url": "%(safesync_url)s", "safesync_url": "%(safesync_url)s",
@ -689,8 +698,8 @@ solutions = [
# Do not change previous behavior. Only solution level and immediate DEPS # Do not change previous behavior. Only solution level and immediate DEPS
# are processed. # are processed.
self._recursion_limit = 2 self._recursion_limit = 2
Dependency.__init__(self, None, None, None, None, None, None, 'unused', Dependency.__init__(self, None, None, None, None, True, None, None,
True) 'unused', True)
self._options = options self._options = options
if options.deps_os: if options.deps_os:
enforced_os = options.deps_os.split(',') enforced_os = options.deps_os.split(',')
@ -719,6 +728,7 @@ solutions = [
self.dependencies.append(Dependency( self.dependencies.append(Dependency(
self, s['name'], s['url'], self, s['name'], s['url'],
s.get('safesync_url', None), s.get('safesync_url', None),
s.get('managed', True),
s.get('custom_deps', {}), s.get('custom_deps', {}),
s.get('custom_vars', {}), s.get('custom_vars', {}),
s.get('deps_file', 'DEPS'), s.get('deps_file', 'DEPS'),
@ -748,12 +758,13 @@ solutions = [
return client return client
def SetDefaultConfig(self, solution_name, deps_file, solution_url, def SetDefaultConfig(self, solution_name, deps_file, solution_url,
safesync_url): safesync_url, managed=True):
self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % { self.SetConfig(self.DEFAULT_CLIENT_FILE_TEXT % {
'solution_name': solution_name, 'solution_name': solution_name,
'solution_url': solution_url, 'solution_url': solution_url,
'deps_file': deps_file, 'deps_file': deps_file,
'safesync_url' : safesync_url, 'safesync_url' : safesync_url,
'managed': managed,
}) })
def _SaveEntries(self): def _SaveEntries(self):
@ -799,13 +810,14 @@ solutions = [
# Do not check safesync_url if one or more --revision flag is specified. # Do not check safesync_url if one or more --revision flag is specified.
if not self._options.revisions: if not self._options.revisions:
for s in self.dependencies: for s in self.dependencies:
if not s.safesync_url: if not s.managed:
continue self._options.revisions.append('%s@unmanaged' % s.name)
handle = urllib.urlopen(s.safesync_url) elif s.safesync_url:
rev = handle.read().strip() handle = urllib.urlopen(s.safesync_url)
handle.close() rev = handle.read().strip()
if len(rev): handle.close()
self._options.revisions.append('%s@%s' % (s.name, rev)) if len(rev):
self._options.revisions.append('%s@%s' % (s.name, rev))
if not self._options.revisions: if not self._options.revisions:
return revision_overrides return revision_overrides
solutions_names = [s.name for s in self.dependencies] solutions_names = [s.name for s in self.dependencies]
@ -929,6 +941,7 @@ solutions = [
'solution_url': d.url, 'solution_url': d.url,
'deps_file': d.deps_file, 'deps_file': d.deps_file,
'safesync_url' : d.safesync_url or '', 'safesync_url' : d.safesync_url or '',
'managed': d.managed,
'solution_deps': ''.join(custom_deps), 'solution_deps': ''.join(custom_deps),
} }
# Print the snapshot configuration file # Print the snapshot configuration file
@ -1048,6 +1061,11 @@ URL.
parser.add_option('--deps-file', default='DEPS', parser.add_option('--deps-file', default='DEPS',
help='overrides the default name for the DEPS file for the' help='overrides the default name for the DEPS file for the'
'main solutions and all sub-dependencies') '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', parser.add_option('--git-deps', action='store_true',
help='sets the deps file to ".DEPS.git" instead of "DEPS"') help='sets the deps file to ".DEPS.git" instead of "DEPS"')
(options, args) = parser.parse_args(args) (options, args) = parser.parse_args(args)
@ -1073,7 +1091,8 @@ URL.
safesync_url = '' safesync_url = ''
if len(args) > 1: if len(args) > 1:
safesync_url = 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() client.SaveConfig()
return 0 return 0

@ -174,9 +174,13 @@ class GitWrapper(SCMWrapper):
url, deps_revision = gclient_utils.SplitUrlRevision(self.url) url, deps_revision = gclient_utils.SplitUrlRevision(self.url)
rev_str = "" rev_str = ""
revision = deps_revision revision = deps_revision
managed = True
if options.revision: if options.revision:
# Override the revision number. # Override the revision number.
revision = str(options.revision) revision = str(options.revision)
if revision == 'unmanaged':
revision = None
managed = False
if not revision: if not revision:
revision = default_rev revision = default_rev
@ -218,6 +222,10 @@ class GitWrapper(SCMWrapper):
print('') print('')
return return
if not managed:
print ('________ unmanaged solution; skipping %s' % self.relpath)
return
if not os.path.exists(os.path.join(self.checkout_path, '.git')): if not os.path.exists(os.path.join(self.checkout_path, '.git')):
raise gclient_utils.Error('\n____ %s%s\n' raise gclient_utils.Error('\n____ %s%s\n'
'\tPath is not a git repo. No .git dir.\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) url, revision = gclient_utils.SplitUrlRevision(self.url)
# Keep the original unpinned url for reference in case the repo is switched. # Keep the original unpinned url for reference in case the repo is switched.
base_url = url base_url = url
managed = True
if options.revision: if options.revision:
# Override the revision number. # Override the revision number.
revision = str(options.revision) revision = str(options.revision)
if revision: if revision:
forced_revision = True if revision != 'unmanaged':
# Reconstruct the url. forced_revision = True
url = '%s@%s' % (url, revision) # Reconstruct the url.
rev_str = ' at %s' % revision url = '%s@%s' % (url, revision)
rev_str = ' at %s' % revision
else:
managed = False
revision = None
else: else:
forced_revision = False forced_revision = False
rev_str = '' rev_str = ''
@ -754,6 +767,10 @@ class SVNWrapper(SCMWrapper):
self._RunAndGetFileList(command, options, file_list, self._root_dir) self._RunAndGetFileList(command, options, file_list, self._root_dir)
return 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. # Get the existing scm url and the revision number of the current checkout.
try: try:
from_info = scm.SVN.CaptureInfo(os.path.join(self.checkout_path, '.')) 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)) ('________ found .hg directory; skipping %s\n' % self.relpath))
class GitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils, class BaseGitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils,
unittest.TestCase): unittest.TestCase):
"""This class doesn't use pymox.""" """This class doesn't use pymox."""
class OptionsObject(object): class OptionsObject(object):
def __init__(self, verbose=False, revision=None): def __init__(self, verbose=False, revision=None):
@ -543,6 +543,8 @@ from :3
unittest.TestCase.tearDown(self) unittest.TestCase.tearDown(self)
rmtree(self.root_dir) rmtree(self.root_dir)
class ManagedGitWrapperTestCase(BaseGitWrapperTestCase):
def testDir(self): def testDir(self):
members = [ members = [
'FullUrlForRelativeUrl', 'GetRevisionDate', 'RunCommand', 'FullUrlForRelativeUrl', 'GetRevisionDate', 'RunCommand',
@ -823,6 +825,64 @@ from :3
self.assertEquals(rev_info, '069c602044c5388d2d15c3f875b057c852003458') 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 __name__ == '__main__':
if '-v' in sys.argv: if '-v' in sys.argv:
logging.basicConfig( logging.basicConfig(

@ -200,6 +200,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "src",\n' ' { "name" : "src",\n'
' "url" : "%strunk/src",\n' ' "url" : "%strunk/src",\n'
' "deps_file" : "DEPS",\n' ' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' },\n' ' },\n'
' "safesync_url": "",\n' ' "safesync_url": "",\n'
@ -211,6 +212,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "src",\n' ' { "name" : "src",\n'
' "url" : "%srepo_1",\n' ' "url" : "%srepo_1",\n'
' "deps_file" : "DEPS",\n' ' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' },\n' ' },\n'
' "safesync_url": "",\n' ' "safesync_url": "",\n'
@ -222,6 +224,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "foo",\n' ' { "name" : "foo",\n'
' "url" : "foo",\n' ' "url" : "foo",\n'
' "deps_file" : "DEPS",\n' ' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' },\n' ' },\n'
' "safesync_url": "faa",\n' ' "safesync_url": "faa",\n'
@ -233,6 +236,7 @@ class GClientSmoke(GClientSmokeBase):
' { "name" : "foo",\n' ' { "name" : "foo",\n'
' "url" : "foo",\n' ' "url" : "foo",\n'
' "deps_file" : "blah",\n' ' "deps_file" : "blah",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' },\n' ' },\n'
' "safesync_url": "",\n' ' "safesync_url": "",\n'
@ -687,6 +691,7 @@ class GClientSmokeSVN(GClientSmokeBase):
' { "name" : "src",\n' ' { "name" : "src",\n'
' "url" : "%(base)s/src",\n' ' "url" : "%(base)s/src",\n'
' "deps_file" : "DEPS",\n' ' "deps_file" : "DEPS",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' "foo/bar": None,\n' ' "foo/bar": None,\n'
' "invalid": None,\n' ' "invalid": None,\n'
@ -713,6 +718,7 @@ class GClientSmokeSVN(GClientSmokeBase):
' { "name" : "src",\n' ' { "name" : "src",\n'
' "url" : "%(base)s/src",\n' ' "url" : "%(base)s/src",\n'
' "deps_file" : "DEPS.alt",\n' ' "deps_file" : "DEPS.alt",\n'
' "managed" : True,\n'
' "custom_deps" : {\n' ' "custom_deps" : {\n'
' "src/other2": \'%(base)s/other@2\',\n' ' "src/other2": \'%(base)s/other@2\',\n'
' },\n' ' },\n'

@ -199,7 +199,7 @@ class GclientTest(trial_dir.TestCase):
# Invalid urls causes pain when specifying requirements. Make sure it's # Invalid urls causes pain when specifying requirements. Make sure it's
# auto-fixed. # auto-fixed.
d = gclient.Dependency( d = gclient.Dependency(
None, 'name', 'proto://host/path/@revision', None, None, None, 'name', 'proto://host/path/@revision', None, None, None,
None, '', True) None, '', True)
self.assertEquals('proto://host/path@revision', d.url) self.assertEquals('proto://host/path@revision', d.url)
@ -210,23 +210,25 @@ class GclientTest(trial_dir.TestCase):
options, _ = parser.parse_args([]) options, _ = parser.parse_args([])
obj = gclient.GClient('foo', options) obj = gclient.GClient('foo', options)
obj.dependencies.append( 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( 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( obj.dependencies[0].dependencies.append(
gclient.Dependency( gclient.Dependency(
obj.dependencies[0], 'foo/dir1', 'url', None, None, None, 'DEPS', obj.dependencies[0], 'foo/dir1', 'url', None, None, None, None,
True)) 'DEPS', True))
obj.dependencies[0].dependencies.append( obj.dependencies[0].dependencies.append(
gclient.Dependency( gclient.Dependency(
obj.dependencies[0], 'foo/dir2', obj.dependencies[0], 'foo/dir2',
gclient.GClientKeywords.FromImpl('bar'), None, None, None, 'DEPS', gclient.GClientKeywords.FromImpl('bar'), None, None, None, None,
True)) 'DEPS', True))
obj.dependencies[0].dependencies.append( obj.dependencies[0].dependencies.append(
gclient.Dependency( gclient.Dependency(
obj.dependencies[0], 'foo/dir3', obj.dependencies[0], 'foo/dir3',
gclient.GClientKeywords.FileImpl('url'), None, None, None, 'DEPS', gclient.GClientKeywords.FileImpl('url'), None, None, None, None,
True)) 'DEPS', True))
obj.dependencies[0]._file_list.append('foo') obj.dependencies[0]._file_list.append('foo')
self.assertEquals(434, len(str(obj)), '%d\n%s' % (len(str(obj)), str(obj))) self.assertEquals(434, len(str(obj)), '%d\n%s' % (len(str(obj)), str(obj)))

Loading…
Cancel
Save