changeset 784:f0327df85b9d

Merge branch Gaya-8.1.x
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Thu, 17 Apr 2014 20:16:48 +0200
parents 44b15b5a87e8 (diff) d60aa99940ba (current diff)
children 427f550c4554
files mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java mercurial-server-tc/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSubrepoUsageStatistics.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java
diffstat 40 files changed, 640 insertions(+), 268 deletions(-) [+]
line wrap: on
line diff
--- a/.idea/libraries/TeamCity_impl.xml	Thu Apr 17 19:56:05 2014 +0200
+++ b/.idea/libraries/TeamCity_impl.xml	Thu Apr 17 20:16:48 2014 +0200
@@ -3,6 +3,7 @@
     <CLASSES>
       <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/patches-impl.jar!/" />
       <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove4j.jar!/" />
+      <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove-3.0.3.jar!/" />
     </CLASSES>
     <JAVADOC />
     <SOURCES />
--- a/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml	Thu Apr 17 20:16:48 2014 +0200
@@ -26,4 +26,7 @@
   <bean id="mirrorCleaner" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentMirrorCleaner" />
   <bean id="commandSettingsFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentCommandSettingsFactory" />
   <bean id="agentRepoFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentRepoFactory"/>
+
+  <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl"/>
+  <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver"/>
 </beans>
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentCommandSettingsFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentCommandSettingsFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -18,9 +18,11 @@
 
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettings;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory;
+import org.jetbrains.annotations.NotNull;
 
 public class AgentCommandSettingsFactory implements CommandSettingsFactory {
 
+  @NotNull
   public CommandSettings create() {
     return new CommandSettings().setLogLevel("info");
   }
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentRepoFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentRepoFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,8 +16,7 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRoot;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
@@ -26,23 +25,16 @@
 
 public class AgentRepoFactory implements HgRepoFactory {
 
-  private final CommandSettingsFactory myCommandSettingsFactory;
+  private final CommandSettingsForRoot myCommandSettingsFactory;
   private final HgPathProvider myHgPathProvider;
 
-  public AgentRepoFactory(@NotNull CommandSettingsFactory commandSettingsFactory,
+  public AgentRepoFactory(@NotNull CommandSettingsForRoot commandSettingsFactory,
                           @NotNull HgPathProvider hgPathProvider) {
     myCommandSettingsFactory = commandSettingsFactory;
     myHgPathProvider = hgPathProvider;
   }
 
   public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException {
-    return new HgRepo(myCommandSettingsFactory, workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings());
+    return new HgRepo(myCommandSettingsFactory.forRoot(root), workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings());
   }
-
-  public HgRepo create(@NotNull File workingDir,
-                       @NotNull String hgPath,
-                       @NotNull AuthSettings authSettings) {
-    return new HgRepo(myCommandSettingsFactory, workingDir, hgPath, authSettings);
-  }
-
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Thu Apr 17 20:16:48 2014 +0200
@@ -32,6 +32,7 @@
   String USE_TAGS_AS_BRANCHES = "useTagsAsBranches";
   String INCLUDE_SUBREPOS_IN_PATCH = "includeSubreposInPatch";
   String USE_ARCHIVE_FOR_PATCH = "useArchiveForPatch";
+  String HG_EXTENSIONS = "hg.extensions";
 
   String GLOBAL_DETECT_SUBREPO_CHANGES = "teamcity.hg.detectSubrepoChanges";
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialClasspathTemplate.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+
+import static com.intellij.openapi.util.io.FileUtil.createTempFile;
+import static com.intellij.openapi.util.io.FileUtil.delete;
+
+/**
+* Created 25.02.14 11:29
+*
+* @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+*/
+public class MercurialClasspathTemplate implements MercurialTemplate {
+  private final String myResourcePath;
+  private final String myTmpFileSuffix;
+
+  public MercurialClasspathTemplate(@NotNull final String resourcePath,
+                                    @NotNull final String tmpFileSuffix) {
+    myResourcePath = resourcePath;
+    myTmpFileSuffix = tmpFileSuffix;
+  }
+
+  @NotNull
+  public <T> T withTemplate(@NotNull final WithTemplate<T> action) throws VcsException {
+    //TODO: we may pack plugin and use jetbrains.buildServer.web.openapi.PluginDescriptor.getPluginRoot()
+    //TODO: to get path to existing file
+    final File template = copyTemplate();
+    try {
+      return action.action(template);
+    } finally {
+      delete(template);
+    }
+  }
+
+  private File copyTemplate() throws VcsException {
+    try {
+      final File template = createTempFile("teamcity", myTmpFileSuffix);
+      FileUtil.copyResource(getClass(), myResourcePath, template);
+      return template;
+    } catch (IOException e) {
+      throw new VcsException("Cannot create mercurial log template", e);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialTemplate.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * Created 25.02.14 11:51
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+public interface MercurialTemplate {
+  @NotNull
+  <T> T withTemplate(@NotNull WithTemplate<T> action) throws VcsException;
+
+  interface WithTemplate<T> {
+    @NotNull
+    T action(@NotNull final File template) throws VcsException;
+  }
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -92,16 +92,18 @@
     cli.addParameter("archive");
     setType(cli);
     setRevision(cli);
+    addIncludeRules(cli);
     setDestination(cli);
-    addIncludeRules(cli);
     return cli;
   }
 
   private void addIncludeRules(@NotNull MercurialCommandLine cli) {
     if (myIncludeRules.isEmpty())
       return;
-    cli.addParameter("-I");
-    cli.addParameters(myIncludeRules);
+    for (String include : myIncludeRules) {
+      cli.addParameter("-I");
+      cli.addParameter(include);
+    }
   }
 
   private void setDestination(GeneralCommandLine cli) {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -32,9 +32,9 @@
   private final String myHgPath;
   private final File myWorkDirectory;
 
-  public BaseCommand(@NotNull CommandSettings commandSettings,
+  public BaseCommand(@NotNull final CommandSettings commandSettings,
                      @NotNull final String hgPath,
-                     @NotNull File workingDir) {
+                     @NotNull final File workingDir) {
     myCommandSettings = commandSettings;
     myHgPath = hgPath;
     myWorkDirectory = workingDir;
@@ -52,17 +52,29 @@
   }
 
   protected MercurialCommandLine createCL() {
-    MercurialCommandLine cl = new MercurialCommandLine(getPrivateData());
+    final MercurialCommandLine cl = new MercurialCommandLine(getPrivateData());
     cl.setExePath(myHgPath);
     cl.setEnvParams(myCommandSettings.getHgEnv());
     cl.setPassParentEnvs(true);
+
+    //include global arguments if any
+    cl.addParameters(myCommandSettings.getGlobalArguments());
+
     return cl;
   }
 
-  protected CommandResult runCommand(@NotNull MercurialCommandLine cli) throws VcsException {
-    return CommandUtil.runCommand(cli, myCommandSettings);
+  @NotNull
+  protected final CommandResult runCommand(@NotNull MercurialCommandLine cli) throws VcsException {
+    return runCommand(cli, myCommandSettings);
   }
 
+  @NotNull
+  protected final CommandResult runCommand(@NotNull final MercurialCommandLine cli,
+                                           @NotNull final CommandSettings commandSettings) throws VcsException {
+    return CommandUtil.runCommand(cli, commandSettings.setPrivateData(getPrivateData()));
+  }
+
+  @NotNull
   protected Set<String> getPrivateData() {
     return emptySet();
   }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettings.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettings.java	Thu Apr 17 20:16:48 2014 +0200
@@ -18,10 +18,7 @@
 
 import org.jetbrains.annotations.NotNull;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 /**
  * @author dmitry.neverov
@@ -29,41 +26,37 @@
 public class CommandSettings {
 
   private int myTimeout = 3600;
-  private Set<String> myPrivateData = new HashSet<String>();
+  private final Set<String> myPrivateData = new HashSet<String>();
   private boolean myCheckForFailure = true;
   private boolean myFailWhenStderrNotEmpty = false;
   private String myLogLevel = "debug";
   private Map<String, String> myHgEnv = new HashMap<String, String>();
   private int myLogOutputLimit = -1;
   private int myExceptionOutputLimit = 5000;
-
-  public CommandSettings() {
-
-  }
-
-  public CommandSettings(int timeout,
-                         @NotNull Set<String> privateData,
-                         boolean checkForFailure,
-                         boolean failWhenStderrNotEmpty,
-                         @NotNull String logLevel) {
-    myTimeout = timeout;
-    myPrivateData = privateData;
-    myCheckForFailure = checkForFailure;
-    myFailWhenStderrNotEmpty = failWhenStderrNotEmpty;
-    myLogLevel = logLevel;
-  }
+  private List<String> myGlobalArguments = new ArrayList<String>(0);
 
   public CommandSettings setTimeout(int timeout) {
     myTimeout = timeout;
     return this;
   }
 
+  @NotNull
+  public List<String> getGlobalArguments() {
+    return myGlobalArguments;
+  }
+
+  @NotNull
+  public CommandSettings withGlobalArguments(@NotNull String... argz) {
+    myGlobalArguments.addAll(Arrays.asList(argz));
+    return this;
+  }
+
   public int getTimeout() {
     return myTimeout;
   }
 
   public CommandSettings setPrivateData(@NotNull Set<String> privateData) {
-    myPrivateData = privateData;
+    myPrivateData.addAll(privateData);
     return this;
   }
 
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,8 +16,11 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
+import org.jetbrains.annotations.NotNull;
+
 public interface CommandSettingsFactory {
 
+  @NotNull
   CommandSettings create();
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsForRoot.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created 25.02.14 12:58
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+public interface CommandSettingsForRoot {
+  @NotNull CommandSettingsFactory forRoot(@NotNull HgVcsRoot root);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsForRootImpl.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created 25.02.14 13:01
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+public class CommandSettingsForRootImpl implements CommandSettingsForRoot {
+  private final CommandSettingsFactory myFactory;
+  private final CommandSettingsWeaver[] myWeavers;
+
+  public CommandSettingsForRootImpl(@NotNull CommandSettingsFactory factory,
+                                    @NotNull final CommandSettingsWeaver... weavers) {
+    myFactory = factory;
+    myWeavers = weavers;
+  }
+
+  @NotNull
+  public CommandSettingsFactory forRoot(@NotNull final HgVcsRoot root) {
+    return new CommandSettingsFactory() {
+      @NotNull
+      public CommandSettings create() {
+        CommandSettings settings = myFactory.create();
+        for (CommandSettingsWeaver weaver : myWeavers) {
+          settings = weaver.update(root, settings);
+        }
+        return settings;
+      }
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsWeaver.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created 25.02.14 13:02
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+public interface CommandSettingsWeaver {
+  @NotNull
+  CommandSettings update(@NotNull HgVcsRoot root, @NotNull CommandSettings settings);
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java	Thu Apr 17 20:16:48 2014 +0200
@@ -49,7 +49,7 @@
         return executionTimeout;
       }
       @Override
-      public void onProcessFinished(Process ps) {
+      public void onProcessFinished(@NotNull Process ps) {
         long duration = System.currentTimeMillis() - start;
         Loggers.VCS.debug("Command " + command + " took " + duration + "ms");
       }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitsAndMountPointsCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitsAndMountPointsCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,9 +16,7 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.*;
 import jetbrains.buildServer.util.FileUtil;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ExtensionsWeaver.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants;
+import jetbrains.buildServer.util.StringUtil;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created 25.02.14 13:03
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+public class ExtensionsWeaver implements CommandSettingsWeaver {
+  @NotNull
+  public CommandSettings update(@NotNull HgVcsRoot root, @NotNull CommandSettings settings) {
+    String extensions = root.getProperty(Constants.HG_EXTENSIONS);
+    if (StringUtil.isEmpty(extensions)) return settings;
+
+    for (String _line : extensions.split("[\\r\\n]+")) {
+      String line = _line.trim();
+      if (line.isEmpty()) continue;
+
+      if (!line.contains("=")) line += "=";
+
+      settings = settings.withGlobalArguments("--config", "extensions." + line);
+    }
+
+    return settings;
+  }
+}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LoadDagCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LoadDagCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -17,6 +17,7 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
 import com.intellij.openapi.util.Pair;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate;
 import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
@@ -27,14 +28,14 @@
 
 public class LoadDagCommand extends VcsRootCommand {
 
-  private final File myDagLogTemplate;
+  private final MercurialTemplate myDagLogTemplate;
   private int myMaxDagNodesCount;
 
   public LoadDagCommand(@NotNull CommandSettings commandSettings,
                         @NotNull String hgPath,
                         @NotNull File workingDir,
                         @NotNull AuthSettings authSettings,
-                        @NotNull File dagLogTemplate) {
+                        @NotNull MercurialTemplate dagLogTemplate) {
     super(commandSettings, hgPath, workingDir, authSettings);
     myDagLogTemplate = dagLogTemplate;
   }
@@ -45,31 +46,42 @@
 
   @NotNull
   public List<Pair<String, String>> call() throws VcsException {
-    List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>();
-    MercurialCommandLine cli = createCommandLine();
-    cli.addParameter("log");
-    cli.addParameter("--style=" + myDagLogTemplate.getAbsolutePath());
-    if (myMaxDagNodesCount > 0)
-      cli.addParameters("--limit", String.valueOf(myMaxDagNodesCount));
-    CommandResult res = runCommand(cli);
-    String output = res.getStdout();
-    String fromNode = null;
-    for (String line : StringUtil.splitByLines(output)) {
-      String[] revs = line.split(" ");
-      if (revs.length == 0)
-        continue;
-      if (fromNode != null) {
-        edges.add(Pair.create(fromNode, revs[0]));
-        fromNode = null;
+    return myDagLogTemplate.withTemplate(new MercurialTemplate.WithTemplate<List<Pair<String, String>>>() {
+      @NotNull
+      public List<Pair<String, String>> action(@NotNull File template) throws VcsException {
+        final List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>();
+        final MercurialCommandLine cli = createCommandLine();
+        cli.addParameter("log");
+        cli.addParameter("--style=" + template.getAbsolutePath());
+        if (myMaxDagNodesCount > 0) {
+          cli.addParameters("--limit", String.valueOf(myMaxDagNodesCount));
+        }
+
+        final CommandResult res = runCommand(cli);
+
+
+        final String output = res.getStdout();
+        String fromNode = null;
+        for (String line : StringUtil.splitByLines(output)) {
+          final String[] revs = line.split(" ");
+          if (revs.length == 0) continue;
+
+          if (fromNode != null) {
+            edges.add(Pair.create(fromNode, revs[0]));
+            fromNode = null;
+          }
+
+          if (revs.length == 1) {
+            fromNode = revs[0];
+          } else {
+            edges.add(Pair.create(revs[0], revs[1]));
+            if (revs.length == 3) {
+              edges.add(Pair.create(revs[0], revs[2]));
+            }
+          }
+        }
+        return edges;
       }
-      if (revs.length == 1) {
-        fromNode = revs[0];
-      } else {
-        edges.add(Pair.create(revs[0], revs[1]));
-        if (revs.length == 3)
-          edges.add(Pair.create(revs[0], revs[2]));
-      }
-    }
-    return edges;
+    });
   }
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,6 +16,7 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
 import com.intellij.openapi.diagnostic.Logger;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -43,7 +44,7 @@
   private String myBranchName;
   private boolean myCalculateParents = true;
   private String myRevsets;
-  private File myTemplate;
+  private MercurialTemplate myTemplate;
   private List<String> myFiles = new ArrayList<String>();
 
   public LogCommand(@NotNull CommandSettings commandSettings,
@@ -53,7 +54,7 @@
     super(commandSettings, hgPath, workingDir, authSettings);
   }
 
-  public LogCommand withTemplate(@NotNull File template) {
+  public LogCommand withTemplate(@NotNull MercurialTemplate template) {
     myTemplate = template;
     return this;
   }
@@ -103,44 +104,52 @@
     return this;
   }
 
+  @NotNull
   public List<ChangeSet> call() throws VcsException {
-    MercurialCommandLine cli = createCommandLine();
-    cli.setCharset(Charset.forName("UTF-8"));
-    cli.addParameters("--encoding", "UTF-8");
-    cli.addParameter("log");
-    cli.addParameter("-v");
-    if (myTemplate != null)
-      cli.addParameter("--style=" + myTemplate.getAbsolutePath());
-    if (myBranchName != null) {
-      cli.addParameter("-b");
-      cli.addParameter(myBranchName);
-    }
-    cli.addParameter("-r");
-    if (myRevsets != null) {
-      cli.addParameter(myRevsets);
-    } else {
-      String from = myFromId != null ? myFromId : "0";
-      String to = myToId != null ? myToId : "tip";
-      cli.addParameter(from + ":" + to);
-    }
-    if (myLimit != null) {
-      cli.addParameter("--limit");
-      cli.addParameter(myLimit.toString());
-    }
+    return myTemplate.withTemplate(new MercurialTemplate.WithTemplate<List<ChangeSet>>() {
+      @NotNull
+      public List<ChangeSet> action(@NotNull File template) throws VcsException {
+        final MercurialCommandLine cli = createCommandLine();
+        cli.setCharset(Charset.forName("UTF-8"));
+        cli.addParameters("--encoding", "UTF-8");
+        cli.addParameter("log");
+        cli.addParameter("-v");
+        if (myTemplate != null) {
+          cli.addParameter("--style=" + template.getAbsolutePath());
+        }
 
-    cli.addParameters(myFiles);
+        if (myBranchName != null) {
+          cli.addParameter("-b");
+          cli.addParameter(myBranchName);
+        }
+        cli.addParameter("-r");
+        if (myRevsets != null) {
+          cli.addParameter(myRevsets);
+        } else {
+          String from = myFromId != null ? myFromId : "0";
+          String to = myToId != null ? myToId : "tip";
+          cli.addParameter(from + ":" + to);
+        }
+        if (myLimit != null) {
+          cli.addParameter("--limit");
+          cli.addParameter(myLimit.toString());
+        }
 
-    CommandResult res = runCommand(cli);
-    String output = res.getStdout();
-    try {
-      List<ChangeSet> changes = parseChangeSetsXml(output);
-      if (myCalculateParents)
-        assignTrivialParents(changes);
-      return changes;
-    } catch (Exception e) {
-      LOG.error("Error while parsing log output:\n" + output, e);
-      throw new VcsException("Error while parsing log output, see teamcity-vcs.log for details", e);
-    }
+        cli.addParameters(myFiles);
+
+        final CommandResult res = runCommand(cli);
+        final String output = res.getStdout();
+        try {
+          List<ChangeSet> changes = parseChangeSetsXml(output);
+          if (myCalculateParents)
+            assignTrivialParents(changes);
+          return changes;
+        } catch (Exception e) {
+          LOG.error("Error while parsing log output:\n" + output, e);
+          throw new VcsException("Error while parsing log output, see teamcity-vcs.log for details", e);
+        }
+      }
+    });
   }
 
   private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws SAXException, ParserConfigurationException, IOException {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,7 +16,6 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
-import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.File;
@@ -38,12 +37,7 @@
     myAuthSettings = authSettings;
   }
 
-
-  protected CommandResult runCommand(@NotNull MercurialCommandLine cli, @NotNull CommandSettings s) throws VcsException {
-    s.setPrivateData(getPrivateData());
-    return CommandUtil.runCommand(cli, s);
-  }
-
+  @NotNull
   protected Set<String> getPrivateData() {
     String password = myAuthSettings.getPassword();
     return password != null ? Collections.singleton(password) : Collections.<String>emptySet();
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java	Thu Apr 17 20:16:48 2014 +0200
@@ -43,7 +43,7 @@
     cli.addParameter("version");
     cli.addParameter("--quiet");
     setDefaultLocale(cli);
-    CommandResult result = CommandUtil.runCommand(cli, myCommandSettings);
+    CommandResult result = runCommand(cli, myCommandSettings);
     return HgVersion.parse(result.getStdout());
   }
 
--- a/mercurial-server-tc/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSubrepoUsageStatistics.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server-tc/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSubrepoUsageStatistics.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,29 +16,30 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import jetbrains.buildServer.usageStatistics.impl.providers.BaseVCSFeatureUsageStatisticsProvider;
 import jetbrains.buildServer.vcs.SVcsRoot;
 import jetbrains.buildServer.vcs.VcsManager;
 import org.jetbrains.annotations.NotNull;
 
-public class MercurialSubrepoUsageStatistics /*extends BaseVCSFeatureUsageStatisticsProvider*/ {
+public class MercurialSubrepoUsageStatistics extends BaseVCSFeatureUsageStatisticsProvider {
 
   public MercurialSubrepoUsageStatistics(@NotNull VcsManager vcsManager) {
-//    super(vcsManager);
+    super(vcsManager);
   }
 
   @NotNull
-//  @Override
+  @Override
   protected String getFeatureName() {
     return "subRepoSupport-mercurial";
   }
 
   @NotNull
-//  @Override
+  @Override
   protected String getFeatureDisplayName() {
     return "Mercurial VCS roots with subrepo support enabled";
   }
 
-//  @Override
+  @Override
   protected boolean hasFeature(@NotNull SVcsRoot root) {
     return Boolean.parseBoolean(root.getProperty(Constants.DETECT_SUBREPO_CHANGES));
   }
--- a/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml	Thu Apr 17 20:16:48 2014 +0200
@@ -31,4 +31,7 @@
 
   <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialCommitsInfoBuilderSupport"/>
   <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialModificationInfoBuilder"/>
+
+  <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl"/>
+  <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver"/>
 </beans>
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java	Thu Apr 17 20:16:48 2014 +0200
@@ -47,8 +47,8 @@
 
 
   public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException {
-    HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot);
-    HgRepo repo = createRepo(root);
+    final HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot);
+    final HgRepo repo = createRepo(root);
     try {
       repo.id().repository(root.getRepository())
               .withAuthSettings(root.getAuthSettings())
@@ -64,8 +64,9 @@
     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());
+  @NotNull
+  private HgRepo createRepo(HgVcsRoot root) throws VcsException {
+    return myRepoFactory.createRepo(root, getWorkingDir(root));
   }
 
   private File getWorkingDir(HgVcsRoot root) {
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Thu Apr 17 20:16:48 2014 +0200
@@ -123,7 +123,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 = myHgVcsRootFactory.createHgRoot(vcsRoot);
+    HgVcsRoot root = getHgRoot(vcsRoot);
     syncRepository(root, cset);
     HgRepo repo = createRepo(root);
     File parentDir = repo.cat().files(filePath).atRevision(cset).call();
@@ -138,6 +138,11 @@
   }
 
   @NotNull
+  public HgVcsRoot getHgRoot(@NotNull final VcsRoot vcsRoot) throws VcsException {
+    return myHgVcsRootFactory.createHgRoot(vcsRoot);
+  }
+
+  @NotNull
   public String getName() {
     return Constants.VCS_NAME;
   }
@@ -174,11 +179,12 @@
   }
 
   @NotNull
-  public String describeVcsRoot(final VcsRoot vcsRoot) {
+  public String describeVcsRoot(@NotNull final VcsRoot vcsRoot) {
     return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP);
   }
 
   @Override
+  @NotNull
   public TestConnectionSupport getTestConnectionSupport() {
     return myTestConnection;
   }
@@ -227,21 +233,28 @@
       }
     }
 
-    File parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call();
+    File parentDir = null;
     try {
-      for (FileStatus f: modifiedFiles) {
-        String mappedPath = checkoutRules.map(f.getPath());
-        if (mappedPath == null) continue; // skip
-        final File virtualFile = new File(mappedPath);
-        if (f.getStatus() == Status.REMOVED) {
-          builder.deleteFile(virtualFile, true);
-        } else {
-          File realFile = new File(parentDir, f.getPath());
-          FileInputStream is = new FileInputStream(realFile);
-          try {
-            builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length());
-          } finally {
-            is.close();
+      if (root.useArchiveForPatch()) {
+        parentDir = HgFileUtil.createTempDir();
+        File archFile = new File(parentDir, "arch.tar");
+        buildIncrementalPatchWithArchive(builder, repo, toVer, checkoutRules, modifiedFiles, notDeletedFiles, archFile);
+      } else {
+        parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call();
+        for (FileStatus f: modifiedFiles) {
+          String mappedPath = checkoutRules.map(f.getPath());
+          if (mappedPath == null) continue; // skip
+          final File virtualFile = new File(mappedPath);
+          if (f.getStatus() == Status.REMOVED) {
+            builder.deleteFile(virtualFile, true);
+          } else {
+            File realFile = new File(parentDir, f.getPath());
+            FileInputStream is = new FileInputStream(realFile);
+            try {
+              builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length());
+            } finally {
+              is.close();
+            }
           }
         }
       }
@@ -253,7 +266,50 @@
       builder.deleteDirectory(new File(""), true);//clean patch
       buildFullPatch(root, toVer, builder, checkoutRules);
     } finally {
-      deleteDir(parentDir, Loggers.VCS);
+      if (parentDir != null)
+        deleteDir(parentDir, Loggers.VCS);
+    }
+  }
+
+  private void buildIncrementalPatchWithArchive(@NotNull PatchBuilder builder,
+                                                @NotNull HgRepo repo,
+                                                @NotNull ChangeSet toVer,
+                                                @NotNull CheckoutRules checkoutRules,
+                                                @NotNull List<FileStatus> modifiedFiles,
+                                                @NotNull List<String> notDeletedFiles,
+                                                @NotNull File archiveFile) throws VcsException, IOException {
+    ArchiveCommand archive = repo.archive().revision(toVer).type("tar").destination(archiveFile);
+    int i = 0;
+    while (i < notDeletedFiles.size()) {
+      String mappedPath = checkoutRules.map(notDeletedFiles.get(i));
+      if (mappedPath == null) {
+        i++;
+        continue;
+      }
+      if (archive.addIncludeRule(notDeletedFiles.get(i))) {
+        i++;
+        continue;
+      }
+      //archive command is full, call it
+      archive.call();
+      buildPatchFromArchive(builder, archiveFile, checkoutRules, new ExcludeHgArchival());
+      FileUtil.delete(archiveFile);
+      archive = repo.archive().revision(toVer).type("tar").destination(archiveFile);
+    }
+    if (!notDeletedFiles.isEmpty()) {
+      archive.call();
+      buildPatchFromArchive(builder, archiveFile, checkoutRules, new ExcludeHgArchival());
+      FileUtil.delete(archiveFile);
+    }
+
+    //delete removed files
+    for (FileStatus f: modifiedFiles) {
+      if (f.getStatus() == Status.REMOVED) {
+        String mappedPath = checkoutRules.map(f.getPath());
+        if (mappedPath == null)
+          continue; // skip
+        builder.deleteFile(new File(mappedPath), true);
+      }
     }
   }
 
@@ -338,11 +394,7 @@
           if (root.useArchiveForPatch()) {
             File archive = new File(tempDir, "arch.tar");
             repo.archive().revision(toVer).type("tar").destination(archive).call();
-            buildPatchFromArchive(builder, archive, checkoutRules, new FileFilter() {
-              public boolean accept(File f) {
-                return !f.getName().equals(".hg_archival.txt");
-              }
-            });
+            buildPatchFromArchive(builder, archive, checkoutRules, new ExcludeHgArchival());
           } else {
             repo.archive().revision(toVer).destination(tempDir).call();
             buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter);
@@ -353,11 +405,7 @@
         if (root.useArchiveForPatch()) {
           File archive = new File(tempDir, "arch.tar");
           repo.archive().revision(toVer).type("tar").destination(archive).call();
-          buildPatchFromArchive(builder, archive, checkoutRules, new FileFilter() {
-            public boolean accept(File f) {
-              return !f.getName().equals(".hg_archival.txt");
-            }
-          });
+          buildPatchFromArchive(builder, archive, checkoutRules, new ExcludeHgArchival());
         } else {
           repo.archive().revision(toVer).destination(tempDir).call();
           buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter);
@@ -490,7 +538,7 @@
   }
 
   public void syncRepository(@NotNull final VcsRoot root) throws VcsException {
-    syncRepository(myHgVcsRootFactory.createHgRoot(root));
+    syncRepository(getHgRoot(root));
   }
 
   public void syncRepository(@NotNull final HgVcsRoot root) throws VcsException {
@@ -561,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 = myHgVcsRootFactory.createHgRoot(root);
+    HgVcsRoot hgRoot = getHgRoot(root);
     buildPatch(hgRoot, fromVersion, toVersion, builder, checkoutRules);
   }
 
@@ -604,11 +652,12 @@
     return myConfig.allowSourceCaching();
   }
 
+  @NotNull
   public String label(@NotNull String label, @NotNull String version, @NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules) throws VcsException {
     File tmpDir = null;
     try {
       tmpDir = createLabelingTmpDir();
-      HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root);
+      HgVcsRoot hgRoot = getHgRoot(root);
       hgRoot.setCustomWorkingDir(tmpDir);
       syncRepository(hgRoot);
       HgRepo repo = createRepo(hgRoot);
@@ -643,7 +692,7 @@
     return label.replace(':', '_').replace('\r', '_').replace('\n', '_');
   }
 
-  public File getWorkingDir(@NotNull HgVcsRoot root) {
+  public File getWorkingDir(HgVcsRoot root) {
     File customDir = root.getCustomWorkingDir();
     return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository());
   }
@@ -686,17 +735,19 @@
     }
   }
 
+  @NotNull
   public ServerHgRepo createRepo(@NotNull HgVcsRoot root) throws VcsException {
-    return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings());
+    return myRepoFactory.createRepo(root, getWorkingDir(root));
   }
 
+  @NotNull
   public ServerHgRepo createRepo(@NotNull OperationContext ctx, @NotNull HgVcsRoot root) throws VcsException {
-    return ctx.createRepo(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings());
+    return ctx.createRepo(root, getWorkingDir(root));
   }
 
-
-  public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File customDir) throws VcsException {
-    return myRepoFactory.create(customDir, myHgPathProvider.getHgPath(root), root.getAuthSettings());
+  @NotNull
+  public ServerHgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File customDir) throws VcsException {
+    return myRepoFactory.createRepo(root, customDir);
   }
 
   @NotNull
@@ -729,4 +780,11 @@
     }
     return super.getVcsCustomExtension(extensionClass);
   }
