changeset 430:3600b68a4c0c

TW-21403 better error message when hg not found
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Fri, 11 May 2012 19:33:48 +0400
parents 04eab204ba39
children 9a2b6a7a3381
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/MercurialNotFoundException.java mercurial-server/src/META-INF/build-server-plugin-mercurial.xml mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootFactory.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java
diffstat 8 files changed, 196 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java	Fri May 11 16:37:00 2012 +0400
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java	Fri May 11 19:33:48 2012 +0400
@@ -1,16 +1,15 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
+import com.intellij.execution.process.ProcessNotCreatedException;
 import com.intellij.openapi.diagnostic.Logger;
 import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ConnectionRefusedException;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownFileException;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownRevisionException;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.*;
 import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
+import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -33,6 +32,9 @@
   //e.g. pull command in hg 2.1 exits with 1 if no new changes were pulled.
   private static final Set<Integer> ERROR_EXIT_CODES = setOf(-1, 255);
 
+  private static final String MERCURIAL_NOT_FOUND_MESSAGE_PREFIX = "Cannot run program \"";
+  private static final String MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX = "No such file or directory";
+
   private final Logger myLogger;
   private final String myCommand;
   private final ExecResult myDelegate;
@@ -75,9 +77,30 @@
     myLogger.warn(message);
     if (hasImportantException())
       myLogger.error("Error during executing '" + getCommand() + "'", getException());
+    throwVcsException(message);
+  }
+
+  private void throwVcsException(@NotNull String message) throws VcsException {
+    //noinspection ThrowableResultOfMethodCallIgnored
+    Throwable e = getException();
+    if (isMercurialNotFoundException(e)) {
+      assert e != null;
+      throw new MercurialNotFoundException(myCommand, e);
+    }
     throw new VcsException(message);
   }
 
+  private boolean isMercurialNotFoundException(@Nullable Throwable e) {
+    if (e == null)
+      return false;
+    final String message = e.getMessage();
+    return e instanceof ProcessNotCreatedException &&
+           e.getCause() instanceof IOException &&
+           message != null &&
+           message.startsWith(MERCURIAL_NOT_FOUND_MESSAGE_PREFIX) &&
+           message.endsWith(MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX);
+  }
+
   private void logStderr(String stderr) {
     myLogger.warn("Error output produced by: " + getCommand());
     myLogger.warn(stderr);
@@ -94,6 +117,7 @@
   }
 
   private boolean isFailure() {
+    //noinspection ThrowableResultOfMethodCallIgnored
     return getException() != null || isErrorExitCode();
   }
 
@@ -112,6 +136,7 @@
   }
 
   private boolean hasImportantException() {
+    //noinspection ThrowableResultOfMethodCallIgnored
     Throwable exception = getException();
     return exception instanceof NullPointerException;
   }
