Extract replay revisions logic into own import step

Change-Id: I6ac0a8d1b9531d09ca4cf0181bbfed82a62583e5
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
index 4ffeabe..7ce81b1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/Module.java
@@ -45,5 +45,6 @@
     bind(GitFetchStep.class);
     bind(AccountUtil.class);
     install(new FactoryModuleBuilder().build(ReplayChangesStep.Factory.class));
+    install(new FactoryModuleBuilder().build(ReplayRevisionsStep.Factory.class));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
index bd7c099..df3f878 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayChangesStep.java
@@ -29,7 +29,6 @@
 import com.google.gerrit.extensions.common.ChangeMessageInfo;
 import com.google.gerrit.extensions.common.CommentInfo;
 import com.google.gerrit.extensions.common.LabelInfo;
-import com.google.gerrit.extensions.common.RevisionInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
@@ -38,9 +37,7 @@
 import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.reviewdb.client.PatchSetInfo;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.RevId;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.ChangeMessagesUtil;
 import com.google.gerrit.server.ChangeUtil;
@@ -52,7 +49,6 @@
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gerrit.server.index.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeUpdate;
-import com.google.gerrit.server.patch.PatchSetInfoFactory;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.validators.ValidationException;
@@ -62,10 +58,7 @@
 import com.google.inject.assistedinject.Assisted;
 
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.RefUpdate;
 import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 
 import java.io.IOException;
@@ -90,10 +83,10 @@
         Project.NameKey name);
   }
 
+  private final ReplayRevisionsStep.Factory replayRevisionsFactory;
   private final AccountUtil accountUtil;
   private final ReviewDb db;
   private final ChangeIndexer indexer;
-  private final PatchSetInfoFactory patchSetInfoFactory;
   private final Provider<PostReview> postReview;
   private final ChangeUpdate.Factory updateFactory;
   private final ChangeMessagesUtil cmUtil;
@@ -108,10 +101,10 @@
 
   @Inject
   ReplayChangesStep(
+      ReplayRevisionsStep.Factory replayRevisionsFactory,
       AccountUtil accountUtil,
       ReviewDb db,
       ChangeIndexer indexer,
-      PatchSetInfoFactory patchSetInfoFactory,
       Provider<PostReview> postReview,
       ChangeUpdate.Factory updateFactory,
       ChangeMessagesUtil cmUtil,
@@ -124,10 +117,10 @@
       @Assisted("password") String password,
       @Assisted Repository repo,
       @Assisted Project.NameKey name) {
+    this.replayRevisionsFactory = replayRevisionsFactory;
     this.accountUtil = accountUtil;
     this.db = db;
     this.indexer = indexer;
-    this.patchSetInfoFactory = patchSetInfoFactory;
     this.postReview = postReview;
     this.updateFactory = updateFactory;
     this.cmUtil = cmUtil;
@@ -159,7 +152,7 @@
       throws IOException, OrmException, NoSuchAccountException,
       NoSuchChangeException, RestApiException, ValidationException {
     Change change = createChange(c);
-    replayRevisions(rw, change, c);
+    replayRevisionsFactory.create(repo, rw, change, c).replay();
     db.changes().insert(Collections.singleton(change));
 
     replayInlineComments(change, c);
@@ -193,57 +186,6 @@
     }
   }
 