+
+
+  private static class ExcludeHgArchival implements FileFilter {
+    public boolean accept(File f) {
+      return !f.getName().equals(".hg_archival.txt");
+    }
+  }
 }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java	Thu Apr 17 20:16:48 2014 +0200
@@ -18,10 +18,10 @@
 
 import com.intellij.openapi.util.Pair;
 import gnu.trove.TLongObjectHashMap;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
 import jetbrains.buildServer.util.Hash;
-import jetbrains.buildServer.util.graph.*;
+import jetbrains.buildServer.util.graph.BFSVisitorAdapter;
+import jetbrains.buildServer.util.graph.DAG;
 import jetbrains.buildServer.vcs.ModificationData;
 import jetbrains.buildServer.vcs.RepositoryStateData;
 import jetbrains.buildServer.vcs.VcsException;
@@ -117,11 +117,13 @@
   }
 
   @NotNull
-  public ServerHgRepo createRepo(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) throws VcsException {
+  public ServerHgRepo createRepo(@NotNull final HgVcsRoot root, @NotNull final File workingDir) throws VcsException {
     ServerHgRepo repo = myRepos.get(workingDir);
-    if (repo != null)
+    if (repo != null) {
       return repo;
-    repo = myRepoFactory.create(workingDir, hgPath, authSettings);
+    }
+
+    repo = myRepoFactory.createRepo(root, workingDir);
     repo.setOperationContext(this);
     myRepos.put(workingDir, repo);
     return repo;
@@ -208,7 +210,7 @@
                                                       @NotNull String fromRevision,
                                                       @NotNull String toRevision) throws VcsException {
     syncRepository(root);
-    ServerHgRepo repo = createRepo(myVcs.getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings());
+    ServerHgRepo repo = createRepo(root, myVcs.getWorkingDir(root));
 
     if (!repo.supportRevsets())
       return singleton(fromRevision);
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/RepoFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/RepoFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -18,33 +18,26 @@
 
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRoot;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
-import jetbrains.buildServer.util.FileUtil;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.File;
 import java.io.IOException;
 
-import static com.intellij.openapi.util.io.FileUtil.createTempFile;
-import static com.intellij.openapi.util.io.FileUtil.delete;
-
 /**
  * @author dmitry.neverov
  */
 public class RepoFactory implements HgRepoFactory {
 
   protected final ServerPluginConfig myConfig;
-  protected final CommandSettingsFactory myCommandSettingsFactory;
+  protected final CommandSettingsForRoot myCommandSettingsFactory;
   protected final HgPathProvider myHgPathProvider;
 
-  protected final MercurialLogTemplate myLogTemplate = new MercurialLogTemplate("/buildServerResources/log.template", "hg.log.template");
-  protected final MercurialLogTemplate myLogNoFilesTemplate = new MercurialLogTemplate("/buildServerResources/log.no.files.template", "hg.short.log.template");
-  protected final MercurialLogTemplate myDagTemplate = new MercurialLogTemplate("/buildServerResources/dag.template", "hg.dag.template");
-  protected final MercurialLogTemplate myFastLogTemplate = new MercurialLogTemplate("/buildServerResources/fastlog.template", "hg.fastlog.template");
 
   public RepoFactory(@NotNull ServerPluginConfig config,
-                     @NotNull CommandSettingsFactory commandSettingsFactory,
+                     @NotNull CommandSettingsForRoot commandSettingsFactory,
                      @NotNull HgPathProvider hgPathProvider) throws IOException {
     myConfig = config;
     myCommandSettingsFactory = commandSettingsFactory;
@@ -52,58 +45,20 @@
   }
 
   @NotNull
-  public ServerHgRepo create(@NotNull File workingDir,
-                             @NotNull String hgPath,
-                             @NotNull AuthSettings authSettings) throws VcsException {
-    return new ServerHgRepo(myCommandSettingsFactory, myConfig, workingDir, hgPath, authSettings)
-            .withLogTemplates(myLogTemplate.getTemplate(),
-                    myLogNoFilesTemplate.getTemplate(),
-                    myDagTemplate.getTemplate(),
-                    myFastLogTemplate.getTemplate());
+  protected ServerHgRepo create(@NotNull File workingDir,
+                                @NotNull String hgPath,
+                                @NotNull AuthSettings authSettings,
+                                @NotNull CommandSettingsFactory commandSettingsFactory,
+                                @NotNull ServerPluginConfig config) {
+    return new ServerHgRepo(commandSettingsFactory, config, workingDir, hgPath, authSettings);
   }
 
-  public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException {
-    return create(workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings());
+  @NotNull
+  public ServerHgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException {
+    return create(workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings(), myCommandSettingsFactory.forRoot(root), myConfig);
   }
 
   public void dispose() {
-    myLogTemplate.dispose();
-    myLogNoFilesTemplate.dispose();
-    myDagTemplate.dispose();
-    myFastLogTemplate.dispose();
   }
 
-  static class MercurialLogTemplate {
-    private final String myResourcePath;
-    private final String myTmpFileSuffix;
-    private File myFile;
-
-    private MercurialLogTemplate(@NotNull String resourcePath, @NotNull String tmpFileSuffix) throws IOException {
-      myResourcePath = resourcePath;
-      myTmpFileSuffix = tmpFileSuffix;
-      copyTemplate();
-    }
-
-    @NotNull
-    public File getTemplate() throws VcsException {
-      if (myFile.isFile() && myFile.exists())
-        return myFile;
-      try {
-        copyTemplate();
-        return myFile;
-      } catch (IOException e) {
-        throw new VcsException("Cannot create mercurial log template", e);
-      }
-    }
-
-    public void dispose() {
-      delete(myFile);
-    }
-
-    private void copyTemplate() throws IOException {
-      File template = createTempFile("teamcity", myTmpFileSuffix);
-      FileUtil.copyResource(RepoFactory.class, myResourcePath, template);
-      myFile = template;
-    }
-  }
 }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerCommandSettingsFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerCommandSettingsFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -28,6 +28,7 @@
     myConfig = config;
   }
 
+  @NotNull
   public CommandSettings create() {
     return new CommandSettings().setLogLevel("debug").setLogOutputLimit(myConfig.getLogOutputLimit());
   }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java	Thu Apr 17 20:16:48 2014 +0200
@@ -39,10 +39,10 @@
   private final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0);
   private final CommandSettingsFactory myCommandSettingsFactory;
   private final ServerPluginConfig myConfig;
-  private File myLogTemplate;
-  private File myLogNoFilesTemplate;
-  private File myDagTemplate;
-  private File myFastLogTemplate;
+  protected final MercurialClasspathTemplate myLogTemplate = new MercurialClasspathTemplate("/buildServerResources/log.template", "hg.log.template");
+  protected final MercurialClasspathTemplate myLogNoFilesTemplate = new MercurialClasspathTemplate("/buildServerResources/log.no.files.template", "hg.short.log.template");
+  protected final MercurialClasspathTemplate myDagTemplate = new MercurialClasspathTemplate("/buildServerResources/dag.template", "hg.dag.template");
+  protected final MercurialClasspathTemplate myFastLogTemplate = new MercurialClasspathTemplate("/buildServerResources/fastlog.template", "hg.fastlog.template");
   private OperationContext myContext;
 
   public ServerHgRepo(@NotNull CommandSettingsFactory commandSettingsFactory,
@@ -59,17 +59,6 @@
     myContext = context;
   }
 
-  public ServerHgRepo withLogTemplates(@NotNull File logTemplate,
-                                       @NotNull File logNoFilesTemplate,
-                                       @NotNull File dagTemplate,
-                                       @NotNull File fastLogTemplate) {
-    myLogTemplate = logTemplate;
-    myLogNoFilesTemplate = logNoFilesTemplate;
-    myDagTemplate = dagTemplate;
-    myFastLogTemplate = fastLogTemplate;
-    return this;
-  }
-
   public LogCommand log() {
     return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings).withTemplate(myLogTemplate);
   }
@@ -80,7 +69,7 @@
   }
 
   public LogCommand log(@NotNull HgVcsRoot root) {
-    File template = root.isSubrepo() && !myConfig.reportSubrepoChangesFileStatus() ? myFastLogTemplate : myLogTemplate;
+    final MercurialTemplate template = root.isSubrepo() && !myConfig.reportSubrepoChangesFileStatus() ? myFastLogTemplate : myLogTemplate;
     return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings).withTemplate(template);
   }
 
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesNoRevsets.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesNoRevsets.java	Thu Apr 17 20:16:48 2014 +0200
@@ -17,6 +17,7 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
 import com.intellij.openapi.util.Pair;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgRepo;
 import jetbrains.buildServer.util.graph.DAG;
 import jetbrains.buildServer.util.graph.DAGIterator;