@@ -128,6 +153,7 @@
 
   @Nullable
   private String getExceptionMessage() {
+    //noinspection ThrowableResultOfMethodCallIgnored
     Throwable exception = getException();
     if (exception == null)
       return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/MercurialNotFoundException.java	Fri May 11 19:33:48 2012 +0400
@@ -0,0 +1,15 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception;
+
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author dmitry.neverov
+ */
+public class MercurialNotFoundException extends VcsException {
+
+  public MercurialNotFoundException(@NotNull String failedHgCommand, Throwable cause) {
+    super("'" + failedHgCommand + "' command failed: mercurial executable not found", cause);
+  }
+
+}
--- a/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml	Fri May 11 16:37:00 2012 +0400
+++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml	Fri May 11 19:33:48 2012 +0400
@@ -7,4 +7,6 @@
   <bean id="repoFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.RepoFactory" />
   <bean id="hgPathProvider" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgPathProvider"/>
   <bean id="mirrorManager" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerImpl" />
+  <bean id="hgVcsRootFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVcsRootFactory" />
+  <bean id="testConnection" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgTestConnectionSupport" />
 </beans>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java	Fri May 11 19:33:48 2012 +0400
@@ -0,0 +1,59 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MercurialNotFoundException;
+import jetbrains.buildServer.vcs.TestConnectionSupport;
+import jetbrains.buildServer.vcs.VcsException;
+import jetbrains.buildServer.vcs.VcsRoot;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * @author dmitry.neverov
+ */
+public class HgTestConnectionSupport implements TestConnectionSupport {
+
+  private final HgVcsRootFactory myHgVcsRootFactory;
+  private final RepoFactory myRepoFactory;
+  private final MirrorManager myMirrorManager;
+  private final HgPathProvider myHgPathProvider;
+
+  public HgTestConnectionSupport(@NotNull HgVcsRootFactory hgVcsRootFactory,
+                                 @NotNull RepoFactory repoFactory,
+                                 @NotNull MirrorManager mirrorManager,
+                                 @NotNull HgPathProvider hgPathProvider) {
+    myHgVcsRootFactory = hgVcsRootFactory;
+    myRepoFactory = repoFactory;
+    myMirrorManager = mirrorManager;
+    myHgPathProvider = hgPathProvider;
+  }
+
+
+  public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException {
+    HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot);
+    HgRepo repo = createRepo(root);
+    try {
+      repo.id().repository(root.getRepository())
+              .withAuthSettings(root.getAuthSettings())
+              .call();
+      return null;
+    } catch (MercurialNotFoundException e) {
+      throw friendlyException(root, e);
+    }
+  }
+
+
+  private VcsException friendlyException(HgVcsRoot root, MercurialNotFoundException e) {
+    return new VcsException("Cannot find mercurial executable at path '" + myHgPathProvider.getHgPath(root) + "'", e);
+  }
+
+  private ServerHgRepo createRepo(HgVcsRoot root) throws VcsException {
+    return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings());
+  }
+
+  private File getWorkingDir(HgVcsRoot root) {
+    File customDir = root.getCustomWorkingDir();
+    return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository());
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootFactory.java	Fri May 11 19:33:48 2012 +0400
@@ -0,0 +1,48 @@
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
+import jetbrains.buildServer.util.StringUtil;
+import jetbrains.buildServer.vcs.VcsException;
+import jetbrains.buildServer.vcs.VcsRoot;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * @author dmitry.neverov
+ */
+public class HgVcsRootFactory {
+
+  private File myDefaultWorkFolderParent;
+
+  public HgVcsRootFactory(@NotNull final ServerPluginConfig config) {
+    myDefaultWorkFolderParent = config.getCachesDir();
+  }
+
+
+  public HgVcsRoot createHgRoot(@NotNull VcsRoot root) throws VcsException {
+    HgVcsRoot hgRoot = new HgVcsRoot(root);
+    String customClonePath = hgRoot.getCustomClonePath();
+    if (!StringUtil.isEmptyOrSpaces(customClonePath) && !myDefaultWorkFolderParent.equals(new File(customClonePath).getAbsoluteFile())) {
+      File parentDir = new File(customClonePath);
+      createClonedRepositoryParentDir(parentDir);
+
+      // take last part of repository path
+      String repPath = hgRoot.getRepositoryUrlWithCredentials();
+      String[] splitted = repPath.split("[/\\\\]");
+      if (splitted.length > 0) {
+        repPath = splitted[splitted.length-1];
+      }
+
+      File customWorkingDir = new File(parentDir, repPath);
+      hgRoot.setCustomWorkingDir(customWorkingDir);
+    }
+    return hgRoot;
+  }
+
+  private void createClonedRepositoryParentDir(final File parentDir) throws VcsException {
+    if (!parentDir.exists() && !parentDir.mkdirs())
+      throw new VcsException("Failed to create parent directory for cloned repository: " + parentDir.getAbsolutePath());
+  }
+
+}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Fri May 11 16:37:00 2012 +0400
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Fri May 11 19:33:48 2012 +0400
@@ -25,7 +25,6 @@
 import jetbrains.buildServer.serverSide.*;
 import jetbrains.buildServer.util.EventDispatcher;
 import jetbrains.buildServer.util.FileUtil;
