Fix project import rollback

Deleting directory from file system is not enough to properly remove
repository. We have to invalidate caches and send an event to notify
rest of the system.

Bug: Issue 11343
Change-Id: I03344c4dad52ac8994cd4c1b4ff875ea9231fb64
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
index bcfc117..44b24cb 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/git/GitCloneStep.java
@@ -14,8 +14,14 @@
 package com.googlesource.gerrit.plugins.github.git;
 
 import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.changes.NotifyHandling;
+import com.google.gerrit.extensions.events.ProjectDeletedListener;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.util.ManualRequestContext;
 import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.gwtorm.server.OrmException;
@@ -29,6 +35,8 @@
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,6 +50,9 @@
   private final String organisation;
   private final String repository;
   private final File destinationDirectory;
+  private final DynamicSet<ProjectDeletedListener> deletedListeners;
+  private final ProjectCache projectCache;
+  private final GitRepositoryManager repoManager;
 
   public interface Factory {
     GitCloneStep create(
@@ -54,6 +65,9 @@
       GitHubRepository.Factory gitHubRepoFactory,
       GerritApi gerritApi,
       OneOffRequestContext context,
+      DynamicSet<ProjectDeletedListener> deletedListeners,
+      ProjectCache projectCache,
+      GitRepositoryManager repoManager,
       @Assisted("organisation") String organisation,
       @Assisted("name") String repository)
       throws GitException {
@@ -67,6 +81,9 @@
     this.organisation = organisation;
     this.repository = repository;
     this.destinationDirectory = prepareTargetGitDirectory(gitDir, organisation, repository);
+    this.deletedListeners = deletedListeners;
+    this.projectCache = projectCache;
+    this.repoManager = repoManager;
   }
 
   private static File prepareTargetGitDirectory(File gitDir, String organisation, String repository)
@@ -123,11 +140,44 @@
     }
 
     try {
+      String projectName = organisation + "/" + repository;
+      Project.NameKey key = new Project.NameKey(projectName);
+      cleanJGitCache(key);
       FileUtils.deleteDirectory(gitDirectory);
+      projectCache.remove(key);
+      sendProjectDeletedEvent(projectName);
       return true;
     } catch (IOException e) {
       LOG.error("Cannot clean-up output Git directory " + gitDirectory);
       return false;
     }
   }
+
+  private void cleanJGitCache(Project.NameKey key) throws IOException {
+    try (Repository repository = repoManager.openRepository(key)) {
+      RepositoryCache.close(repository);
+    }
+  }
+
+  private void sendProjectDeletedEvent(String projectName) {
+    ProjectDeletedListener.Event event =
+        new ProjectDeletedListener.Event() {
+          @Override
+          public String getProjectName() {
+            return projectName;
+          }
+
+          @Override
+          public NotifyHandling getNotify() {
+            return NotifyHandling.NONE;
+          }
+        };
+    for (ProjectDeletedListener l : deletedListeners) {
+      try {
+        l.onProjectDeleted(event);
+      } catch (RuntimeException e) {
+        LOG.warn("Failure in ProjectDeletedListener", e);
+      }
+    }
+  }
 }