-  private void replayRevisions(RevWalk rw, Change change,
-      ChangeInfo c) throws IOException, OrmException, NoSuchAccountException {
-    List<RevisionInfo> revisions = new ArrayList<>(c.revisions.values());
-    sortRevisionInfoByNumber(revisions);
-    List<PatchSet> patchSets = new ArrayList<>();
-
-    db.changes().beginTransaction(change.getId());
-    try {
-      for (RevisionInfo r : revisions) {
-        String origRef = r.ref;
-        ObjectId id = repo.resolve(origRef);
-        if (id == null) {
-          // already replayed?
-          continue;
-        }
-        RevCommit commit = rw.parseCommit(id);
-
-        PatchSet ps = new PatchSet(new PatchSet.Id(change.getId(), r._number));
-        patchSets.add(ps);
-
-        ps.setUploader(accountUtil.resolveUser(r.uploader));
-        ps.setCreatedOn(r.created);
-        ps.setRevision(new RevId(commit.name()));
-        ps.setDraft(r.draft != null && r.draft);
-
-        PatchSetInfo info = patchSetInfoFactory.get(commit, ps.getId());
-        if (c.currentRevision.equals(info.getRevId())) {
-          change.setCurrentPatchSet(info);
-        }
-
-        ChangeUtil.insertAncestors(db, ps.getId(), commit);
-
-        renameRef(repo, origRef, ps);
-      }
-
-      db.patchSets().insert(patchSets);
-      db.commit();
-    } finally {
-      db.rollback();
-    }
-  }
-
-  private static void sortRevisionInfoByNumber(List<RevisionInfo> list) {
-    Collections.sort(list, new Comparator<RevisionInfo>() {
-      @Override
-      public int compare(RevisionInfo a, RevisionInfo b) {
-        return a._number - b._number;
-      }
-    });
-  }
-
   private void replayInlineComments(Change change, ChangeInfo c) throws OrmException,
       RestApiException, IOException, NoSuchChangeException,
       NoSuchAccountException {
@@ -308,49 +250,6 @@
         input, ts);
   }
 
