diff mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CheckoutRepository.java @ 645:4cf1ab3cd162

Merge in subrepos
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Tue, 17 Sep 2013 18:48:51 +0400
parents
children 0b50d7952a7d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CheckoutRepository.java	Tue Sep 17 18:48:51 2013 +0400
@@ -0,0 +1,175 @@
+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 final HgVcsRoot myRoot;
+  private final File myWorkingDir;
+  private String myRevision;
+  private String myBranch;
+
+  CheckoutRepository(@NotNull MirrorManager mirrorManager,
+                     @NotNull HgRepoFactory hgRepoFactory,
+                     int pullTimeout,
+                     @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);
+      Map<String, String> revisions = repo.getBranchRevisions(true);
+      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);
+    }
+  }
+}