@@ -24,7 +25,6 @@
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 
-import java.io.File;
 import java.util.*;
 
 /**
@@ -34,9 +34,9 @@
 
   private final HgVcsRoot myRoot;
   private final ServerHgRepo myRepo;
-  private final File myLogNoFilesTemplate;
+  private final MercurialTemplate myLogNoFilesTemplate;
 
-  public CollectChangesNoRevsets(@NotNull HgVcsRoot root, @NotNull ServerHgRepo repo, @NotNull File logNoFilesTemplate) {
+  public CollectChangesNoRevsets(@NotNull HgVcsRoot root, @NotNull ServerHgRepo repo, @NotNull MercurialTemplate logNoFilesTemplate) {
     myRoot = root;
     myRepo = repo;
     myLogNoFilesTemplate = logNoFilesTemplate;
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleanerTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleanerTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -17,6 +17,8 @@
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
 import jetbrains.buildServer.agent.*;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
 import jetbrains.buildServer.vcs.*;
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
@@ -62,7 +64,7 @@
 
     AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig);
     myMirrorManager = new MirrorManagerImpl(pluginConfig);
-    AgentRepoFactory repoFactory = new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig));
+    AgentRepoFactory repoFactory = new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver()), new AgentHgPathProvider(agentConfig));
     myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, myMirrorManager, repoFactory);
     myCleaner = new AgentMirrorCleaner(myMirrorManager);
     myLogger = myContext.mock(BuildProgressLogger.class);
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -18,6 +18,8 @@
 import jetbrains.buildServer.agent.AgentRunningBuild;
 import jetbrains.buildServer.agent.BuildAgentConfiguration;
 import jetbrains.buildServer.agent.BuildProgressLogger;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
 import jetbrains.buildServer.util.FileUtil;
 import jetbrains.buildServer.util.TestFor;
@@ -75,7 +77,7 @@
     final AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig);
     myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig,
             new MirrorManagerImpl(pluginConfig),
-            new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig)));
+            new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver()), new AgentHgPathProvider(agentConfig)));
 
     myLogger = myContext.mock(BuildProgressLogger.class);
     myContext.checking(new Expectations() {{
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -21,6 +21,8 @@
 import jetbrains.buildServer.agent.BuildProgressLogger;
 import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ConnectionRefusedException;
 import jetbrains.buildServer.util.FileUtil;
@@ -83,7 +85,7 @@
     myMirrorManager = new MirrorManagerImpl(pluginConfig);
     myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig,
             myMirrorManager,
-            new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig)));
+            new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver()), new AgentHgPathProvider(agentConfig)));
 
     myLogger = myContext.mock(BuildProgressLogger.class);
     myContext.checking(new Expectations() {{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ExtensionsTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * 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 jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.vcs.VcsException;
+import jetbrains.buildServer.vcs.VcsRoot;
+import junit.framework.Assert;
+import org.jetbrains.annotations.NotNull;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialSupportBuilder.mercurialSupport;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigBuilder.serverPluginConfig;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
+
+/**
+ * Created 25.02.14 13:17
+ *
+ * @author Eugene Petrenko (eugene.petrenko@jetbrains.com)
+ */
+@RequiredHgVersion(min = "2.0.0")
+public class ExtensionsTest extends BaseMercurialTestCase {
+
+  @Test(dataProviderClass = HgVersionConstraint.class, dataProvider = "installedHgVersion")
+  public void test_no_extension(HgVersion _) throws IOException, VcsException {
+    String extension = "HGExtensionThatDoesNotExits";
+
+    try {
+      runWithExtensions(extension);
+      Assert.fail();
+    } catch (VcsException e) {
+      Assert.assertTrue(e.getMessage().contains(extension));
+    }
+  }
+
+  @Test(dataProviderClass = HgVersionConstraint.class, dataProvider = "installedHgVersion")
+  public void test_extension(HgVersion _) throws IOException, VcsException {
+    runWithExtensions("mq", "largefiles");
+  }
+
+  private void runWithExtensions(@NotNull String... extensions) throws IOException, VcsException {
+    ServerPluginConfig config = serverPluginConfig()
+            .cachesDir(myTempFiles.createTempDir())
+            .hgPath(Util.getHgPath())
+            .build();
+
+    final File myRemoteRepository = myTempFiles.createTempDir();
+    Util.copyRepository(new File("mercurial-tests/testData/rep2"), myRemoteRepository);
+
+
+    final MercurialSupportBuilder hgBuilder = mercurialSupport().withConfig(config);
+    final MercurialVcsSupport vcs = hgBuilder.build();
+    final VcsRoot root = vcsRoot().withUrl(myRemoteRepository.getAbsolutePath()).withBranch("default").withExtensions(extensions).build();
+
+    vcs.getCollectChangesPolicy().getCurrentState(root);
+    vcs.getTestConnectionSupport().testConnection(root);
+  }
+
+
+}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,6 +16,8 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
 import jetbrains.buildServer.serverSide.ServerListener;
 import jetbrains.buildServer.util.EventDispatcher;