-  private void renameRef(Repository repo, String origRef, PatchSet ps)
-      throws IOException {
-    String ref = ps.getId().toRefName();
-    if (ref.equals(origRef)) {
-      return;
-    }
-
-    createRef(repo, ps);
-    deleteRef(repo, ps, origRef);
-  }
-
-  private void createRef(Repository repo, PatchSet ps) throws IOException {
-    String ref = ps.getId().toRefName();
-    RefUpdate ru = repo.updateRef(ref);
-    ru.setForceUpdate(true);
-    ru.setExpectedOldObjectId(ObjectId.zeroId());
-    ru.setNewObjectId(ObjectId.fromString(ps.getRevision().get()));
-    RefUpdate.Result result = ru.update();
-    switch (result) {
-      case NEW:
-      case FORCED:
-      case FAST_FORWARD:
-        return;
-      default:
-        throw new IOException(String.format("Failed to create ref %s", ref));
-    }
-  }
-
-  private void deleteRef(Repository repo, PatchSet ps, String ref)
-      throws IOException {
-    RefUpdate ru = repo.updateRef(ref);
-    ru.setForceUpdate(true);
-    ru.setExpectedOldObjectId(ObjectId.fromString(ps.getRevision().get()));
-    ru.setNewObjectId(ObjectId.zeroId());
-    RefUpdate.Result result = ru.update();
-    switch (result) {
-      case FORCED:
-        return;
-      default:
-        throw new IOException(String.format("Failed to delete ref %s", ref));
-    }
-  }
-
   private void replayMessages(Change change, ChangeInfo c)
       throws IOException, NoSuchChangeException, OrmException,
       NoSuchAccountException {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java
new file mode 100644
index 0000000..47eeaa5
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/importer/ReplayRevisionsStep.java
@@ -0,0 +1,167 @@
+//Copyright (C) 2015 The Android Open Source Project
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+package com.googlesource.gerrit.plugins.importer;
+
+import com.google.gerrit.common.errors.NoSuchAccountException;
+import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.client.RevId;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.ChangeUtil;
+import com.google.gerrit.server.patch.PatchSetInfoFactory;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RefUpdate;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+class ReplayRevisionsStep {
+
+  interface Factory {
+    ReplayRevisionsStep create(Repository repo, RevWalk rw, Change change,
+        ChangeInfo changeInfo);
+  }
+
+  private final AccountUtil accountUtil;
+  private final ReviewDb db;
+  private final PatchSetInfoFactory patchSetInfoFactory;
+  private final Repository repo;
+  private final RevWalk rw;
+  private final Change change;
+  private final ChangeInfo changeInfo;
+
+  @Inject
+  public ReplayRevisionsStep(AccountUtil accountUtil,
+      ReviewDb db,
+      PatchSetInfoFactory patchSetInfoFactory,
+      @Assisted Repository repo,
+      @Assisted RevWalk rw,
+      @Assisted Change change,
+      @Assisted ChangeInfo changeInfo) {
+    this.accountUtil = accountUtil;
+    this.db = db;
+    this.patchSetInfoFactory = patchSetInfoFactory;
+    this.repo = repo;
+    this.rw = rw;
+    this.change = change;
+    this.changeInfo = changeInfo;
+  }
+
+  void replay() throws IOException, OrmException, NoSuchAccountException {
+    List<RevisionInfo> revisions = new ArrayList<>(changeInfo.revisions.values());
+    sortRevisionInfoByNumber(revisions);
+    List<PatchSet> patchSets = new ArrayList<>();
+
+    db.changes().beginTransaction(change.getId());
+    try {
+      for (RevisionInfo r : revisions) {
+        String origRef = r.ref;
+        ObjectId id = repo.resolve(origRef);
+        if (id == null) {
+          // already replayed?
+          continue;
+        }
+        RevCommit commit = rw.parseCommit(id);
+
+        PatchSet ps = new PatchSet(new PatchSet.Id(change.getId(), r._number));
+        patchSets.add(ps);
+
+        ps.setUploader(accountUtil.resolveUser(r.uploader));
+        ps.setCreatedOn(r.created);
+        ps.setRevision(new RevId(commit.name()));
+        ps.setDraft(r.draft != null && r.draft);
+
+        PatchSetInfo info = patchSetInfoFactory.get(commit, ps.getId());
+        if (changeInfo.currentRevision.equals(info.getRevId())) {
+          change.setCurrentPatchSet(info);
+        }
+
+        ChangeUtil.insertAncestors(db, ps.getId(), commit);
+
+        renameRef(repo, origRef, ps);
+      }
+
+      db.patchSets().insert(patchSets);
+      db.commit();
+    } finally {
+      db.rollback();
+    }
+  }
+
+  private static void sortRevisionInfoByNumber(List<RevisionInfo> list) {
+    Collections.sort(list, new Comparator<RevisionInfo>() {
+      @Override
+      public int compare(RevisionInfo a, RevisionInfo b) {
+        return a._number - b._number;
+      }
+    });
+  }
+
+  private void renameRef(Repository repo, String origRef, PatchSet ps)
+      throws IOException {
+    String ref = ps.getId().toRefName();
+    if (ref.equals(origRef)) {
+      return;
+    }
+
+    createRef(repo, ps);
+    deleteRef(repo, ps, origRef);
+  }
+
+  private void createRef(Repository repo, PatchSet ps) throws IOException {
+    String ref = ps.getId().toRefName();
+    RefUpdate ru = repo.updateRef(ref);
+    ru.setForceUpdate(true);
+    ru.setExpectedOldObjectId(ObjectId.zeroId());
+    ru.setNewObjectId(ObjectId.fromString(ps.getRevision().get()));
+    RefUpdate.Result result = ru.update();
+    switch (result) {
+      case NEW:
+      case FORCED:
+      case FAST_FORWARD:
+        return;
+      default:
+        throw new IOException(String.format("Failed to create ref %s", ref));
+    }
+  }
+
+  private void deleteRef(Repository repo, PatchSet ps, String ref)
+      throws IOException {
+    RefUpdate ru = repo.updateRef(ref);
+    ru.setForceUpdate(true);
+    ru.setExpectedOldObjectId(ObjectId.fromString(ps.getRevision().get()));
+    ru.setNewObjectId(ObjectId.zeroId());
+    RefUpdate.Result result = ru.update();
+    switch (result) {
+      case FORCED:
+        return;
+      default:
+        throw new IOException(String.format("Failed to delete ref %s", ref));
+    }
+  }
+}