Support cleanup of projects that are checked out to multiple paths.

Currently if the same project is checked out to multiple locations, we
may delete the project without deleting all the places that the project
is checked out. Fix that.

BUG=chromium:333044, chromium:348870
TEST=All unit tests. Trybot run with official.xml manifest.

Change-Id: Ic6b481f20f74243d53ccd9258f9b65a488dfaf80
Previous-Reviewed-on: https://chromium-review.googlesource.com/182074
(cherry picked from commit ceafa0f3b437a97aa3049d95881f2284b7d1404f)
Reviewed-on: https://chromium-review.googlesource.com/188668
Reviewed-by: Matt Tennant <mtennant@chromium.org>
Tested-by: David James <davidjames@chromium.org>
diff --git a/buildbot/cbuildbot_commands.py b/buildbot/cbuildbot_commands.py
index 68a83f6..f6d73ee 100644
--- a/buildbot/cbuildbot_commands.py
+++ b/buildbot/cbuildbot_commands.py
@@ -162,6 +162,7 @@
     buildroot: buildroot to clean up.
   """
   lock_path = os.path.join(buildroot, '.clean_lock')
+  deleted_paths = multiprocessing.Event()
 
   def RunCleanupCommands(project, cwd):
     with locking.FileLock(lock_path, verbose=False).read_lock() as lock:
@@ -180,6 +181,7 @@
         logging.warn('\n%s', result.error)
         logging.warn('Deleting %s because %s failed', cwd, e.result.cmd)
         lock.write_lock()
+        deleted_paths.set()
         osutils.RmDir(cwd, ignore_missing=True)
         # Delete the backing stores as well.
         for store in (repo_git_store, repo_obj_store):
@@ -196,6 +198,13 @@
           git.ManifestCheckout.Cached(buildroot).ListCheckouts()]
   parallel.RunTasksInProcessPool(RunCleanupCommands, dirs)
 
+  # repo shares git object directories amongst multiple project paths. If the
+  # first pass deleted an object dir for a project path, then other repositories
+  # (project paths) of that same project may now be broken. Do a second pass to
+  # clean them up as well.
+  if deleted_paths.is_set():
+    parallel.RunTasksInProcessPool(RunCleanupCommands, dirs)
+
 
 def CleanUpMountPoints(buildroot):
   """Cleans up any stale mount points from previous runs."""