Use git_dependencies variable in gitlink check

The old implementation was written before gclient got git_dependencies
property. Instead of relying on arbitrary string, use actual content of
git_dependencies.

R=jojwang@google.com

Change-Id: Iea90e531ac6e9a9aaf58ca1dc73347692448107a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/4818788
Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
Reviewed-by: Joanna Wang <jojwang@chromium.org>
changes/88/4818788/3
Josip Sokcevic 2 years ago committed by LUCI CQ
parent cea35a3f77
commit a83906be85

@ -1699,21 +1699,18 @@ def CheckCIPDClientDigests(input_api, output_api, client_version_file):
def CheckForCommitObjects(input_api, output_api):
"""Validates that there are no commit objects in the repository.
"""Validates that commit objects match DEPS.
Commit objects are put into the git tree typically by submodule tooling.
Because we use gclient to handle external repository references instead,
we want to avoid this. Having commit objects in the tree can confuse git
tooling in some scenarios into thinking that the tree is dirty (e.g. the
presence of a DEPS subrepo at a location where a commit object is stored
in the tree).
we want to ensure DEPS content and Git are in sync when desired.
Args:
input_api: Bag of input related interfaces.
output_api: Bag of output related interfaces.
Returns:
A presubmit error if a commit object is present in the tree.
A presubmit error if a commit object is not expected.
"""
def parse_tree_entry(ent):
@ -1730,68 +1727,96 @@ def CheckForCommitObjects(input_api, output_api):
return (spaceparts[0], spaceparts[1], spaceparts[2], tabparts[1])
full_tree = input_api.subprocess.check_output(
['git', 'ls-tree', '-r', '--full-tree', 'HEAD'],
cwd=input_api.PresubmitLocalPath()
).decode('utf8')
# deps_entry holds tree entry for the root DEPS file.
deps_entry = None
['git', 'ls-tree', '-r', '--full-tree', '-z', 'HEAD'],
cwd=input_api.PresubmitLocalPath())
# commit_tree_entries holds all commit entries (ie gitlink, submodule record).
commit_tree_entries = []
for entry in full_tree.strip().split('\n'):
tree_entry = parse_tree_entry(entry)
for entry in full_tree.strip().split(b'\00'):
if not entry.startswith(b'160000'):
# Remove entries that we don't care about. 160000 indicates a gitlink.
continue
tree_entry = parse_tree_entry(entry.decode('utf-8'))
if tree_entry[1] == 'commit':
commit_tree_entries.append(tree_entry)
if tree_entry[3] == 'DEPS':
deps_entry = tree_entry
if len(commit_tree_entries) > 0:
if not deps_entry:
# No DEPS file, carry on!
return []
# This gets DEPS file from HEAD (the same as local DEPS file if there's no
# modification).
deps_content = input_api.subprocess.check_output(
['git', 'cat-file', 'blob', deps_entry[2]],
cwd=input_api.PresubmitLocalPath()).decode('utf8')
if 'use_git_submodules' in deps_content:
# git submodule is source of truth, so no further action needed.
return []
if not 'SUBMODULE_MIGRATION' in deps_content:
commit_tree_entries = [x[3] for x in commit_tree_entries]
return [
output_api.PresubmitError(
'Commit objects present within tree.\n'
'This may be due to submodule-related interactions;\n'
'the presence of a commit object in the tree may lead to odd\n'
'situations where files are inconsistently checked-out.\n'
'Remove these commit entries and validate your changeset '
'again:\n', commit_tree_entries)
]
mismatch_entries = []
deps_msg = ""
for commit_tree_entry in commit_tree_entries:
# Search for commit hashes in DEPS file - they must be present
if commit_tree_entry[2] not in deps_content:
mismatch_entries.append(commit_tree_entry[3])
deps_msg += f"\n {commit_tree_entry[3]} -> {commit_tree_entry[2]}"
if mismatch_entries:
return [
output_api.PresubmitError(
'DEPS file indicates git submodule migration is in progress,\n'
'but the commit objects do not match DEPS entries.\n\n'
'To reset all git submodule git entries to match DEPS, run\n'
'the following command in the root of this repository:\n'
' gclient gitmodules'
'\n\n'
'If git submodule changes are correct, update the following DEPS '
'entries to: ' + deps_msg)
]
# No gitlinks found, return early.
if len(commit_tree_entries) == 0:
return []
return []
# This gets DEPS file.
deps_file = input_api.os_path.join(input_api.PresubmitLocalPath(), 'DEPS')
if not input_api.os_path.isfile(deps_file):
# No DEPS file, carry on!
return []
with open(deps_file) as f:
deps_content = f.read()
deps = _ParseDeps(deps_content)
if not 'git_dependencies' in deps or deps['git_dependencies'] == 'DEPS':
commit_tree_entries = [x[3] for x in commit_tree_entries]
return [
output_api.PresubmitError(
'Commit objects present within tree.\n'
'This may be due to submodule-related interactions;\n'
'the presence of a commit object in the tree may lead to odd\n'
'situations where files are inconsistently checked-out.\n'
'Remove these commit entries and validate your changeset '
'again:\n', commit_tree_entries)
]
if deps['git_dependencies'] == 'SUBMODULES':
# git submodule is source of truth, so no further action needed.
return []
assert deps['git_dependencies'] == 'SYNC', 'unexpected git_dependencies.'
mismatch_entries = []
deps_msg = ""
for commit_tree_entry in commit_tree_entries:
# Search for commit hashes in DEPS file - they must be present
if commit_tree_entry[2] not in deps_content:
mismatch_entries.append(commit_tree_entry[3])
deps_msg += f"\n {commit_tree_entry[3]} -> {commit_tree_entry[2]}"
if mismatch_entries:
return [
output_api.PresubmitError(
'DEPS file indicates git submodule migration is in progress,\n'
'but the commit objects do not match DEPS entries.\n\n'
'To reset all git submodule git entries to match DEPS, run\n'
'the following command in the root of this repository:\n'
' gclient gitmodules'
'\n\n'
'If git submodule changes are correct, update the following DEPS '
'entries to: ' + deps_msg)
]
def _ParseDeps(contents):
"""Simple helper for parsing DEPS files."""
# Stubs for handling special syntax in the root DEPS file.
class _VarImpl:
def __init__(self, local_scope):
self._local_scope = local_scope
def Lookup(self, var_name):
"""Implements the Var syntax."""
try:
return self._local_scope['vars'][var_name]
except KeyError:
raise Exception('Var is not defined: %s' % var_name)
local_scope = {}
global_scope = {
'Var': _VarImpl(local_scope).Lookup,
'Str': str,
}
exec(contents, global_scope, local_scope)
return local_scope
def CheckVPythonSpec(input_api, output_api, file_filter=None):

Loading…
Cancel
Save