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

Use non-interactive merge
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Wed, 16 Oct 2013 14:33:41 +0400
parents 0b50d7952a7d
children d1469a7cc038
line wrap: on
line source

package jetbrains.buildServer.buildTriggers.vcs.mercurial;

import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
import jetbrains.buildServer.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;

import static jetbrains.buildServer.util.FileUtil.delete;

/**
 * Repository checkout which uses mirrors (updates them first)
 * and supports subrepos.
 */
public class CheckoutRepository {

  private final MirrorManager myMirrorManager;
  private final HgRepoFactory myHgRepoFactory;
  private final int myPullTimeout;
  private boolean myGlobalTagsAsBranches;
  private final HgVcsRoot myRoot;
  private final File myWorkingDir;
  private String myRevision;
  private String myBranch;

  CheckoutRepository(@NotNull MirrorManager mirrorManager,
                     @NotNull HgRepoFactory hgRepoFactory,
                     int pullTimeout,
                     boolean globalTagsAsBranches,
                     @NotNull HgVcsRoot root,
                     @NotNull File workingDir) {
    myMirrorManager = mirrorManager;
    myHgRepoFactory = hgRepoFactory;
    myPullTimeout = pullTimeout;
    myRoot = root;
    myWorkingDir = workingDir;
  }

  public CheckoutRepository setRevision(String revision) {
    myRevision = revision;
    return this;
  }

  public CheckoutRepository setBranch(String branch) {
    myBranch = branch;
    return this;
  }

  public void checkout() throws VcsException {
    checkout(myRoot, myWorkingDir, myRevision);
  }

  private void checkout(@NotNull HgVcsRoot root,
                        @NotNull File workingDir,
                        @Nullable String revision) throws VcsException {
    updateRepository(root, workingDir, revision);
    if (revision == null && myBranch != null) {
      HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
      boolean includeTags = myGlobalTagsAsBranches && root.useTagsAsBranches();
      Map<String, String> revisions = repo.getBranchRevisions(true, includeTags);
      revision = revisions.get(myBranch);
    }
    if (revision == null)
      return;
    updateSubrepos(root, workingDir, revision);
    updateWorkingDir(root, workingDir, revision);
  }


  private void updateRepository(@NotNull HgVcsRoot root,
                                @NotNull File workingDir,
                                @Nullable String revision) throws VcsException {
    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
    if (revision != null && repo.containsRevision(revision))
      return;

    updateMirror(root, revision);
    String mirrorUrl = getMirrorUrl(root);

    if (repo.isValidRepository()) {
      repo.pull().fromRepository(mirrorUrl)
              .withTimeout(myPullTimeout)
              .call();
    } else {
      repo.doClone().fromRepository(mirrorUrl)
              .setUpdateWorkingDir(false)
              .call();

      repo.setDefaultPath(root.getRepository());
    }
  }


  private void updateWorkingDir(@NotNull HgVcsRoot root,
                                @NotNull File workingDir,
                                @NotNull String revision) throws VcsException {
    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
    repo.update().toRevision(revision).call();
  }


  private void updateSubrepos(@NotNull HgVcsRoot root,
                              @NotNull File workingDir,
                              @Nullable String revision) throws VcsException {
    HgRepo repo = myHgRepoFactory.createRepo(root, workingDir);
    if (!repo.hasSubreposAtRevision(revision))
      return;

    String workingDirRevision = repo.getWorkingDirRevision();
    Map<String, SubRepo> workingDirSubrepos = repo.getSubrepositories(workingDirRevision);
    Map<String, SubRepo> subrepos = repo.getSubrepositories(revision);
    for (Map.Entry<String, SubRepo> entry : subrepos.entrySet()) {
      String path = entry.getKey();
      SubRepo subrepoConfig = entry.getValue();
      SubRepo workingDirSubrepo = workingDirSubrepos.get(path);
      if (workingDirSubrepo != null && subrepoConfig.hasDifferentUrlThan(workingDirSubrepo))
        delete(subrepoConfigDir(repo, subrepoConfig));

      File subrepoDir = new File(workingDir, subrepoConfig.path());
      String subrepoUrl;
      try {
        subrepoUrl = subrepoConfig.resolveUrl(root.getRepository());
        if (subrepoConfig.vcsType() == SubRepo.VcsType.hg && !isRelativeUrl(subrepoUrl)) {
          HgVcsRoot subrepoRoot = root.withUrl(subrepoUrl);
          updateRepository(subrepoRoot, subrepoDir, subrepoConfig.revision());
        }
      } catch (URISyntaxException e) {
        subrepoUrl = subrepoConfig.url();
      }

      updateSubrepos(root.withUrl(subrepoUrl), subrepoDir, subrepoConfig.revision());
    }
  }


  private boolean isRelativeUrl(@NotNull String url) {
    return url.startsWith(".");
  }


  private File subrepoConfigDir(@NotNull HgRepo parentRepo, @NotNull SubRepo subrepo) {
    return new File(parentRepo.getWorkingDir(), subrepo.path());
  }


  private void updateMirror(@NotNull HgVcsRoot root, @Nullable String revision) throws VcsException {
    String url = root.getRepository();
    File mirrorDir = myMirrorManager.getMirrorDir(url);
    HgRepo repo = myHgRepoFactory.createRepo(root, mirrorDir);
    if (revision != null && repo.containsRevision(revision)) {
      return;
    }

    if (repo.isValidRepository()) {
      repo.pull().fromRepository(root.getRepository())
              .withTimeout(myPullTimeout)
              .call();
    } else {
      repo.doClone().fromRepository(root.getRepository())
              .setUpdateWorkingDir(false)
              .useUncompressedTransfer(root.isUncompressedTransfer())
              .call();
      repo.setDefaultPath(root.getRepository());
    }
  }

  private String getMirrorUrl(@NotNull HgVcsRoot root) throws VcsException {
    try {
      return myMirrorManager.getMirrorDir(root.getRepository()).getCanonicalPath();
    } catch (IOException e) {
      throw new VcsException(e);
    }
  }
}