gclient: add gitmodules command to update/add submodules based on DEPS.

Bug: 1421776
Change-Id: Id1ac48c4b65c17027fa24d0ba350a1a7f2eec64d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4665787
Commit-Queue: Joanna Wang <jojwang@chromium.org>
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
changes/87/4665787/12
Joanna Wang 2 years ago committed by LUCI CQ
parent d6f65bfa32
commit 3ab2f21289

@ -115,6 +115,7 @@ from third_party.repo.progress import Progress
import subcommand
import subprocess2
import setup_color
import git_cl
from third_party import six
@ -2654,6 +2655,67 @@ class Flattener(object):
self._flatten_dep(d)
@metrics.collector.collect_metrics('gclient gitmodules')
def CMDgitmodules(parser, args):
"""Adds or updates Git Submodules based on the contents of the DEPS file.
This command should be run in the root director of the repo.
It will create or update the .gitmodules file and include
`gclient-condition` values. Commits in gitlinks will also be updated.
"""
parser.add_option('--output-gitmodules',
help='name of the .gitmodules file to write to',
default='.gitmodules')
parser.add_option(
'--deps-file',
help=
'name of the deps file to parse for git dependency paths and commits.',
default='DEPS')
parser.add_option(
'--skip-dep',
action="append",
help='skip adding gitmodules for the git dependency at the given path',
default=[])
options, args = parser.parse_args(args)
deps_dir = os.path.dirname(os.path.abspath(options.deps_file))
gclient_path = gclient_paths.FindGclientRoot(deps_dir)
if not gclient_path:
logging.error(
'.gclient not found\n'
'Make sure you are running this script from a gclient workspace.')
sys.exit(1)
deps_content = gclient_utils.FileRead(options.deps_file)
ls = gclient_eval.Parse(deps_content, options.deps_file, None, None)
prefix_length = 0
if not 'use_relative_paths' in ls or ls['use_relative_paths'] != True:
delta_path = os.path.relpath(deps_dir, os.path.abspath(gclient_path))
if delta_path:
prefix_length = len(delta_path.replace(os.path.sep, '/')) + 1
with open(options.output_gitmodules, 'w') as f:
for path, dep in ls.get('deps').items():
if path in options.skip_dep:
continue
if dep.get('dep_type') == 'cipd':
continue
try:
url, commit = dep['url'].split('@', maxsplit=1)
except ValueError:
logging.error('error on %s; %s, not adding it', path, dep["url"])
continue
if prefix_length:
path = path[prefix_length:]
git_cl.RunGit(
['update-index', '--add', '--cacheinfo', '160000', commit, path])
f.write(f'[submodule "{path}"]\n\tpath = {path}\n\turl = {url}\n')
if 'condition' in dep:
f.write(f'\tgclient-condition = {dep["condition"]}\n')
@metrics.collector.collect_metrics('gclient flatten')
def CMDflatten(parser, args):
"""Flattens the solutions into a single DEPS file."""

@ -212,7 +212,7 @@ class FakeReposBase(object):
class FakeRepos(FakeReposBase):
"""Implements populateGit()."""
NB_GIT_REPOS = 18
NB_GIT_REPOS = 20
def populateGit(self):
# Testing:
@ -759,6 +759,73 @@ hooks = [{
'git/repo_18@2\n'
})
# a relative path repo
self._commit_git(
'repo_19', {
'DEPS': """
git_dependencies = "SUBMODULES"
use_relative_paths = True
vars = {
'foo_checkout': True,
}
deps = {
"some_repo": {
"url": '/repo_2@%(hash_2)s',
"condition": "not foo_checkout",
},
"chicken/dickens": {
"url": '/repo_3@%(hash_3)s',
},
"weird/deps": {
"url": '/repo_1'
},
"bar": {
"packages": [{
"package": "lemur",
"version": "version:1234",
}],
"dep_type": "cipd",
},
}""" % {
'hash_2': self.git_hashes['repo_2'][1][0],
'hash_3': self.git_hashes['repo_3'][1][0],
},
})
# a non-relative_path repo
self._commit_git(
'repo_20', {
'DEPS': """
git_dependencies = "SUBMODULES"
vars = {
'foo_checkout': True,
}
deps = {
"foo/some_repo": {
"url": '/repo_2@%(hash_2)s',
"condition": "not foo_checkout",
},
"foo/chicken/dickens": {
"url": '/repo_3@%(hash_3)s',
},
"foo/weird/deps": {
"url": '/repo_1'
},
"foo/bar": {
"packages": [{
"package": "lemur",
"version": "version:1234",
}],
"dep_type": "cipd",
},
}""" % {
'hash_2': self.git_hashes['repo_2'][1][0],
'hash_3': self.git_hashes['repo_3'][1][0],
},
})
class FakeRepoSkiaDEPS(FakeReposBase):
"""Simulates the Skia DEPS transition in Chrome."""

@ -32,6 +32,44 @@ class GClientSmokeGIT(gclient_smoketest_base.GClientSmokeBase):
if not self.enabled:
self.skipTest('git fake repos not available')
def testGitmodules_relative(self):
self.gclient(['config', self.git_base + 'repo_19', '--name', 'dir'],
cwd=self.git_base + 'repo_19')
self.gclient(['sync'], cwd=self.git_base + 'repo_19')
self.gclient(['gitmodules'],
cwd=self.git_base + os.path.join('repo_19', 'dir'))
gitmodules = os.path.join(self.git_base, 'repo_19', 'dir', '.gitmodules')
with open(gitmodules) as f:
contents = f.read().splitlines()
self.assertEqual([
'[submodule "some_repo"]', '\tpath = some_repo', '\turl = /repo_2',
'\tgclient-condition = not foo_checkout',
'[submodule "chicken/dickens"]', '\tpath = chicken/dickens',
'\turl = /repo_3'
], contents)
def testGitmodules_not_relative(self):
self.gclient(['config', self.git_base + 'repo_20', '--name', 'foo'],
cwd=self.git_base + 'repo_20')
self.gclient(['sync'], cwd=self.git_base + 'repo_20')
self.gclient(['gitmodules'],
cwd=self.git_base + os.path.join('repo_20', 'foo'))
gitmodules = os.path.join(self.git_base, 'repo_20', 'foo', '.gitmodules')
with open(gitmodules) as f:
contents = f.read().splitlines()
self.assertEqual([
'[submodule "some_repo"]', '\tpath = some_repo', '\turl = /repo_2',
'\tgclient-condition = not foo_checkout',
'[submodule "chicken/dickens"]', '\tpath = chicken/dickens',
'\turl = /repo_3'
], contents)
def testGitmodules_not_in_gclient(self):
with self.assertRaisesRegex(AssertionError, 'from a gclient workspace'):
self.gclient(['gitmodules'], cwd=self.root_dir)
def testSync(self):
self.gclient(['config', self.git_base + 'repo_1', '--name', 'src'])
# Test unversioned checkout.

Loading…
Cancel
Save