@@ -52,7 +54,7 @@
     MirrorManagerImpl mirrorManager = new MirrorManagerImpl(myConfig);
     myHgPathProvider = new ServerHgPathProvider(myConfig);
     if (myRepoFactory == null)
-      myRepoFactory = new RepoFactory(myConfig, new TestCommandSettingsFactory(), myHgPathProvider);
+      myRepoFactory = new RepoFactory(myConfig, new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver()), myHgPathProvider);
     HgTestConnectionSupport testConnection = new HgTestConnectionSupport(myHgRootFactory, myRepoFactory, mirrorManager, myHgPathProvider);
     final ResetCacheRegister resetCacheManager = myContext.mock(ResetCacheRegister.class);
     myContext.checking(new Expectations() {{
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -581,8 +581,6 @@
     if (!SystemInfo.isUnix)
       return;
 
-    RepoFactory repoFactory = new RepoFactory(myPluginConfig, new TestCommandSettingsFactory(), myHgPathProvider);
-
     //create a file on the server
     File dirOnTheServer = myTempFiles.createTempDir();
     File fileOnTheServer = new File(dirOnTheServer, "file.on.server");
@@ -590,7 +588,7 @@
 
     //create a remote repository with symlink pointing to the file on the server
     File repository = copyRepository(myTempFiles, simpleRepo());
-    ServerHgRepo repo = repoFactory.create(repository, getHgPath(), new AuthSettings());
+    ServerHgRepo repo = new ServerHgRepo(new TestCommandSettingsFactory(), myPluginConfig, repository, getHgPath(), new AuthSettings());
     repo.update().toRevision("9c6a6b4aede0").call();
     new ProcessBuilder("ln", "-s", dirOnTheServer.getCanonicalPath()).directory(repository).start().waitFor();
     new ProcessBuilder(getHgPath(), "add", dirOnTheServer.getName()).directory(repository).start().waitFor();
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SubrepoChangesTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SubrepoChangesTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,10 +16,7 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CatCommand;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*;
 import jetbrains.buildServer.vcs.*;
 import org.jetbrains.annotations.NotNull;
 import org.testng.annotations.BeforeMethod;
@@ -230,15 +227,11 @@
             .build();
 
     final AtomicInteger catCallCounter = new AtomicInteger(0);
-    RepoFactory repoFactory = new RepoFactory(pluginConfig, new TestCommandSettingsFactory(), myHgPathProvider) {
+    RepoFactory repoFactory = new RepoFactory(pluginConfig, new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver()), myHgPathProvider) {
       @NotNull
       @Override
-      public ServerHgRepo create(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) throws VcsException {
-        return new CountingServerHgRepo(myCommandSettingsFactory, myConfig, workingDir, hgPath, authSettings, catCallCounter)
-                .withLogTemplates(myLogTemplate.getTemplate(),
-                        myLogNoFilesTemplate.getTemplate(),
-                        myDagTemplate.getTemplate(),
-                        myFastLogTemplate.getTemplate());
+      protected ServerHgRepo create(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings, @NotNull CommandSettingsFactory commandSettingsFactory, @NotNull ServerPluginConfig config) {
+        return new CountingServerHgRepo(commandSettingsFactory, config, workingDir, hgPath, authSettings, catCallCounter);
       }
     };
 
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,6 +16,7 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.vcs.SVcsRoot;
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
 import org.jetbrains.annotations.NotNull;
@@ -30,6 +31,7 @@
  */
 public class VcsRootBuilder {
 
+  private String myExtensions;
   private String myRepository;
   private String myUsername;
   private String myPassword;
@@ -60,6 +62,7 @@
     vcsRoot.addProperty(Constants.DETECT_SUBREPO_CHANGES, String.valueOf(myDetectSubrepoChanges));
     vcsRoot.addProperty(Constants.INCLUDE_SUBREPOS_IN_PATCH, String.valueOf(myIncludeSubreposInPatch));
     vcsRoot.addProperty(Constants.USE_ARCHIVE_FOR_PATCH, String.valueOf(myUseArchiveForPatch));
+    vcsRoot.addProperty(Constants.HG_EXTENSIONS, myExtensions);
     if (myCloneRepositoryTo != null)
       vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, String.valueOf(myCloneRepositoryTo.getAbsolutePath()));
     vcsRoot.addProperty(Constants.USE_TAGS_AS_BRANCHES, String.valueOf(myTagsAsBranches));
@@ -82,6 +85,7 @@
       allowing(root).getProperty(with(Constants.USER_FOR_TAG)); will(returnValue(myUserForTag));
       allowing(root).getProperty(with(Constants.DETECT_SUBREPO_CHANGES)); will(returnValue(String.valueOf(myDetectSubrepoChanges)));
       allowing(root).getProperty(with(Constants.USE_TAGS_AS_BRANCHES)); will(returnValue(String.valueOf(myTagsAsBranches)));
+      allowing(root).getProperty(with(Constants.HG_EXTENSIONS)); will(returnValue(myExtensions));
     }});
     if (myCloneRepositoryTo != null) {
       context.checking(new Expectations() {{
@@ -97,6 +101,12 @@
     return this;
   }
 
+  @NotNull
+  public VcsRootBuilder withExtensions(@NotNull String... extensions) {
+    myExtensions = StringUtil.join(extensions, "\n");
+    return this;
+  }
+
 
   public VcsRootBuilder withLocalRepository(@NotNull final File repo) {
     return withUrl(repo.getPath()).withCloneRepositoryTo(repo.getParentFile());
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java	Thu Apr 17 20:16:48 2014 +0200
@@ -17,8 +17,8 @@
 
 import jetbrains.buildServer.TempFiles;
 import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport;
-import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialClasspathTemplate;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate;
 import jetbrains.buildServer.vcs.VcsException;
 import org.jetbrains.annotations.NotNull;
 import org.testng.annotations.AfterMethod;
@@ -35,7 +35,7 @@
 public class LogCommandTest extends BaseCommandTestCase {
 
   private TempFiles myTempFiles = new TempFiles();
-  private File myTemplateFile;
+  private MercurialTemplate myTemplateFile;
 
 
   @BeforeMethod
@@ -43,8 +43,7 @@
   protected void setUp() throws Exception {
     super.setUp();
     setRepository("mercurial-tests/testData/rep1", true);
-    myTemplateFile = myTempFiles.createTempFile();
-    FileUtil.copyResource(MercurialVcsSupport.class, "/buildServerResources/log.template", myTemplateFile);
+    myTemplateFile = new MercurialClasspathTemplate("/buildServerResources/log.template", "log.template") {};
   }
 
 
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TestCommandSettingsFactory.java	Thu Apr 17 19:56:05 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TestCommandSettingsFactory.java	Thu Apr 17 20:16:48 2014 +0200
@@ -16,8 +16,11 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
 
+import org.jetbrains.annotations.NotNull;
+
 public class TestCommandSettingsFactory implements CommandSettingsFactory {
 
+  @NotNull
   public CommandSettings create() {
     return new CommandSettings().addHgEnv("HGRCPATH", "");
   }