view mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialMergeSupport.java @ 671:3cc513b9e3c1

Use non-interactive merge
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Wed, 16 Oct 2013 14:33:41 +0400
parents 718e4dbff3c3
children 8b09ec36fbef
line wrap: on
line source
package jetbrains.buildServer.buildTriggers.vcs.mercurial;

import com.intellij.openapi.diagnostic.Logger;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MergeConflictException;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MergeWithWorkingDirAncestor;
import jetbrains.buildServer.vcs.*;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir;

public class MercurialMergeSupport implements MergeSupport, MercurialServerExtension {

  private final static Logger LOG = Logger.getInstance(MercurialMergeSupport.class.getName());

  private final MirrorManager myMirrorManager;
  private final ServerPluginConfig myConfig;
  private final HgVcsRootFactory myHgVcsRootFactory;
  private final HgRepoFactory myHgRepoFactory;

  public MercurialMergeSupport(@NotNull MercurialVcsSupport vcs,
                               @NotNull MirrorManager mirrorManager,
                               @NotNull ServerPluginConfig config,
                               @NotNull HgVcsRootFactory vcsRootFactory,
                               @NotNull HgRepoFactory hgRepoFactory) {
    vcs.addExtension(this);
    myMirrorManager = mirrorManager;
    myConfig = config;
    myHgVcsRootFactory = vcsRootFactory;
    myHgRepoFactory = hgRepoFactory;
  }

  @NotNull
  public Map<MergeTask, MergeResult> tryMerge(@NotNull VcsRoot root, @NotNull List<MergeTask> tasks, @NotNull MergeOptions options) throws VcsException {
    File tmpDir = null;
    try {
      tmpDir = HgFileUtil.createTempDir();
      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
      HgRepo repo = myHgRepoFactory.createRepo(hgRoot, tmpDir);
      Map<MergeTask, MergeResult> results = new HashMap<MergeTask, MergeResult>();
      for (MergeTask task : tasks) {
        try {
          new CheckoutRepository(myMirrorManager, myHgRepoFactory, myConfig.getPullTimeout(), myConfig.useTagsAsBranches(), hgRoot, tmpDir)
                  .setRevision(task.getDestinationRevision()).checkout();
          repo.merge().withMergeTool(myConfig.getMergeTool()).revision(task.getSourceRevision()).call();
          results.put(task, MergeResult.createMergeSuccessResult());
        } catch (MergeConflictException e) {
          results.put(task, MergeResult.createMergeError(detectConflicts(hgRoot, "", repo)));
        } catch (MergeWithWorkingDirAncestor e) {
          //ignore
        } catch (VcsException e) {
          results.put(task, MergeResult.createMergeError(e.getMessage()));
        } finally {
          repo.update().toRevision(task.getDestinationRevision()).call();
        }
      }
      return results;
    } catch (Exception e) {
      if (e instanceof VcsException)
        throw (VcsException) e;
      throw new VcsException(e);
    } finally {
      deleteDir(tmpDir, LOG);
    }
  }


  @NotNull
  public MergeResult merge(@NotNull VcsRoot root,
                           @NotNull String srcRevision,
                           @NotNull String dstBranch,
                           @NotNull String message,
                           @NotNull MergeOptions options) throws VcsException {
    File tmpDir = null;
    try {
      tmpDir = HgFileUtil.createTempDir();
      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);

      new CheckoutRepository(myMirrorManager, myHgRepoFactory, myConfig.getPullTimeout(), myConfig.useTagsAsBranches(), hgRoot, tmpDir)
              .setBranch(dstBranch).checkout();

      HgRepo repo = myHgRepoFactory.createRepo(hgRoot, tmpDir);
      try {
        repo.merge().withMergeTool(myConfig.getMergeTool()).revision(srcRevision).call();
      } catch (MergeConflictException e) {
        return MergeResult.createMergeError(detectConflicts(hgRoot, "", repo));
      } catch (MergeWithWorkingDirAncestor e) {
        return MergeResult.createMergeError(e.getMessage());
      }

      repo.commit().message(message).call();

      repo.push().toRepository(hgRoot.getRepository()).call();
      return MergeResult.createMergeSuccessResult();
    } catch (Exception e) {
      if (e instanceof VcsException)
        throw (VcsException) e;
      throw new VcsException(e);
    } finally {
      deleteDir(tmpDir, LOG);
    }
  }


  private List<String> detectConflicts(@NotNull HgVcsRoot root, @NotNull String prefix, @NotNull HgRepo repo) throws VcsException {
    List<String> conflicts = new ArrayList<String>();
    for (String conflict : repo.resolve().call()) {
      conflicts.add(prefix + conflict);
    }

    List<String> parents = repo.parents().call();
    if (parents.isEmpty())
      return conflicts;

    Map<String, SubRepo> subrepos = repo.getSubrepositories(parents.get(0));
    for (SubRepo subrepo : subrepos.values()) {
      HgVcsRoot subrepoRoot = root.withUrl(subrepo.url());
      HgRepo hgSubrepo = myHgRepoFactory.createRepo(subrepoRoot, new File(repo.getWorkingDir(), subrepo.path()));
      conflicts.addAll(detectConflicts(subrepoRoot, prefix + subrepo.path() + "/", hgSubrepo));
    }
    return conflicts;
  }
}