-import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.util.cache.ResetCacheRegister;
 import jetbrains.buildServer.vcs.*;
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
@@ -53,13 +52,14 @@
 public class MercurialVcsSupport extends ServerVcsSupport implements LabelingSupport, VcsFileContentProvider, BranchSupport,
         CollectChangesBetweenRoots, BuildPatchByCheckoutRules {
   private final VcsManager myVcsManager;
-  private final File myDefaultWorkFolderParent;
   private final MirrorManager myMirrorManager;
   private final ServerPluginConfig myConfig;
   private final HgPathProvider myHgPathProvider;
   private final RepoFactory myRepoFactory;
+  private final HgVcsRootFactory myHgVcsRootFactory;
   private final FileFilter myIgnoreDotHgFilter = new IgnoreDotHgFilter();
   private final FileFilter myAcceptAllFilter = new AcceptAllFilter();
+  private final HgTestConnectionSupport myTestConnection;
 
   public MercurialVcsSupport(@NotNull final VcsManager vcsManager,
                              @NotNull final SBuildServer server,
@@ -68,13 +68,16 @@
                              @NotNull final ServerPluginConfig config,
                              @NotNull final HgPathProvider hgPathProvider,
                              @NotNull final RepoFactory repoFactory,
-                             @NotNull final MirrorManager mirrorManager) {
+                             @NotNull final MirrorManager mirrorManager,
+                             @NotNull final HgVcsRootFactory hgVcsRootFactory,
+                             @NotNull final HgTestConnectionSupport testConnection) {
     myVcsManager = vcsManager;
     myConfig = config;
-    myDefaultWorkFolderParent = myConfig.getCachesDir();
     myMirrorManager = mirrorManager;
     myHgPathProvider = hgPathProvider;
     myRepoFactory = repoFactory;
+    myHgVcsRootFactory = hgVcsRootFactory;
+    myTestConnection = testConnection;
     resetCacheHandlerManager.registerHandler(new MercurialResetCacheHandler(myMirrorManager));
     dispatcher.addListener(new BuildServerAdapter() {
       @Override
@@ -164,7 +167,7 @@
   @NotNull
   public byte[] getContent(@NotNull final String filePath, @NotNull final VcsRoot vcsRoot, @NotNull final String version) throws VcsException {
     ChangeSet cset = new ChangeSet(version);
-    HgVcsRoot root = createHgRoot(vcsRoot);
+    HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot);
     syncRepository(root, cset);
     HgRepo repo = createRepo(root);
     File parentDir = repo.cat().files(filePath).atRevision(cset).call();
@@ -212,7 +215,7 @@
 
   @NotNull
   public String getCurrentVersion(@NotNull final VcsRoot root) throws VcsException {
-    HgVcsRoot hgRoot = createHgRoot(root);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     syncRepository(hgRoot);
     HgRepo repo = createRepo(hgRoot);
     Map<String, ChangeSet> result = repo.branches().call();
@@ -233,28 +236,7 @@
 
   @Override
   public TestConnectionSupport getTestConnectionSupport() {
-    return new TestConnectionSupport() {
-      public String testConnection(@NotNull final VcsRoot vcsRoot) throws VcsException {
-        HgVcsRoot root = createHgRoot(vcsRoot);
-        String idResult = createRepo(root).id()
-                .repository(root.getRepository())
-                .withAuthSettings(root.getAuthSettings())
-                .call();
-        StringBuilder res = new StringBuilder();
-        res.append(quoteIfNeeded(myHgPathProvider.getHgPath(root)));
-        res.append(" identify ");
-        res.append(quoteIfNeeded(root.getAuthSettings().getRepositoryUrlWithHiddenPassword(root.getRepository())));
-        res.append('\n').append(idResult);
-        return res.toString();
-      }
-    };
-  }
-
-  private String quoteIfNeeded(@NotNull String str) {
-    if (str.indexOf(' ') != -1) {
-      return "\"" + str + "\"";
-    }
-    return str;
+    return myTestConnection;
   }
 
   @Nullable
@@ -475,7 +457,7 @@
 
   @NotNull
   private Map<String, String> getBranchesRevisions(@NotNull VcsRoot root) throws VcsException {
-    HgVcsRoot hgRoot = createHgRoot(root);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     syncRepository(hgRoot);
     HgRepo repo = createRepo(hgRoot);
     Map<String, String> result = new HashMap<String, String>();
@@ -495,7 +477,7 @@
 
   @Nullable
   public PersonalBranchDescription getPersonalBranchDescription(@NotNull VcsRoot root, @NotNull String branchName) throws VcsException {
-    HgVcsRoot hgRoot = createHgRoot(root);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     VcsRoot branchRoot = createBranchRoot(root, branchName);
     String baseVersion = getCurrentVersion(root);
     String branchVersion = getCurrentVersion(branchRoot);
@@ -529,7 +511,7 @@
   public List<ModificationData> collectChanges(@NotNull VcsRoot fromRoot, @NotNull String fromRootRevision,
                                                @NotNull VcsRoot toRoot, @Nullable String toRootRevision,
                                                @NotNull CheckoutRules checkoutRules) throws VcsException {
-    HgVcsRoot hgRoot = createHgRoot(toRoot);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(toRoot);
     syncRepository(hgRoot);
     String toRevision = toRootRevision != null ? toRootRevision : getCurrentVersion(toRoot);
     String mergeBase = getMergeBase(hgRoot, fromRootRevision, toRevision);
@@ -571,7 +553,7 @@
   }
 
   public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException {
-    HgVcsRoot hgRoot = createHgRoot(root);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     syncRepository(hgRoot);
     List<ModificationData> result = new ArrayList<ModificationData>();
     for (ChangeSet cset : getChangesets(hgRoot, fromVersion, currentVersion)) {
@@ -627,7 +609,7 @@
   }
 
   public void buildPatch(@NotNull VcsRoot root, @Nullable String fromVersion, @NotNull String toVersion, @NotNull PatchBuilder builder, @NotNull CheckoutRules checkoutRules) throws IOException, VcsException {
-    HgVcsRoot hgRoot = createHgRoot(root);
+    HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
     syncRepository(hgRoot);
     ChangeSet to = new ChangeSet(toVersion);
     if (fromVersion == null) {
@@ -668,7 +650,7 @@
     File tmpDir = null;
     try {
       tmpDir = createLabelingTmpDir();
-      HgVcsRoot hgRoot = createHgRoot(root);
+      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
       hgRoot.setCustomWorkingDir(tmpDir);
       syncRepository(hgRoot);
       HgRepo repo = createRepo(hgRoot);
@@ -703,31 +685,6 @@
     return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository());
   }
 
-  private HgVcsRoot createHgRoot(@NotNull VcsRoot root) throws VcsException {
-    HgVcsRoot hgRoot = new HgVcsRoot(root);
-    String customClonePath = hgRoot.getCustomClonePath();
-    if (!StringUtil.isEmptyOrSpaces(customClonePath) && !myDefaultWorkFolderParent.equals(new File(customClonePath).getAbsoluteFile())) {
-      File parentDir = new File(customClonePath);
-      createClonedRepositoryParentDir(parentDir);
-
-      // take last part of repository path
-      String repPath = hgRoot.getRepositoryUrlWithCredentials();
-      String[] splitted = repPath.split("[/\\\\]");
-      if (splitted.length > 0) {
-        repPath = splitted[splitted.length-1];
-      }
-
-      File customWorkingDir = new File(parentDir, repPath);
-      hgRoot.setCustomWorkingDir(customWorkingDir);
-    }
-    return hgRoot;
-  }
-
-  private void createClonedRepositoryParentDir(final File parentDir) throws VcsException {
-    if (!parentDir.exists() && !parentDir.mkdirs()) {
-      throw new VcsException("Failed to create parent directory for cloned repository: " + parentDir.getAbsolutePath());
-    }
-  }
 
   public boolean isAgentSideCheckoutAvailable() {
     return true;
@@ -777,7 +734,7 @@
   @NotNull
   public String getBranchName(@NotNull final VcsRoot root) {
     try {
-      HgVcsRoot hgRoot = createHgRoot(root);
+      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
       return hgRoot.getBranchName();
     } catch (VcsException e) {
       return "default";
@@ -797,7 +754,7 @@
   @Override
   public ListFilesPolicy getListFilesPolicy(@NotNull VcsRoot root) {
     try {
-      HgVcsRoot hgRoot = createHgRoot(root);
+      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
       HgRepo repo = createRepo(hgRoot);
       return new ListFilesSupport(this, hgRoot, repo);
     } catch (VcsException e) {
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Fri May 11 16:37:00 2012 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Fri May 11 19:33:48 2012 +0400
@@ -35,6 +35,7 @@
 import java.util.*;
 
 import static com.intellij.openapi.util.io.FileUtil.copyDir;
+import static com.intellij.openapi.util.io.FileUtil.delete;
 import static com.intellij.openapi.util.io.FileUtil.moveDirWithContent;
 import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
 
@@ -234,6 +235,22 @@
     }
   }
 
+
+  public void should_throw_friendly_exception_when_cannot_run_hg() throws Exception {
+    VcsRootImpl root = createVcsRoot(simpleRepo());
+    File nonExistingHg = myTempFiles.createTempFile();
+    delete(nonExistingHg);
+    String nonExistingHgPath = nonExistingHg.getAbsolutePath();
+    root.addProperty(Constants.HG_COMMAND_PATH_PROP, nonExistingHgPath);
+    try {
+      myVcs.getTestConnectionSupport().testConnection(root);
+      fail("Exception expected");
+    } catch (VcsException e) {
+      assertEquals(e.getMessage(), "Cannot find mercurial executable at path '" + nonExistingHgPath + "'");
+    }
+  }
+
+
   public void test_tag() throws IOException, VcsException {
     VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
     cleanRepositoryAfterTest(simpleRepo());
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java	Fri May 11 16:37:00 2012 +0400
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java	Fri May 11 19:33:48 2012 +0400
@@ -36,7 +36,7 @@
   }
 
 
-  public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull RepoFactory commandFactory) throws IOException {
+  public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull RepoFactory repoFactory) throws IOException {
     VcsManager vcsManager = context.mock(VcsManager.class);
     final SBuildServer server = context.mock(SBuildServer.class);
     final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
@@ -44,6 +44,11 @@
       allowing(server).getExecutor(); will(returnValue(executor));
     }});
     EventDispatcher<BuildServerListener> dispatcher = EventDispatcher.create(BuildServerListener.class);
-    return new MercurialVcsSupport(vcsManager, server, dispatcher, new ResetCacheRegister(), config, new ServerHgPathProvider(config), commandFactory, new MirrorManagerImpl(config));
+    HgVcsRootFactory hgVcsRootFactory = new HgVcsRootFactory(config);
+    MirrorManagerImpl mirrorManager = new MirrorManagerImpl(config);
+    ServerHgPathProvider hgPathProvider = new ServerHgPathProvider(config);
+    HgTestConnectionSupport testConnection = new HgTestConnectionSupport(hgVcsRootFactory, repoFactory, mirrorManager, hgPathProvider);
+    return new MercurialVcsSupport(vcsManager, server, dispatcher, new ResetCacheRegister(), config, hgPathProvider,
+            repoFactory, mirrorManager, hgVcsRootFactory, testConnection);
   }
 }