gclient: Sync CIPD deps before running hooks.

Bug: 882611
Change-Id: I72646544a164f557ea7d53e0ce0f16d663618a98
Reviewed-on: https://chromium-review.googlesource.com/c/1255446
Reviewed-by: Andrii Shyshkalov <tandrii@chromium.org>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
diff --git a/gclient.py b/gclient.py
index 2b8ae35..f2d90f6 100755
--- a/gclient.py
+++ b/gclient.py
@@ -1563,6 +1563,103 @@
       patch_refs[patch_repo] = patch_ref
     return patch_refs, target_branches
 
+  def _RemoveUnversionedGitDirs(self):
+    """Remove directories that are no longer part of the checkout.
+
+    Notify the user if there is an orphaned entry in their working copy.
+    Only delete the directory if there are no changes in it, and
+    delete_unversioned_trees is set to true.
+    """
+
+    entries = [i.name for i in self.root.subtree(False) if i.url]
+    full_entries = [os.path.join(self.root_dir, e.replace('/', os.path.sep))
+                    for e in entries]
+
+    for entry, prev_url in self._ReadEntries().iteritems():
+      if not prev_url:
+        # entry must have been overridden via .gclient custom_deps
+        continue
+      # Fix path separator on Windows.
+      entry_fixed = entry.replace('/', os.path.sep)
+      e_dir = os.path.join(self.root_dir, entry_fixed)
+      # Use entry and not entry_fixed there.
+      if (entry not in entries and
+          (not any(path.startswith(entry + '/') for path in entries)) and
+          os.path.exists(e_dir)):
+        # The entry has been removed from DEPS.
+        scm = gclient_scm.GitWrapper(
+            prev_url, self.root_dir, entry_fixed, self.outbuf)
+
+        # Check to see if this directory is now part of a higher-up checkout.
+        scm_root = None
+        try:
+          scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(scm.checkout_path)
+        except subprocess2.CalledProcessError:
+          pass
+        if not scm_root:
+          logging.warning('Could not find checkout root for %s. Unable to '
+                          'determine whether it is part of a higher-level '
+                          'checkout, so not removing.' % entry)
+          continue
+
+        # This is to handle the case of third_party/WebKit migrating from
+        # being a DEPS entry to being part of the main project.
+        # If the subproject is a Git project, we need to remove its .git
+        # folder. Otherwise git operations on that folder will have different
+        # effects depending on the current working directory.
+        if os.path.abspath(scm_root) == os.path.abspath(e_dir):
+          e_par_dir = os.path.join(e_dir, os.pardir)
+          if gclient_scm.scm.GIT.IsInsideWorkTree(e_par_dir):
+            par_scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(e_par_dir)
+            # rel_e_dir : relative path of entry w.r.t. its parent repo.
+            rel_e_dir = os.path.relpath(e_dir, par_scm_root)
+            if gclient_scm.scm.GIT.IsDirectoryVersioned(
+                par_scm_root, rel_e_dir):
+              save_dir = scm.GetGitBackupDirPath()
+              # Remove any eventual stale backup dir for the same project.
+              if os.path.exists(save_dir):
+                gclient_utils.rmtree(save_dir)
+              os.rename(os.path.join(e_dir, '.git'), save_dir)
+              # When switching between the two states (entry/ is a subproject
+              # -> entry/ is part of the outer project), it is very likely
+              # that some files are changed in the checkout, unless we are
+              # jumping *exactly* across the commit which changed just DEPS.
+              # In such case we want to cleanup any eventual stale files
+              # (coming from the old subproject) in order to end up with a
+              # clean checkout.
+              gclient_scm.scm.GIT.CleanupDir(par_scm_root, rel_e_dir)
+              assert not os.path.exists(os.path.join(e_dir, '.git'))
+              print(('\nWARNING: \'%s\' has been moved from DEPS to a higher '
+                     'level checkout. The git folder containing all the local'
+                     ' branches has been saved to %s.\n'
+                     'If you don\'t care about its state you can safely '
+                     'remove that folder to free up space.') %
+                    (entry, save_dir))
+              continue
+
+        if scm_root in full_entries:
+          logging.info('%s is part of a higher level checkout, not removing',
+                       scm.GetCheckoutRoot())
+          continue
+
+        file_list = []
+        scm.status(self._options, [], file_list)
+        modified_files = file_list != []
+        if (not self._options.delete_unversioned_trees or
+            (modified_files and not self._options.force)):
+          # There are modified files in this entry. Keep warning until
+          # removed.
+          print(('\nWARNING: \'%s\' is no longer part of this client.  '
+                 'It is recommended that you manually remove it.\n') %
+                    entry_fixed)
+        else:
+          # Delete the entry
+          print('\n________ deleting \'%s\' in \'%s\'' % (
+              entry_fixed, self.root_dir))
+          gclient_utils.rmtree(e_dir)
+    # record the current list of entries for next time
+    self._SaveEntries()
+
   def RunOnDeps(self, command, args, ignore_requirements=False, progress=True):
     """Runs a command on each dependency in a client and its dependencies.
 
@@ -1624,103 +1721,7 @@
       if gn_args_dep and gn_args_dep.HasGNArgsFile():
         gn_args_dep.WriteGNArgsFile()
 
-    if not self._options.nohooks:
-      if should_show_progress:
-        pm = Progress('Running hooks', 1)
-      self.RunHooksRecursively(self._options, pm)
-
-    if command == 'update':
-      # Notify the user if there is an orphaned entry in their working copy.
-      # Only delete the directory if there are no changes in it, and
-      # delete_unversioned_trees is set to true.
-      entries = [i.name for i in self.root.subtree(False) if i.url]
-      full_entries = [os.path.join(self.root_dir, e.replace('/', os.path.sep))
-                      for e in entries]
-
-      for entry, prev_url in self._ReadEntries().iteritems():
-        if not prev_url:
-          # entry must have been overridden via .gclient custom_deps
-          continue
-        # Fix path separator on Windows.
-        entry_fixed = entry.replace('/', os.path.sep)
-        e_dir = os.path.join(self.root_dir, entry_fixed)
-        # Use entry and not entry_fixed there.
-        if (entry not in entries and
-            (not any(path.startswith(entry + '/') for path in entries)) and
-            os.path.exists(e_dir)):
-          # The entry has been removed from DEPS.
-          scm = gclient_scm.GitWrapper(
-              prev_url, self.root_dir, entry_fixed, self.outbuf)
-
-          # Check to see if this directory is now part of a higher-up checkout.
-          scm_root = None
-          try:
-            scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(scm.checkout_path)
-          except subprocess2.CalledProcessError:
-            pass
-          if not scm_root:
-            logging.warning('Could not find checkout root for %s. Unable to '
-                            'determine whether it is part of a higher-level '
-                            'checkout, so not removing.' % entry)
-            continue
-
-          # This is to handle the case of third_party/WebKit migrating from
-          # being a DEPS entry to being part of the main project.
-          # If the subproject is a Git project, we need to remove its .git
-          # folder. Otherwise git operations on that folder will have different
-          # effects depending on the current working directory.
-          if os.path.abspath(scm_root) == os.path.abspath(e_dir):
-            e_par_dir = os.path.join(e_dir, os.pardir)
-            if gclient_scm.scm.GIT.IsInsideWorkTree(e_par_dir):
-              par_scm_root = gclient_scm.scm.GIT.GetCheckoutRoot(e_par_dir)
-              # rel_e_dir : relative path of entry w.r.t. its parent repo.
-              rel_e_dir = os.path.relpath(e_dir, par_scm_root)
-              if gclient_scm.scm.GIT.IsDirectoryVersioned(
-                  par_scm_root, rel_e_dir):
-                save_dir = scm.GetGitBackupDirPath()
-                # Remove any eventual stale backup dir for the same project.
-                if os.path.exists(save_dir):
-                  gclient_utils.rmtree(save_dir)
-                os.rename(os.path.join(e_dir, '.git'), save_dir)
-                # When switching between the two states (entry/ is a subproject
-                # -> entry/ is part of the outer project), it is very likely
-                # that some files are changed in the checkout, unless we are
-                # jumping *exactly* across the commit which changed just DEPS.
-                # In such case we want to cleanup any eventual stale files
-                # (coming from the old subproject) in order to end up with a
-                # clean checkout.
-                gclient_scm.scm.GIT.CleanupDir(par_scm_root, rel_e_dir)
-                assert not os.path.exists(os.path.join(e_dir, '.git'))
-                print(('\nWARNING: \'%s\' has been moved from DEPS to a higher '
-                       'level checkout. The git folder containing all the local'
-                       ' branches has been saved to %s.\n'
-                       'If you don\'t care about its state you can safely '
-                       'remove that folder to free up space.') %
-                      (entry, save_dir))
-                continue
-
-          if scm_root in full_entries:
-            logging.info('%s is part of a higher level checkout, not removing',
-                         scm.GetCheckoutRoot())
-            continue
-
-          file_list = []
-          scm.status(self._options, [], file_list)
-          modified_files = file_list != []
-          if (not self._options.delete_unversioned_trees or
-              (modified_files and not self._options.force)):
-            # There are modified files in this entry. Keep warning until
-            # removed.
-            print(('\nWARNING: \'%s\' is no longer part of this client.  '
-                   'It is recommended that you manually remove it.\n') %
-                      entry_fixed)
-          else:
-            # Delete the entry
-            print('\n________ deleting \'%s\' in \'%s\'' % (
-                entry_fixed, self.root_dir))
-            gclient_utils.rmtree(e_dir)
-      # record the current list of entries for next time
-      self._SaveEntries()
+      self._RemoveUnversionedGitDirs()
 
     # Sync CIPD dependencies once removed deps are deleted. In case a git
     # dependency was moved to CIPD, we want to remove the old git directory
@@ -1728,6 +1729,12 @@
     if self._cipd_root:
       self._cipd_root.run(command)
 
+    if not self._options.nohooks:
+      if should_show_progress:
+        pm = Progress('Running hooks', 1)
+      self.RunHooksRecursively(self._options, pm)
+
+
     return 0
 
   def PrintRevInfo(self):