Read git submodules within gclient
Design Doc: go/depot-tools-on-submodules
Change-Id: Ic7025a26ace8cb0b46d915909ee1321c6d044797
Bug: 1429149
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4599672
Reviewed-by: Josip Sokcevic <sokcevic@chromium.org>
Commit-Queue: Aravind Vasudevan <aravindvasudev@google.com>
diff --git a/gclient.py b/gclient.py
index 3c8ed83..003afca 100755
--- a/gclient.py
+++ b/gclient.py
@@ -881,6 +881,12 @@
self.local_target_os = local_scope['target_os']
deps = local_scope.get('deps', {})
+
+ # If dependencies are configured within git submodules, add them to DEPS.
+ if self.git_dependencies_state in (gclient_eval.SUBMODULES,
+ gclient_eval.SYNC):
+ deps.update(self.ParseGitSubmodules())
+
deps_to_add = self._deps_to_objects(
self._postprocess_deps(deps, rel_prefix), self._use_relative_paths)
@@ -921,6 +927,65 @@
hooks_cwd=hooks_cwd)
logging.info('ParseDepsFile(%s) done' % self.name)
+ def ParseGitSubmodules(self):
+ # type: () -> Mapping[str, str]
+ """
+ Parses git submodules and returns a dict of path to DEPS git url entries.
+
+ e.g {<path>: <url>@<commit_hash>}
+ """
+ cwd = os.path.join(self.root.root_dir, self.name)
+ filepath = os.path.join(cwd, '.gitmodules')
+ if not os.path.isfile(filepath):
+ logging.warning('ParseGitSubmodules(): No .gitmodules found at %s',
+ filepath)
+ return {}
+
+ # Get submodule commit hashes
+ result = subprocess2.check_output(['git', 'submodule', 'status'],
+ cwd=cwd).decode('utf-8')
+ commit_hashes = {}
+ for record in result.splitlines():
+ commit, module = record.split(maxsplit=1)
+ commit_hashes[module] = commit[1:]
+
+ # Get .gitmodules fields
+ gitmodules_entries = subprocess2.check_output(
+ ['git', 'config', '--file', filepath, '-l']).decode('utf-8')
+
+ gitmodules = {}
+ for entry in gitmodules_entries.splitlines():
+ key, value = entry.split('=', maxsplit=1)
+
+ # git config keys consist of section.name.key, e.g., submodule.foo.path
+ section, submodule_key = key.split('.', maxsplit=1)
+
+ # Only parse [submodule "foo"] sections from .gitmodules.
+ if section != 'submodule':
+ continue
+
+ # The name of the submodule can contain '.', hence split from the back.
+ submodule, sub_key = submodule_key.rsplit('.', maxsplit=1)
+
+ if submodule not in gitmodules:
+ gitmodules[submodule] = {}
+
+ if sub_key in ('url', 'gclient-condition', 'path'):
+ gitmodules[submodule][sub_key] = value
+
+ # Structure git submodules into a dict of DEPS git url entries.
+ submodules = {}
+ for name, module in gitmodules.items():
+ submodules[module['path']] = {
+ 'dep_type': 'git',
+ 'url': '{}@{}'.format(module['url'], commit_hashes[name])
+ }
+
+ if 'gclient-condition' in module:
+ submodules[module['path']]['condition'] = module['gclient-condition']
+
+ return submodules
+
def _get_option(self, attr, default):
obj = self
while not hasattr(obj, '_options'):