mirror of
https://chromium.googlesource.com/chromium/tools/depot_tools.git
synced 2026-01-11 10:41:31 +00:00
Reland "[gclient] Read submodule status information
This reverts commit 58ff1badf9.
This change also restricts diff only to changes that are submodule related by
utilizing patch diff search.
Original change's description:
> [gclient] Read submodule status information
>
> This allow us to skip sync if we know the state is correct.
>
> R=gavinmak@google.com
>
> Bug: 40283612, 40942309
> Change-Id: I30fd5bfb9ca8ab0f7dcce567e2a5cb4aebdc7b2f
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5480172
> Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
> Reviewed-by: Gavin Mak <gavinmak@google.com>
Bug: 40283612, 40942309
Change-Id: Iac7ed8c927de1a03a3d60dd50108ddb0b6d96c7e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/5513190
Reviewed-by: Gavin Mak <gavinmak@google.com>
Commit-Queue: Josip Sokcevic <sokcevic@chromium.org>
This commit is contained in:
@@ -229,6 +229,7 @@ class GitWrapper(SCMWrapper):
|
||||
filter_kwargs['predicate'] = self.out_cb
|
||||
self.filter = gclient_utils.GitFilter(**filter_kwargs)
|
||||
self._running_under_rosetta = None
|
||||
self.current_revision = None
|
||||
|
||||
def GetCheckoutRoot(self):
|
||||
return scm.GIT.GetCheckoutRoot(self.checkout_path)
|
||||
@@ -250,6 +251,75 @@ class GitWrapper(SCMWrapper):
|
||||
['-c', 'core.quotePath=false', 'diff', '--name-only', base])
|
||||
)).split()
|
||||
|
||||
def GetSubmoduleStateFromIndex(self):
|
||||
"""Returns a map where keys are submodule names and values are commit
|
||||
hashes. It reads data from the Git index, so only committed values are
|
||||
present."""
|
||||
out = self._Capture(['ls-files', '-s'])
|
||||
result = {}
|
||||
for l in out.split('\n'):
|
||||
if not l.startswith('160000'):
|
||||
# Not a submodule
|
||||
continue
|
||||
(_, commit, _, filepath) = l.split(maxsplit=3)
|
||||
result[filepath] = commit
|
||||
return result
|
||||
|
||||
def GetSubmoduleDiff(self):
|
||||
"""Returns a map where keys are submodule names and values are tuples of
|
||||
(old_commit_hash, new_commit_hash). old_commit_hash matches the Git
|
||||
index, whereas new_commit_hash matches currently checked out commit
|
||||
hash."""
|
||||
out = self._Capture([
|
||||
'diff',
|
||||
'--no-prefix',
|
||||
'--no-ext-diff',
|
||||
'--no-color',
|
||||
'--ignore-submodules=dirty',
|
||||
'--submodule=short',
|
||||
'-G',
|
||||
'Subproject commit',
|
||||
])
|
||||
NO_COMMIT = 40 * '0'
|
||||
committed_submodule = None
|
||||
checked_submodule = None
|
||||
filepath = None
|
||||
state = 0
|
||||
diff = {}
|
||||
# Parsing git diff uses simple state machine. States:
|
||||
# 0 - start state
|
||||
# 1 - diff file/line detected, ready to process content
|
||||
# 2 - gitlink detected, ready to process gitlink past and current
|
||||
# content.
|
||||
# 3 - past gitlink content detected. It contains a commit hash that's in
|
||||
# git index.
|
||||
# 4 - new gitlink content detected. It contains currently checked
|
||||
# commit. At this point, we have all information needed, and we can
|
||||
# reset state to 0.
|
||||
for l in out.split('\n'):
|
||||
if l.startswith('diff --git'):
|
||||
# New file detected, reset state.
|
||||
state = 1
|
||||
elif state == 1 and l.startswith('index') and l.endswith('160000'):
|
||||
# We detected gitlink
|
||||
state = 2
|
||||
elif state == 2 and l.startswith('+++ '):
|
||||
# This line contains filename
|
||||
filepath = l[4:]
|
||||
state = 3
|
||||
elif state == 3 and l.startswith('-Subproject commit '):
|
||||
# This line contains what commit hash Git index expects
|
||||
# (ls-files).
|
||||
committed_submodule = l.split(' ')[-1]
|
||||
state = 4
|
||||
elif state == 4 and l.startswith('+Subproject commit '):
|
||||
# This line contains currently checked out commit for this submodule.
|
||||
checked_submodule = l.split(' ')[-1]
|
||||
if NO_COMMIT not in (committed_submodule, checked_submodule):
|
||||
diff[filepath] = (committed_submodule, checked_submodule)
|
||||
state = 0
|
||||
return diff
|
||||
|
||||
def diff(self, options, _args, _file_list):
|
||||
_, revision = gclient_utils.SplitUrlRevision(self.url)
|
||||
if not revision:
|
||||
@@ -638,7 +708,6 @@ class GitWrapper(SCMWrapper):
|
||||
raise gclient_utils.Error("Unsupported argument(s): %s" %
|
||||
",".join(args))
|
||||
|
||||
current_revision = None
|
||||
url, deps_revision = gclient_utils.SplitUrlRevision(self.url)
|
||||
revision = deps_revision
|
||||
managed = True
|
||||
@@ -714,11 +783,11 @@ class GitWrapper(SCMWrapper):
|
||||
self._UpdateMirrorIfNotContains(mirror, options, rev_type,
|
||||
revision)
|
||||
try:
|
||||
current_revision = self._Clone(revision, url, options)
|
||||
self.current_revision = self._Clone(revision, url, options)
|
||||
except subprocess2.CalledProcessError as e:
|
||||
logging.warning('Clone failed due to: %s', e)
|
||||
self._DeleteOrMove(options.force)
|
||||
current_revision = self._Clone(revision, url, options)
|
||||
self.current_revision = self._Clone(revision, url, options)
|
||||
if file_list is not None:
|
||||
files = self._Capture(
|
||||
['-c', 'core.quotePath=false', 'ls-files']).splitlines()
|
||||
@@ -742,6 +811,17 @@ class GitWrapper(SCMWrapper):
|
||||
self.relpath)
|
||||
return self._Capture(['rev-parse', '--verify', 'HEAD'])
|
||||
|
||||
# Special case for rev_type = hash. If we use submodules, we can check
|
||||
# information already.
|
||||
if rev_type == 'hash':
|
||||
if self.current_revision == revision:
|
||||
if verbose:
|
||||
self.Print('Using submodule information to skip check')
|
||||
if options.reset or options.force:
|
||||
self._Scrub('HEAD', options)
|
||||
|
||||
return revision
|
||||
|
||||
self._maybe_break_locks(options)
|
||||
|
||||
if mirror:
|
||||
|
||||
Reference in New Issue
Block a user