changeset 27:7944e8985ebd

prepare modules structure for agent side checkout
author Pavel.Sher
date Wed, 23 Jul 2008 09:18:03 +0400
parents de75221eb196
children a7cab5083ada
files build.xml mercurial-agent/mercurial-agent.iml mercurial-common/mercurial-common.iml mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java mercurial-server/lib/annotations.jar mercurial-server/lib/common-api.jar mercurial-server/lib/log4j-1.2.12.jar mercurial-server/lib/openapi.jar mercurial-server/lib/patches-impl.jar mercurial-server/lib/resources_en.jar mercurial-server/lib/server-api.jar mercurial-server/lib/src/openApi-source.jar mercurial-server/lib/trove4j.jar mercurial-server/lib/util.jar mercurial-server/mercurial-server.iml mercurial-server/resources/buildServerResources/mercurialSettings.jsp mercurial-server/src/META-INF/build-server-plugin-mercurial.xml mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-tests/mercurial-tests.iml mercurial.ipr mercurial.xml mercurial/lib/annotations.jar mercurial/lib/common-api.jar mercurial/lib/log4j-1.2.12.jar mercurial/lib/openapi.jar mercurial/lib/patches-impl.jar mercurial/lib/resources_en.jar mercurial/lib/server-api.jar mercurial/lib/src/openApi-source.jar mercurial/lib/trove4j.jar mercurial/lib/util.jar mercurial/mercurial.iml mercurial/resources/buildServerResources/mercurialSettings.jsp mercurial/src/META-INF/build-server-plugin-mercurial.xml mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java
diffstat 62 files changed, 1654 insertions(+), 1465 deletions(-) [+]
line wrap: on
line diff
--- a/build.xml	Mon Jul 21 21:22:25 2008 +0400
+++ b/build.xml	Wed Jul 23 09:18:03 2008 +0400
@@ -4,15 +4,18 @@
 
   <property name="distPath" value="${basedir}/dist"/>
 
-  <target name="dist" depends="clean, init, compile.module.mercurial.production">
+  <target name="dist" depends="all">
     <mkdir dir="${distPath}/unpacked"/>
-    <jar destfile="${distPath}/unpacked/mercurial.jar" basedir="${mercurial.output.dir}"/>
+    <jar destfile="${distPath}/unpacked/mercurial-common.jar" basedir="${mercurial-common.output.dir}"/>
+    <jar destfile="${distPath}/unpacked/mercurial-server.jar" basedir="${mercurial-server.output.dir}"/>
+    <jar destfile="${distPath}/unpacked/mercurial-agent.jar" basedir="${mercurial-agent.output.dir}"/>
     <zip basedir="${distPath}/unpacked" destfile="${distPath}/mercurial.zip" includes="**/*"/>
     <zip basedir="${basedir}" destfile="${distPath}/mercurial-src.zip">
       <exclude name=".hg/**"/>
       <exclude name="dist/**"/>
       <exclude name="**/classes/**"/>
       <exclude name="*.iws"/>
+      <exclude name="test-output/**"/>
     </zip>
   </target>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-agent/mercurial-agent.iml	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntryProperties />
+  </component>
+</module>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/mercurial-common.iml	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" name="TeamCityAPI-common" level="project" />
+    <orderEntry type="library" exported="" name="IDEA-openapi" level="project" />
+    <orderEntryProperties />
+  </component>
+</module>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2007 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;
+
+public interface Constants {
+  String REPOSITORY_PROP = "repositoryPath";
+  String HG_COMMAND_PATH_PROP = "hgCommandPath";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2007 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 org.jetbrains.annotations.NotNull;
+
+public class PathUtil {
+  @NotNull
+  public static String normalizeSeparator(@NotNull String repPath) {
+    return repPath.replace('\\', '/');
+  }
+  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class CatCommand {
+  private Settings mySettings;
+  private String myRevId;
+
+  public CatCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public void setRevId(final String revId) {
+    myRevId = revId;
+  }
+
+  public File execute(List<String> relPaths) throws VcsException {
+    File tempDir;
+    try {
+      tempDir = FileUtil.createTempDirectory("mercurial", "catresult");
+    } catch (IOException e) {
+      throw new VcsException("Unable to create temporary directory");
+    }
+    for (String path: relPaths) {
+      final File parentFile = new File(tempDir, path).getParentFile();
+      if (!parentFile.isDirectory() && !parentFile.mkdirs()) {
+        throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath());
+      }
+    }
+
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.addParameter("cat");
+    cli.addParameter("-o");
+    cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p");
+    if (myRevId != null) {
+      cli.addParameter("-r");
+      cli.addParameter(myRevId);
+    }
+    for (String p: relPaths) {
+      cli.addParameter(FileUtil.normalizeSeparator(p));
+    }
+    CommandUtil.runCommand(cli);
+    return tempDir;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2007 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;
+
+import java.util.Date;
+
+/**
+ * Represents Mercurial change set
+ */
+public class ChangeSet {
+  private int myRevNumber;
+  @NotNull private String myId;
+  @NotNull private String myUser;
+  @NotNull private Date myTimestamp;
+  private String mySummary;
+
+  public ChangeSet(final int revNumber, @NotNull final String id) {
+    myRevNumber = revNumber;
+    myId = id;
+  }
+
+  /**
+   * Constructor for version in the form revnum:changeset_id
+   * @param fullVersion full changeset version as reported by hg log command
+   */
+  public ChangeSet(@NotNull final String fullVersion) {
+    try {
+      String[] parts = fullVersion.split(":");
+      myRevNumber = Integer.parseInt(parts[0]);
+      myId = parts[1];
+    } catch (Throwable e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+
+  public void setUser(@NotNull final String user) {
+    myUser = user;
+  }
+
+  public void setTimestamp(@NotNull final Date timestamp) {
+    myTimestamp = timestamp;
+  }
+
+  public void setSummary(final String summary) {
+    mySummary = summary;
+  }
+
+  /**
+   * Returns changeset revision id
+   * @return changeset revision id
+   */
+  @NotNull
+  public String getId() {
+    return myId;
+  }
+
+  /**
+   * Returns changeset revision number
+   * @return changeset revision number
+   */
+  public int getRevNumber() {
+    return myRevNumber;
+  }
+
+  /**
+   * Returns full changeset version as reported by hg log command: revnum:revid
+   * @return full changeset version as reported by hg log
+   */
+  @NotNull
+  public String getFullVersion() {
+    return myRevNumber + ":" + myId;
+  }
+
+  /**
+   * Returns user who made changeset
+   * @return user who made changeset
+   */
+  @NotNull
+  public String getUser() {
+    return myUser;
+  }
+
+  /**
+   * Returns changeset timestamp
+   * @return changeset timestamp
+   */
+  @NotNull
+  public Date getTimestamp() {
+    return myTimestamp;
+  }
+
+  /**
+   * Returns changeset summary specified by user
+   * @return changeset summary
+   */
+  public String getSummary() {
+    return mySummary;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+public class CloneCommand {
+  private Settings mySettings;
+  private String myDestDir;
+  private String myToId;
+  private boolean myUpdateWorkingDir = true;
+
+  public CloneCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public void setDestDir(@NotNull String destDir) {
+    myDestDir = destDir;
+  }
+
+  public void setToId(final String toId) {
+    myToId = toId;
+  }
+
+  public void setUpdateWorkingDir(final boolean updateWorkingDir) {
+    myUpdateWorkingDir = updateWorkingDir;
+  }
+
+  public void execute() throws VcsException {
+    if (myDestDir == null) throw new IllegalStateException("Destination dir must be specified");
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    File dir = new File(myDestDir);
+    File parent = dir.getParentFile();
+    cli.setWorkDirectory(parent.getAbsolutePath());
+    cli.addParameter("clone");
+    if (myToId != null) {
+      cli.addParameter("-r");
+      cli.addParameter(myToId);
+    }
+    cli.addParameter("--pull");
+    if (!myUpdateWorkingDir) {
+      cli.addParameter("-U");
+    }
+    cli.addParameter(mySettings.getRepository());
+    cli.addParameter(dir.getName());
+
+    CommandUtil.runCommand(cli);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.SimpleCommandLineProcessRunner;
+import jetbrains.buildServer.log.Loggers;
+import jetbrains.buildServer.util.StringUtil;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+public class CommandUtil {
+  public static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res) throws VcsException {
+    if (res.getExitCode() > 0 || res.getException() != null) {
+      commandFailed(cmdName, res);
+    } 
+  }
+
+  public static void commandFailed(final String cmdName, final ExecResult res) throws VcsException {
+    Throwable exception = res.getException();
+    String stderr = res.getStderr();
+    String stdout = res.getStdout();
+    final String message = "'" + cmdName + "' command failed.\n" +
+            (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") +
+            (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") +
+            (exception != null ? "exception: " + exception.getLocalizedMessage() : "");
+    Loggers.VCS.warn(message);
+    throw new VcsException(message);
+  }
+
+  public static ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException {
+    String cmdStr = cli.getCommandLineString();
+    Loggers.VCS.debug("Run command: " + cmdStr);
+    ExecResult res = SimpleCommandLineProcessRunner.runCommand(cli, null);
+    CommandUtil.checkCommandFailed(cmdStr, res);
+    return res;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Pavel.Sher
+ *         Date: 16.07.2008
+ */
+public class IdentifyCommand {
+  private Settings mySettings;
+
+  public IdentifyCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public String execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.addParameter("identify");
+    cli.addParameter(mySettings.getRepository());
+    ExecResult res = CommandUtil.runCommand(cli);
+    if (res.getStderr().length() > 0) {
+      CommandUtil.commandFailed(cli.getCommandLineString(), res);
+    }
+    return res.getStdout();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.openapi.diagnostic.Logger;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+public class LogCommand {
+  private final static Logger LOG = Logger.getInstance(LogCommand.class.getName());
+  private String myFromId;
+  private String myToId;
+  private Settings mySettings;
+  private static final String CHANGESET_PREFIX = "changeset:";
+  private static final String USER_PREFIX = "user:";
+  private static final String DATE_PREFIX = "date:";
+  private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z";
+  private static final String SUMMARY_PREFIX = "summary:";
+
+  public LogCommand(@NotNull Settings settings) {
+    mySettings = settings;
+  }
+
+  public void setFromRevId(String id) {
+    myFromId = id;
+  }
+
+  public void setToRevId(String id) {
+    myToId = id;
+  }
+
+  public List<ChangeSet> execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.addParameter("log");
+    cli.addParameter("-r");
+    String from = myFromId;
+    if (from == null) from = "0";
+    String to = myToId;
+    if (to == null) to = "0";
+    cli.addParameter(from + ":" + to);
+
+    ExecResult res = CommandUtil.runCommand(cli);
+    return parseChangeSets(res.getStdout());
+  }
+
+  public static List<ChangeSet> parseChangeSets(final String stdout) {
+    List<ChangeSet> result = new ArrayList<ChangeSet>();
+    String[] lines = stdout.split("\n");
+    ChangeSet current = null;
+    int lineNum = 0;                  
+    while (lineNum < lines.length) {
+      String line = lines[lineNum];
+      lineNum++;
+
+      if (line.startsWith(CHANGESET_PREFIX)) {
+        String revAndId = line.substring(CHANGESET_PREFIX.length()).trim();
+        try {
+          current = new ChangeSet(revAndId);
+          result.add(current);
+        } catch (IllegalArgumentException e) {
+          LOG.warn("Unable to extract changeset id from the line: " + line);
+        }
+
+        continue;
+      }
+
+      if (current == null) continue;
+
+      if (line.startsWith(USER_PREFIX)) {
+        current.setUser(line.substring(USER_PREFIX.length()).trim());
+        continue;
+      }
+
+      if (line.startsWith(DATE_PREFIX)) {
+        String date = line.substring(DATE_PREFIX.length()).trim();
+        try {
+          Date parsedDate = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH).parse(date);
+          current.setTimestamp(parsedDate);
+        } catch (ParseException e) {
+          LOG.warn("Unable to parse date: " + date);
+          current = null;
+        }
+
+        continue;
+      }
+
+      if (line.startsWith(SUMMARY_PREFIX)) {
+        String summary = line.substring(SUMMARY_PREFIX.length()).trim();
+        current.setSummary(summary);
+
+        continue;
+      }
+    }
+
+    return result;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2007 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;
+
+/**
+ * Represents repository modified file
+ */
+public class ModifiedFile {
+  /**
+   * Type of modification
+   */
+  public static enum Status {
+    ADDED("added"),
+    MODIFIED("modified"),
+    REMOVED("removed"),
+    UNKNOWN("unknown");
+    private String myName;
+
+    Status(@NotNull final String name) {
+      myName = name;
+    }
+
+    @NotNull
+    public String getName() {
+      return myName;
+    }
+  }
+
+  @NotNull private Status myStatus;
+  @NotNull private String myPath;
+
+  public ModifiedFile(@NotNull final Status status, @NotNull final String path) {
+    myStatus = status;
+    myPath = path;
+  }
+
+  /**
+   * Returns type of modification
+   * @return type of modification
+   */
+  @NotNull
+  public Status getStatus() {
+    return myStatus;
+  }
+
+  /**
+   * Returns file path
+   * @return file path
+   */
+  @NotNull
+  public String getPath() {
+    return myPath;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Pavel.Sher
+ *         Date: 14.07.2008
+ */
+public class PullCommand {
+  private Settings mySettings;
+
+  public PullCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public void execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.addParameter("pull");
+    cli.addParameter(mySettings.getRepository());
+    CommandUtil.runCommand(cli);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2007 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.buildTriggers.vcs.mercurial.PathUtil;
+import jetbrains.buildServer.vcs.VcsRoot;
+import jetbrains.buildServer.util.Hash;
+import jetbrains.buildServer.util.FileUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * Represents Mercurial repository settings
+ */
+public class Settings {
+  private String myRepository;
+  private String myHgCommandPath;
+  private File myWorkingDir;
+  private File myWorkFolderParentDir;
+
+  public Settings(@NotNull File workFolderParentDir, @NotNull VcsRoot vcsRoot) {
+    myWorkFolderParentDir = workFolderParentDir;
+    setRepository(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
+    setHgCommandPath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
+  }
+
+  public Settings() {
+  }
+
+  public void setRepository(@NotNull final String repository) {
+    myRepository = repository;
+  }
+
+  /**
+   * Returns repository path
+   * @return repository path
+   */
+  @NotNull
+  public String getRepository() {
+    return myRepository;
+  }
+
+  /**
+   * Returns path to hg command
+   * @return path to hg command
+   */
+  @NotNull
+  public String getHgCommandPath() {
+    return myHgCommandPath;
+  }
+
+  public void setHgCommandPath(@NotNull final String hgCommandPath) {
+    myHgCommandPath = hgCommandPath;
+  }
+
+  public void setWorkingDir(@NotNull final File workingDir) {
+    myWorkingDir = FileUtil.getCanonicalFile(workingDir);
+  }
+
+  /**
+   * Returns repository working directory where all mercurial commands should be invoked
+   * @return repository working directory
+   */
+  @NotNull
+  public File getWorkingDir() {
+    if (myWorkingDir != null) {
+      return myWorkingDir;
+    }
+
+    return getDefaultWorkDir(myWorkFolderParentDir, myRepository);
+  }
+
+  public static String DEFAULT_WORK_DIR_PREFIX = "hg_";
+
+  private static File getDefaultWorkDir(@NotNull File workFolderParentDir, @NotNull String repPath) {
+    String workingDirname = DEFAULT_WORK_DIR_PREFIX + String.valueOf(Hash.calc(normalize(repPath)));
+    return FileUtil.getCanonicalFile(new File(workFolderParentDir, workingDirname));
+  }
+
+  private static String normalize(final String path) {
+    String normalized = PathUtil.normalizeSeparator(path);
+    if (path.endsWith("/")) {
+      return normalized.substring(0, normalized.length()-1);
+    }
+    return normalized;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StatusCommand {
+  private Settings mySettings;
+  private String myFromId;
+  private String myToId;
+
+  public StatusCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public void setFromRevId(final String fromId) {
+    myFromId = fromId;
+  }
+
+  public void setToRevId(final String toId) {
+    myToId = toId;
+  }
+
+  public List<ModifiedFile> execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.addParameter("status");
+    cli.addParameter("--rev");
+    String from = myFromId;
+    if (from == null) from = "0";
+    String to = myToId;
+    if (to == null) to = "0";
+    cli.addParameter(from + ":" + to);
+    ExecResult res = CommandUtil.runCommand(cli);
+    return parseFiles(res.getStdout());
+  }
+
+  private List<ModifiedFile> parseFiles(final String stdout) {
+    List<ModifiedFile> result = new ArrayList<ModifiedFile>();
+    String[] lines = stdout.split("\n");
+    for (String line: lines) {
+      if (line.length() == 0) continue;
+      char modifier = line.charAt(0);
+      String path = line.substring(2);
+      ModifiedFile.Status status = toStatus(modifier);
+      if (status == ModifiedFile.Status.UNKNOWN) continue;
+      result.add(new ModifiedFile(status, path));
+    }
+    return result;
+  }
+
+  private ModifiedFile.Status toStatus(final char modifier) {
+    switch (modifier) {
+      case 'A': return ModifiedFile.Status.ADDED;
+      case 'M': return ModifiedFile.Status.MODIFIED;
+      case 'R': return ModifiedFile.Status.REMOVED;
+      default: return ModifiedFile.Status.UNKNOWN;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.ExecResult;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * @author Pavel.Sher
+ *         Date: 14.07.2008
+ */
+public class TipCommand {
+  @NotNull
+  private Settings mySettings;
+
+  public TipCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  @NotNull
+  public ChangeSet execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.addParameter("tip");
+    ExecResult res = CommandUtil.runCommand(cli);
+    List<ChangeSet> changeSets = LogCommand.parseChangeSets(res.getStdout());
+    if (changeSets.isEmpty()) {
+      CommandUtil.commandFailed("hg tip", res);
+    }
+
+    return changeSets.get(0);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+public class UpdateCommand {
+  private Settings mySettings;
+
+  public UpdateCommand(@NotNull final Settings settings) {
+    mySettings = settings;
+  }
+
+  public void execute() throws VcsException {
+    GeneralCommandLine cli = new GeneralCommandLine();
+    cli.setExePath(mySettings.getHgCommandPath());
+    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
+    cli.addParameter("update");
+    cli.addParameter("-C");
+    CommandUtil.runCommand(cli);
+  }
+}
Binary file mercurial-server/lib/annotations.jar has changed
Binary file mercurial-server/lib/common-api.jar has changed
Binary file mercurial-server/lib/log4j-1.2.12.jar has changed
Binary file mercurial-server/lib/openapi.jar has changed
Binary file mercurial-server/lib/patches-impl.jar has changed
Binary file mercurial-server/lib/resources_en.jar has changed
Binary file mercurial-server/lib/server-api.jar has changed
Binary file mercurial-server/lib/src/openApi-source.jar has changed
Binary file mercurial-server/lib/trove4j.jar has changed
Binary file mercurial-server/lib/util.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/mercurial-server.iml	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration>
+        <options>
+          <option name="enableValidation" value="false" />
+          <option name="reportErrorsAsWarnings" value="true" />
+        </options>
+        <customNs />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <excludeFolder url="file://$MODULE_DIR$/classes" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" name="TeamCityAPI-server" level="project" />
+    <orderEntry type="library" exported="" name="IDEA-openapi" level="project" />
+    <orderEntry type="library" exported="" name="TeamCity-impl" level="project" />
+    <orderEntry type="library" exported="" name="Log4j" level="project" />
+    <orderEntry type="library" exported="" name="GNU Trove" level="project" />
+    <orderEntry type="module" module-name="mercurial-common" />
+    <orderEntryProperties />
+  </component>
+</module>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/resources/buildServerResources/mercurialSettings.jsp	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,19 @@
+<%@include file="/include.jsp"%>
+<%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
+<jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
+<table class="runnerFormTable">
+
+  <l:settingsGroup title="Mercurial Settings">
+  <tr>
+    <th><label for="hgCommandPath">HG command path: <l:star/></label></th>
+    <td><props:textProperty name="hgCommandPath" className="longField" />
+      <span class="error" id="error_hgCommandPath"></span></td>
+  </tr>
+  <tr>
+    <th><label for="repositoryPath">Pull changes from: <l:star/></label></th>
+    <td><props:textProperty name="repositoryPath" className="longField" />
+      <span class="error" id="error_repositoryPath"></span></td>
+  </tr>
+  </l:settingsGroup>
+  
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<beans default-autowire="constructor">
+  <bean id="svn" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport" />
+</beans>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Wed Jul 23 09:18:03 2008 +0400
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2000-2007 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.CollectChangesByIncludeRule;
+import jetbrains.buildServer.Used;
+import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*;
+import jetbrains.buildServer.log.Loggers;
+import jetbrains.buildServer.serverSide.InvalidProperty;
+import jetbrains.buildServer.serverSide.PropertiesProcessor;
+import jetbrains.buildServer.serverSide.SBuildServer;
+import jetbrains.buildServer.serverSide.ServerPaths;
+import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.vcs.*;
+import jetbrains.buildServer.vcs.patches.PatchBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Mercurial VCS plugin for TeamCity works as follows:
+ * <ul>
+ * <li>clones repository to internal storage
+ * <li>before any operation with working copy of repository pulls changes from the original repository
+ * <li>executes corresponding hg command
+ * </ul>
+ *
+ * <p>Working copy of repository is created in the $TEAMCITY_DATA_PATH/system/caches/mercurial folder.
+ * <p>Personal builds (remote runs) are not yet supported, they require corresponding functionality from the IDE.
+ * <p>Checkout on agent mode is not yet supported too.
+ */
+public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule {
+  private ServerPaths myServerPaths;
+  private ConcurrentMap<String, Lock> myWorkDirLocks= new ConcurrentHashMap<String, Lock>();
+  private static final int OLD_WORK_DIRS_CLEANUP_PERIOD = 600;
+  private VcsManager myVcsManager;
+  private File myDefaultWorkFolderParent;
+
+  public MercurialVcsSupport(@NotNull final VcsManager vcsManager,
+                             @NotNull ServerPaths paths,
+                             @NotNull SBuildServer server) {
+    vcsManager.registerVcsSupport(this);
+    myServerPaths = paths;
+    myVcsManager = vcsManager;
+    server.getExecutor().scheduleAtFixedRate(new Runnable() {
+      public void run() {
+        removeOldWorkFolders();
+      }
+    }, 0, OLD_WORK_DIRS_CLEANUP_PERIOD, TimeUnit.SECONDS);
+    myDefaultWorkFolderParent = new File(paths.getCachesDir());
+  }
+
+  public List<ModificationData> collectBuildChanges(final VcsRoot root,
+                                                    @NotNull final String fromVersion,
+                                                    @NotNull final String currentVersion,
+                                                    final CheckoutRules checkoutRules) throws VcsException {
+    updateWorkingDirectory(root);
+    return VcsSupportUtil.collectBuildChanges(root, fromVersion, currentVersion, checkoutRules, this);
+  }
+
+  public List<ModificationData> collectBuildChanges(final VcsRoot root,
+                                                    final String fromVersion,
+                                                    final String currentVersion,
+                                                    final IncludeRule includeRule) throws VcsException {
+    // first obtain changes between specified versions
+    List<ModificationData> result = new ArrayList<ModificationData>();
+    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    LogCommand lc = new LogCommand(settings);
+    lc.setFromRevId(new ChangeSet(fromVersion).getId());
+    lc.setToRevId(new ChangeSet(currentVersion).getId());
+    List<ChangeSet> changeSets = lc.execute();
+    if (changeSets.isEmpty()) {
+      return result;
+    }
+
+    // invoke status command for each changeset and determine what files were modified in these changesets
+    Iterator<ChangeSet> it = changeSets.iterator();
+    ChangeSet prev = it.next(); // skip first changeset (cause it was already reported)
+    StatusCommand st = new StatusCommand(settings);
+    while (it.hasNext()) {
+      ChangeSet cur = it.next();
+      st.setFromRevId(prev.getId());
+      st.setToRevId(cur.getId());
+      List<ModifiedFile> modifiedFiles = st.execute();
+      // changeset full version will be set into VcsChange structure and
+      // stored in database (note that getContent method will be invoked with this version)
+      List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), includeRule);
+      if (files.isEmpty()) continue;
+      ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getSummary(), cur.getUser(), root, cur.getFullVersion(), cur.getFullVersion());
+      result.add(md);
+      prev = cur;
+    }
+
+    return result;
+  }
+
+  private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, final IncludeRule includeRule) {
+    List<VcsChange> files = new ArrayList<VcsChange>();
+    for (ModifiedFile mf: modifiedFiles) {
+      String normalizedPath = PathUtil.normalizeSeparator(mf.getPath());
+      if (!normalizedPath.startsWith(includeRule.getFrom())) continue; // skip files which do not match include rule
+
+      VcsChangeInfo.Type changeType = getChangeType(mf.getStatus());
+      if (changeType == null) {
+        Loggers.VCS.warn("Unable to convert status: " + mf.getStatus() + " to VCS change type");
+        changeType = VcsChangeInfo.Type.NOT_CHANGED;
+      }
+      files.add(new VcsChange(changeType, mf.getStatus().getName(), normalizedPath, normalizedPath, prevVer, curVer));
+    }
+    return files;
+  }
+
+  private VcsChangeInfo.Type getChangeType(final ModifiedFile.Status status) {
+    switch (status) {
+      case ADDED:return VcsChangeInfo.Type.ADDED;
+      case MODIFIED:return VcsChangeInfo.Type.CHANGED;
+      case REMOVED:return VcsChangeInfo.Type.REMOVED;
+    }
+    return null;
+  }
+
+  @NotNull
+  public byte[] getContent(final VcsModification vcsModification,
+                           final VcsChangeInfo change,
+                           final VcsChangeInfo.ContentType contentType,
+                           final VcsRoot vcsRoot) throws VcsException {
+    updateWorkingDirectory(vcsRoot);
+    String version = contentType == VcsChangeInfo.ContentType.AFTER_CHANGE ? change.getAfterChangeRevisionNumber() : change.getBeforeChangeRevisionNumber();
+    return getContent(change.getRelativeFileName(), vcsRoot, version);
+  }
+
+  @NotNull
+  public byte[] getContent(final String filePath, final VcsRoot vcsRoot, final String version) throws VcsException {
+    updateWorkingDirectory(vcsRoot);
+    Settings settings = new Settings(myDefaultWorkFolderParent, vcsRoot);
+    CatCommand cc = new CatCommand(settings);
+    ChangeSet cs = new ChangeSet(version);
+    cc.setRevId(cs.getId());
+    File parentDir = cc.execute(Collections.singletonList(filePath));
+    File file = new File(parentDir, filePath);
+    if (file.isFile()) {
+      try {
+        return FileUtil.loadFileBytes(file);
+      } catch (IOException e) {
+        throw new VcsException("Failed to load content of file: " + file.getAbsolutePath(), e);
+      }
+    } else {
+      Loggers.VCS.warn("Unable to obtain content of the file: " + filePath);
+    }
+    return new byte[0];
+  }
+
+  public String getName() {
+    return "mercurial";
+  }
+
+  @Used("jsp")
+  public String getDisplayName() {
+    return "Mercurial";
+  }
+
+  @Nullable
+  public PropertiesProcessor getVcsPropertiesProcessor() {
+    return new AbstractVcsPropertiesProcessor() {
+      public Collection<InvalidProperty> process(final Map<String, String> properties) {
+        List<InvalidProperty> result = new ArrayList<InvalidProperty>();
+        if (isEmpty(properties.get(Constants.HG_COMMAND_PATH_PROP))) {
+          result.add(new InvalidProperty(Constants.HG_COMMAND_PATH_PROP, "Path to 'hg' command must be specified"));
+        } 
+        if (isEmpty(properties.get(Constants.REPOSITORY_PROP))) {
+          result.add(new InvalidProperty(Constants.REPOSITORY_PROP, "Repository must be specified"));
+        }
+        return result;
+      }
+    };
+  }
+
+  public String getVcsSettingsJspFilePath() {
+    return "mercurialSettings.jsp";
+  }
+
+  @NotNull
+  public String getCurrentVersion(final VcsRoot root) throws VcsException {
+    // we will return full version of the most recent change as current version
+    updateWorkingDirectory(root);
+    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    TipCommand lc = new TipCommand(settings);
+    ChangeSet changeSet = lc.execute();
+    return changeSet.getFullVersion();
+  }
+
+  public String describeVcsRoot(final VcsRoot vcsRoot) {
+    return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP);
+  }
+
+  public boolean isTestConnectionSupported() {
+    return true;
+  }
+
+  @Nullable
+  public String testConnection(final VcsRoot vcsRoot) throws VcsException {
+    Settings settings = new Settings(myDefaultWorkFolderParent, vcsRoot);
+    IdentifyCommand id = new IdentifyCommand(settings);
+    StringBuilder res = new StringBuilder();
+    res.append(quoteIfNeeded(settings.getHgCommandPath()));
+    res.append(" identify ");
+    res.append(quoteIfNeeded(settings.getRepository()));
+    res.append('\n').append(id.execute());
+    return res.toString();
+  }
+
+  private String quoteIfNeeded(@NotNull String str) {
+    if (str.indexOf(' ') != -1) {
+      return "\"" + str + "\"";
+    }
+
+    return str;
+  }
+
+  @Nullable
+  public Map<String, String> getDefaultVcsProperties() {
+    return Collections.singletonMap(Constants.HG_COMMAND_PATH_PROP, "hg");
+  }
+
+  public String getVersionDisplayName(final String version, final VcsRoot root) throws VcsException {
+    return version;
+  }
+
+  @NotNull
+  public Comparator<String> getVersionComparator() {
+    // comparator is called when TeamCity needs to sort modifications in the order of their appearance,
+    // currently we sort changes by revision number, not sure however that this is a good idea,
+    // probably it would be better to sort them by timestamp (and to add timestamp into the version).
+    return new Comparator<String>() {
+      public int compare(final String o1, final String o2) {
+        try {
+          return new ChangeSet(o1).getRevNumber() - new ChangeSet(o2).getRevNumber();
+        } catch (Exception e) {
+          return 1;
+        }
+      }
+    };
+  }
+
+  public void buildPatch(final VcsRoot root,
+                         @Nullable final String fromVersion,
+                         @NotNull final String toVersion,
+                         final PatchBuilder builder,
+                         final CheckoutRules checkoutRules) throws IOException, VcsException {
+    updateWorkingDirectory(root);
+    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    if (fromVersion == null) {
+      buildFullPatch(settings, new ChangeSet(toVersion), builder);
+    } else {
+      buildIncrementalPatch(settings, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder);
+    }
+  }
+
+  // builds patch from version to version
+  private void buildIncrementalPatch(final Settings settings, @NotNull final ChangeSet fromVer, @NotNull final ChangeSet toVer, final PatchBuilder builder)
+    throws VcsException, IOException {
+    StatusCommand st = new StatusCommand(settings);
+    st.setFromRevId(fromVer.getId());
+    st.setToRevId(toVer.getId());
+    List<ModifiedFile> modifiedFiles = st.execute();
+    List<String> notDeletedFiles = new ArrayList<String>();
+    for (ModifiedFile f: modifiedFiles) {
+      if (f.getStatus() != ModifiedFile.Status.REMOVED) {
+        notDeletedFiles.add(f.getPath());
+      }
+    }
+
+    CatCommand cc = new CatCommand(settings);
+    cc.setRevId(toVer.getId());
+    File parentDir = cc.execute(notDeletedFiles);
+
+    try {
+      for (ModifiedFile f: modifiedFiles) {
+        final File virtualFile = new File(f.getPath());
+        if (f.getStatus() == ModifiedFile.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();
+          }
+        }
+      }
+    } finally {
+      FileUtil.delete(parentDir);
+    }
+  }
+
+  // builds patch by exporting files using specified version
+  private void buildFullPatch(final Settings settings, @NotNull final ChangeSet toVer, final PatchBuilder builder)
+    throws IOException, VcsException {
+    CloneCommand cl = new CloneCommand(settings);
+    cl.setToId(toVer.getId());
+    File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId());
+    try {
+      final File repRoot = new File(tempDir, "rep");
+      cl.setDestDir(repRoot.getAbsolutePath());
+      cl.execute();
+      buildPatchFromDirectory(builder, repRoot, new FileFilter() {
+        public boolean accept(final File file) {
+          return !(file.isDirectory() && ".hg".equals(file.getName()));
+        }
+      });
+    } finally {
+      FileUtil.delete(tempDir);
+    }
+  }
+
+  private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException {
+    buildPatchFromDirectory(repRoot, builder, repRoot, filter);
+  }
+
+  private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException {
+    File[] files = curDir.listFiles(filter);
+    if (files != null) {
+      for (File realFile: files) {
+        String relPath = realFile.getAbsolutePath().substring(repRoot.getAbsolutePath().length());
+        final File virtualFile = new File(relPath);
+        if (realFile.isDirectory()) {
+          builder.createDirectory(virtualFile);
+          buildPatchFromDirectory(realFile, builder, repRoot, filter);
+        } else {
+          final FileInputStream is = new FileInputStream(realFile);
+          try {
+            builder.createBinaryFile(virtualFile, null, is, realFile.length());
+          } finally {
+            is.close();
+          }
+        }
+      }
+    }
+  }
+
+  // updates current working copy of repository by pulling changes from the repository specified in VCS root
+  private void updateWorkingDirectory(final VcsRoot root) throws VcsException {
+    Settings settings = new Settings(myDefaultWorkFolderParent, root);
+    File workDir = settings.getWorkingDir();
+    lockWorkDir(workDir);
+    try {
+      if (hasRepositoryCopy(workDir)) {
+        // update
+        PullCommand pull = new PullCommand(settings);
+        pull.execute();
+      } else {
+        // clone
+        CloneCommand cl = new CloneCommand(settings);
+        cl.setDestDir(workDir.getAbsolutePath());
+        cl.setUpdateWorkingDir(false);
+        cl.execute();
+      }
+    } finally {
+      unlockWorkDir(workDir);
+    }
+  }
+
+  private void lockWorkDir(@NotNull File workDir) {
+    getWorkDirLock(workDir).lock();
+  }
+
+  private void unlockWorkDir(@NotNull File workDir) {
+    getWorkDirLock(workDir).unlock();
+  }
+
+  private Lock getWorkDirLock(final File workDir) {
+    String path = workDir.getAbsolutePath();
+    Lock lock = myWorkDirLocks.get(path);
+    if (lock == null) {
+      lock = new ReentrantLock();
+      Lock curLock = myWorkDirLocks.putIfAbsent(path, lock);
+      if (curLock != null) {
+        lock = curLock;
+      }
+    }
+    return lock;
+  }
+
+  private boolean hasRepositoryCopy(final File workDir) {
+    // need better way to check that repository copy is ok
+    return workDir.isDirectory() && new File(workDir, ".hg").isDirectory();
+  }
+
+  private void removeOldWorkFolders() {
+    File workFoldersParent = new File(myServerPaths.getCachesDir(), "mercurial");
+    if (!workFoldersParent.isDirectory()) return;
+
+    Set<File> workDirs = new HashSet<File>();
+    File[] files = workFoldersParent.listFiles(new FileFilter() {
+      public boolean accept(final File file) {
+        return file.isDirectory() && file.getName().startsWith(Settings.DEFAULT_WORK_DIR_PREFIX);
+      }
+    });
+    if (files != null) {
+      for (File f: files) {
+        workDirs.add(FileUtil.getCanonicalFile(f));
+      }
+    }
+
+    for (VcsRoot vcsRoot: myVcsManager.getAllRegisteredVcsRoots()) {
+      if (getName().equals(vcsRoot.getVcsName())) {
+        Settings s = new Settings(myDefaultWorkFolderParent, vcsRoot);
+        workDirs.remove(FileUtil.getCanonicalFile(s.getWorkingDir()));
+      }
+    }
+
+    for (File f: workDirs) {
+      lockWorkDir(f);
+      try {
+        FileUtil.delete(f);
+      } finally {
+        unlockWorkDir(f);
+      }
+    }
+  }
+}
--- a/mercurial-tests/mercurial-tests.iml	Mon Jul 21 21:22:25 2008 +0400
+++ b/mercurial-tests/mercurial-tests.iml	Wed Jul 23 09:18:03 2008 +0400
@@ -8,11 +8,13 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module" module-name="mercurial" />
+    <orderEntry type="module" module-name="mercurial-server" />
     <orderEntry type="library" name="TeamCity-testsSupport" level="project" />
     <orderEntry type="library" name="JUnit" level="project" />
     <orderEntry type="library" name="TestNG" level="project" />
     <orderEntry type="library" name="JMock" level="project" />
+    <orderEntry type="library" name="TeamCityAPI-common" level="project" />
+    <orderEntry type="module" module-name="mercurial-common" />
     <orderEntryProperties />
   </component>
 </module>
--- a/mercurial.ipr	Mon Jul 21 21:22:25 2008 +0400
+++ b/mercurial.ipr	Wed Jul 23 09:18:03 2008 +0400
@@ -304,7 +304,9 @@
   <component name="ProjectModuleManager">
     <modules>
       <module fileurl="file://$PROJECT_DIR$/main.iml" filepath="$PROJECT_DIR$/main.iml" />
-      <module fileurl="file://$PROJECT_DIR$/mercurial/mercurial.iml" filepath="$PROJECT_DIR$/mercurial/mercurial.iml" />
+      <module fileurl="file://$PROJECT_DIR$/mercurial-agent/mercurial-agent.iml" filepath="$PROJECT_DIR$/mercurial-agent/mercurial-agent.iml" />
+      <module fileurl="file://$PROJECT_DIR$/mercurial-common/mercurial-common.iml" filepath="$PROJECT_DIR$/mercurial-common/mercurial-common.iml" />
+      <module fileurl="file://$PROJECT_DIR$/mercurial-server/mercurial-server.iml" filepath="$PROJECT_DIR$/mercurial-server/mercurial-server.iml" />
       <module fileurl="file://$PROJECT_DIR$/mercurial-tests/mercurial-tests.iml" filepath="$PROJECT_DIR$/mercurial-tests/mercurial-tests.iml" />
     </modules>
   </component>
@@ -435,22 +437,21 @@
     <option name="myLastEditedConfigurable" />
   </component>
   <component name="libraryTable">
-    <library name="TeamCity-openapi">
+    <library name="TeamCityAPI-server">
       <CLASSES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/server-api.jar!/" />
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/common-api.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/server-api.jar!/" />
       </CLASSES>
       <JAVADOC />
       <SOURCES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/src/openApi-source.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/src/openApi-source.jar!/" />
       </SOURCES>
     </library>
     <library name="IDEA-openapi">
       <CLASSES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/annotations.jar!/" />
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/openapi.jar!/" />
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/util.jar!/" />
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/resources_en.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/resources_en.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/util.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/openapi.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/annotations.jar!/" />
       </CLASSES>
       <JAVADOC />
       <SOURCES />
@@ -485,25 +486,34 @@
     </library>
     <library name="TeamCity-impl">
       <CLASSES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/patches-impl.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/patches-impl.jar!/" />
       </CLASSES>
       <JAVADOC />
       <SOURCES />
     </library>
     <library name="Log4j">
       <CLASSES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/log4j-1.2.12.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/log4j-1.2.12.jar!/" />
       </CLASSES>
       <JAVADOC />
       <SOURCES />
     </library>
     <library name="GNU Trove">
       <CLASSES>
-        <root url="jar://$PROJECT_DIR$/mercurial/lib/trove4j.jar!/" />
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/trove4j.jar!/" />
       </CLASSES>
       <JAVADOC />
       <SOURCES />
     </library>
+    <library name="TeamCityAPI-common">
+      <CLASSES>
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/common-api.jar!/" />
+      </CLASSES>
+      <JAVADOC />
+      <SOURCES>
+        <root url="jar://$PROJECT_DIR$/mercurial-server/lib/src/openApi-source.jar!/" />
+      </SOURCES>
+    </library>
   </component>
   <component name="testng.defaultConfiguration">
     <outputDirectory />
--- a/mercurial.xml	Mon Jul 21 21:22:25 2008 +0400
+++ b/mercurial.xml	Wed Jul 23 09:18:03 2008 +0400
@@ -45,21 +45,19 @@
   
   <!-- Project Libraries -->
   
-  <path id="library.teamcity-openapi.classpath">
-    <pathelement location="${basedir}/mercurial/lib/server-api.jar"/>
-    <pathelement location="${basedir}/mercurial/lib/common-api.jar"/>
+  <path id="library.teamcityapi-server.classpath">
+    <pathelement location="${basedir}/mercurial-server/lib/server-api.jar"/>
   </path>
   
   <path id="library.idea-openapi.classpath">
-    <pathelement location="${basedir}/mercurial/lib/annotations.jar"/>
-    <pathelement location="${basedir}/mercurial/lib/openapi.jar"/>
-    <pathelement location="${basedir}/mercurial/lib/util.jar"/>
-    <pathelement location="${basedir}/mercurial/lib/resources_en.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/resources_en.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/util.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/openapi.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/annotations.jar"/>
   </path>
   
   <path id="library.teamcity-testssupport.classpath">
     <pathelement location="${basedir}/mercurial-tests/lib/patches-tests.jar"/>
-    <pathelement location="${basedir}/mercurial-tests/lib/test.jar"/>
   </path>
   
   <path id="library.junit.classpath">
@@ -75,15 +73,19 @@
   </path>
   
   <path id="library.teamcity-impl.classpath">
-    <pathelement location="${basedir}/mercurial/lib/patches-impl.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/patches-impl.jar"/>
   </path>
   
   <path id="library.log4j.classpath">
-    <pathelement location="${basedir}/mercurial/lib/log4j-1.2.12.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/log4j-1.2.12.jar"/>
   </path>
   
   <path id="library.gnu_trove.classpath">
-    <pathelement location="${basedir}/mercurial/lib/trove4j.jar"/>
+    <pathelement location="${basedir}/mercurial-server/lib/trove4j.jar"/>
+  </path>
+  
+  <path id="library.teamcityapi-common.classpath">
+    <pathelement location="${basedir}/mercurial-server/lib/common-api.jar"/>
   </path>
   
   
@@ -133,84 +135,223 @@
   </target>
   
   
-  <!-- Module mercurial -->
+  <!-- Module mercurial-agent -->
   
-  <dirname property="module.mercurial.basedir" file="${ant.file}"/>
+  <dirname property="module.mercurial-agent.basedir" file="${ant.file}"/>
   
   
   
-  <property name="compiler.args.mercurial" value="${compiler.args}"/>
+  <property name="compiler.args.mercurial-agent" value="${compiler.args}"/>
   
-  <property name="mercurial.output.dir" value="${module.mercurial.basedir}/mercurial/classes"/>
-  <property name="mercurial.testoutput.dir" value="${module.mercurial.basedir}/mercurial/classes"/>
+  <property name="mercurial-agent.output.dir" value="${module.mercurial-agent.basedir}/mercurial-agent/classes"/>
+  <property name="mercurial-agent.testoutput.dir" value="${module.mercurial-agent.basedir}/mercurial-agent/classes"/>
   
-  <path id="mercurial.module.bootclasspath">
+  <path id="mercurial-agent.module.bootclasspath">
     <!-- Paths to be included in compilation bootclasspath -->
   </path>
   
-  <path id="mercurial.module.classpath">
-    <path refid="library.teamcity-openapi.classpath"/>
+  <path id="mercurial-agent.module.classpath"/>
+  
+  <path id="mercurial-agent.runtime.module.classpath">
+    <pathelement location="${mercurial-agent.output.dir}"/>
+  </path>
+  
+  
+  <patternset id="excluded.from.module.mercurial-agent">
+    <patternset refid="ignored.files"/>
+  </patternset>
+  
+  <patternset id="excluded.from.compilation.mercurial-agent">
+    <patternset refid="excluded.from.module.mercurial-agent"/>
+  </patternset>
+  
+  <path id="mercurial-agent.module.sourcepath">
+    <dirset dir="${module.mercurial-agent.basedir}/mercurial-agent">
+      <include name="src"/>
+    </dirset>
+  </path>
+  
+  
+  <target name="compile.module.mercurial-agent" depends="compile.module.mercurial-agent.production,compile.module.mercurial-agent.tests" description="Compile module mercurial-agent"/>
+  
+  <target name="compile.module.mercurial-agent.production" description="Compile module mercurial-agent; production classes">
+    <mkdir dir="${mercurial-agent.output.dir}"/>
+    <javac destdir="${mercurial-agent.output.dir}" debug="${compiler.debug}" nowarn="${compiler.generate.no.warnings}" memorymaximumsize="${compiler.max.memory}" fork="true">
+      <compilerarg line="${compiler.args.mercurial-agent}"/>
+      <bootclasspath refid="mercurial-agent.module.bootclasspath"/>
+      <classpath refid="mercurial-agent.module.classpath"/>
+      <src refid="mercurial-agent.module.sourcepath"/>
+      <patternset refid="excluded.from.compilation.mercurial-agent"/>
+    </javac>
+    
+    <copy todir="${mercurial-agent.output.dir}">
+      <fileset dir="${module.mercurial-agent.basedir}/mercurial-agent/src">
+        <patternset refid="compiler.resources"/>
+        <type type="file"/>
+      </fileset>
+    </copy>
+  </target>
+  
+  <target name="compile.module.mercurial-agent.tests" depends="compile.module.mercurial-agent.production" description="compile module mercurial-agent; test classes" unless="skip.tests"/>
+  
+  <target name="clean.module.mercurial-agent" description="cleanup module">
+    <delete dir="${mercurial-agent.output.dir}"/>
+    <delete dir="${mercurial-agent.testoutput.dir}"/>
+  </target>
+  
+  
+  <!-- Module mercurial-common -->
+  
+  <dirname property="module.mercurial-common.basedir" file="${ant.file}"/>
+  
+  
+  
+  <property name="compiler.args.mercurial-common" value="${compiler.args}"/>
+  
+  <property name="mercurial-common.output.dir" value="${module.mercurial-common.basedir}/mercurial-common/classes"/>
+  <property name="mercurial-common.testoutput.dir" value="${module.mercurial-common.basedir}/mercurial-common/classes"/>
+  
+  <path id="mercurial-common.module.bootclasspath">
+    <!-- Paths to be included in compilation bootclasspath -->
+  </path>
+  
+  <path id="mercurial-common.module.classpath">
+    <path refid="library.teamcityapi-common.classpath"/>
+    <path refid="library.idea-openapi.classpath"/>
+  </path>
+  
+  <path id="mercurial-common.runtime.module.classpath">
+    <pathelement location="${mercurial-common.output.dir}"/>
+    <path refid="library.teamcityapi-common.classpath"/>
+    <path refid="library.idea-openapi.classpath"/>
+  </path>
+  
+  
+  <patternset id="excluded.from.module.mercurial-common">
+    <patternset refid="ignored.files"/>
+  </patternset>
+  
+  <patternset id="excluded.from.compilation.mercurial-common">
+    <patternset refid="excluded.from.module.mercurial-common"/>
+  </patternset>
+  
+  <path id="mercurial-common.module.sourcepath">
+    <dirset dir="${module.mercurial-common.basedir}/mercurial-common">
+      <include name="src"/>
+    </dirset>
+  </path>
+  
+  
+  <target name="compile.module.mercurial-common" depends="compile.module.mercurial-common.production,compile.module.mercurial-common.tests" description="Compile module mercurial-common"/>
+  
+  <target name="compile.module.mercurial-common.production" description="Compile module mercurial-common; production classes">
+    <mkdir dir="${mercurial-common.output.dir}"/>
+    <javac destdir="${mercurial-common.output.dir}" debug="${compiler.debug}" nowarn="${compiler.generate.no.warnings}" memorymaximumsize="${compiler.max.memory}" fork="true">
+      <compilerarg line="${compiler.args.mercurial-common}"/>
+      <bootclasspath refid="mercurial-common.module.bootclasspath"/>
+      <classpath refid="mercurial-common.module.classpath"/>
+      <src refid="mercurial-common.module.sourcepath"/>
+      <patternset refid="excluded.from.compilation.mercurial-common"/>
+    </javac>
+    
+    <copy todir="${mercurial-common.output.dir}">
+      <fileset dir="${module.mercurial-common.basedir}/mercurial-common/src">
+        <patternset refid="compiler.resources"/>
+        <type type="file"/>
+      </fileset>
+    </copy>
+  </target>
+  
+  <target name="compile.module.mercurial-common.tests" depends="compile.module.mercurial-common.production" description="compile module mercurial-common; test classes" unless="skip.tests"/>
+  
+  <target name="clean.module.mercurial-common" description="cleanup module">
+    <delete dir="${mercurial-common.output.dir}"/>
+    <delete dir="${mercurial-common.testoutput.dir}"/>
+  </target>
+  
+  
+  <!-- Module mercurial-server -->
+  
+  <dirname property="module.mercurial-server.basedir" file="${ant.file}"/>
+  
+  
+  
+  <property name="compiler.args.mercurial-server" value="${compiler.args}"/>
+  
+  <property name="mercurial-server.output.dir" value="${module.mercurial-server.basedir}/mercurial-server/classes"/>
+  <property name="mercurial-server.testoutput.dir" value="${module.mercurial-server.basedir}/mercurial-server/classes"/>
+  
+  <path id="mercurial-server.module.bootclasspath">
+    <!-- Paths to be included in compilation bootclasspath -->
+  </path>
+  
+  <path id="mercurial-server.module.classpath">
+    <path refid="library.teamcityapi-server.classpath"/>
     <path refid="library.idea-openapi.classpath"/>
     <path refid="library.teamcity-impl.classpath"/>
     <path refid="library.log4j.classpath"/>
     <path refid="library.gnu_trove.classpath"/>
+    <pathelement location="${mercurial-common.output.dir}"/>
+    <path refid="library.teamcityapi-common.classpath"/>
   </path>
   
-  <path id="mercurial.runtime.module.classpath">
-    <pathelement location="${mercurial.output.dir}"/>
-    <path refid="library.teamcity-openapi.classpath"/>
+  <path id="mercurial-server.runtime.module.classpath">
+    <pathelement location="${mercurial-server.output.dir}"/>
+    <path refid="library.teamcityapi-server.classpath"/>
     <path refid="library.idea-openapi.classpath"/>
     <path refid="library.teamcity-impl.classpath"/>
     <path refid="library.log4j.classpath"/>
     <path refid="library.gnu_trove.classpath"/>
+    <pathelement location="${mercurial-common.output.dir}"/>
+    <path refid="library.teamcityapi-common.classpath"/>
   </path>
   
   
-  <patternset id="excluded.from.module.mercurial">
+  <patternset id="excluded.from.module.mercurial-server">
     <patternset refid="ignored.files"/>
   </patternset>
   
-  <patternset id="excluded.from.compilation.mercurial">
-    <patternset refid="excluded.from.module.mercurial"/>
+  <patternset id="excluded.from.compilation.mercurial-server">
+    <patternset refid="excluded.from.module.mercurial-server"/>
   </patternset>
   
-  <path id="mercurial.module.sourcepath">
-    <dirset dir="${module.mercurial.basedir}/mercurial">
+  <path id="mercurial-server.module.sourcepath">
+    <dirset dir="${module.mercurial-server.basedir}/mercurial-server">
       <include name="resources"/>
       <include name="src"/>
     </dirset>
   </path>
   
   
-  <target name="compile.module.mercurial" depends="compile.module.mercurial.production,compile.module.mercurial.tests" description="Compile module mercurial"/>
+  <target name="compile.module.mercurial-server" depends="compile.module.mercurial-server.production,compile.module.mercurial-server.tests" description="Compile module mercurial-server"/>
   
-  <target name="compile.module.mercurial.production" description="Compile module mercurial; production classes">
-    <mkdir dir="${mercurial.output.dir}"/>
-    <javac destdir="${mercurial.output.dir}" debug="${compiler.debug}" nowarn="${compiler.generate.no.warnings}" memorymaximumsize="${compiler.max.memory}" fork="true">
-      <compilerarg line="${compiler.args.mercurial}"/>
-      <bootclasspath refid="mercurial.module.bootclasspath"/>
-      <classpath refid="mercurial.module.classpath"/>
-      <src refid="mercurial.module.sourcepath"/>
-      <patternset refid="excluded.from.compilation.mercurial"/>
+  <target name="compile.module.mercurial-server.production" depends="compile.module.mercurial-common" description="Compile module mercurial-server; production classes">
+    <mkdir dir="${mercurial-server.output.dir}"/>
+    <javac destdir="${mercurial-server.output.dir}" debug="${compiler.debug}" nowarn="${compiler.generate.no.warnings}" memorymaximumsize="${compiler.max.memory}" fork="true">
+      <compilerarg line="${compiler.args.mercurial-server}"/>
+      <bootclasspath refid="mercurial-server.module.bootclasspath"/>
+      <classpath refid="mercurial-server.module.classpath"/>
+      <src refid="mercurial-server.module.sourcepath"/>
+      <patternset refid="excluded.from.compilation.mercurial-server"/>
     </javac>
     
-    <copy todir="${mercurial.output.dir}">
-      <fileset dir="${module.mercurial.basedir}/mercurial/resources">
+    <copy todir="${mercurial-server.output.dir}">
+      <fileset dir="${module.mercurial-server.basedir}/mercurial-server/resources">
         <patternset refid="compiler.resources"/>
         <type type="file"/>
       </fileset>
-      <fileset dir="${module.mercurial.basedir}/mercurial/src">
+      <fileset dir="${module.mercurial-server.basedir}/mercurial-server/src">
         <patternset refid="compiler.resources"/>
         <type type="file"/>
       </fileset>
     </copy>
   </target>
   
-  <target name="compile.module.mercurial.tests" depends="compile.module.mercurial.production" description="compile module mercurial; test classes" unless="skip.tests"/>
+  <target name="compile.module.mercurial-server.tests" depends="compile.module.mercurial-server.production" description="compile module mercurial-server; test classes" unless="skip.tests"/>
   
-  <target name="clean.module.mercurial" description="cleanup module">
-    <delete dir="${mercurial.output.dir}"/>
-    <delete dir="${mercurial.testoutput.dir}"/>
+  <target name="clean.module.mercurial-server" description="cleanup module">
+    <delete dir="${mercurial-server.output.dir}"/>
+    <delete dir="${mercurial-server.testoutput.dir}"/>
   </target>
   
   
@@ -230,26 +371,30 @@
   </path>
   
   <path id="mercurial-tests.module.classpath">
-    <pathelement location="${mercurial.output.dir}"/>
-    <path refid="library.teamcity-openapi.classpath"/>
+    <pathelement location="${mercurial-server.output.dir}"/>
+    <path refid="library.teamcityapi-server.classpath"/>
     <path refid="library.idea-openapi.classpath"/>
     <path refid="library.teamcity-impl.classpath"/>
     <path refid="library.log4j.classpath"/>
     <path refid="library.gnu_trove.classpath"/>
+    <path refid="library.teamcityapi-common.classpath"/>
     <path refid="library.teamcity-testssupport.classpath"/>
     <path refid="library.junit.classpath"/>
     <path refid="library.testng.classpath"/>
     <path refid="library.jmock.classpath"/>
+    <pathelement location="${mercurial-common.output.dir}"/>
   </path>
   
   <path id="mercurial-tests.runtime.module.classpath">
     <pathelement location="${mercurial-tests.output.dir}"/>
-    <pathelement location="${mercurial.output.dir}"/>
-    <path refid="library.teamcity-openapi.classpath"/>
+    <pathelement location="${mercurial-server.output.dir}"/>
+    <path refid="library.teamcityapi-server.classpath"/>
     <path refid="library.idea-openapi.classpath"/>
     <path refid="library.teamcity-impl.classpath"/>
     <path refid="library.log4j.classpath"/>
     <path refid="library.gnu_trove.classpath"/>
+    <pathelement location="${mercurial-common.output.dir}"/>
+    <path refid="library.teamcityapi-common.classpath"/>
     <path refid="library.teamcity-testssupport.classpath"/>
     <path refid="library.junit.classpath"/>
     <path refid="library.testng.classpath"/>
@@ -274,7 +419,7 @@
   
   <target name="compile.module.mercurial-tests" depends="compile.module.mercurial-tests.production,compile.module.mercurial-tests.tests" description="Compile module mercurial-tests"/>
   
-  <target name="compile.module.mercurial-tests.production" depends="compile.module.mercurial" description="Compile module mercurial-tests; production classes">
+  <target name="compile.module.mercurial-tests.production" depends="compile.module.mercurial-server,compile.module.mercurial-common" description="Compile module mercurial-tests; production classes">
     <mkdir dir="${mercurial-tests.output.dir}"/>
     <javac destdir="${mercurial-tests.output.dir}" debug="${compiler.debug}" nowarn="${compiler.generate.no.warnings}" memorymaximumsize="${compiler.max.memory}" fork="true">
       <compilerarg line="${compiler.args.mercurial-tests}"/>
@@ -303,7 +448,7 @@
     <!-- Perform any build initialization in this target -->
   </target>
   
-  <target name="clean" depends="clean.module.main, clean.module.mercurial, clean.module.mercurial-tests" description="cleanup all"/>
+  <target name="clean" depends="clean.module.main, clean.module.mercurial-agent, clean.module.mercurial-common, clean.module.mercurial-server, clean.module.mercurial-tests" description="cleanup all"/>
   
-  <target name="all" depends="init, clean, compile.module.main, compile.module.mercurial, compile.module.mercurial-tests" description="build all"/>
+  <target name="all" depends="init, clean, compile.module.main, compile.module.mercurial-agent, compile.module.mercurial-common, compile.module.mercurial-server, compile.module.mercurial-tests" description="build all"/>
 </project>
\ No newline at end of file
Binary file mercurial/lib/annotations.jar has changed
Binary file mercurial/lib/common-api.jar has changed
Binary file mercurial/lib/log4j-1.2.12.jar has changed
Binary file mercurial/lib/openapi.jar has changed
Binary file mercurial/lib/patches-impl.jar has changed
Binary file mercurial/lib/resources_en.jar has changed
Binary file mercurial/lib/server-api.jar has changed
Binary file mercurial/lib/src/openApi-source.jar has changed
Binary file mercurial/lib/trove4j.jar has changed
Binary file mercurial/lib/util.jar has changed
--- a/mercurial/mercurial.iml	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module relativePaths="true" type="JAVA_MODULE" version="4">
-  <component name="FacetManager">
-    <facet type="Spring" name="Spring">
-      <configuration>
-        <options>
-          <option name="enableValidation" value="false" />
-          <option name="reportErrorsAsWarnings" value="true" />
-        </options>
-        <customNs />
-      </configuration>
-    </facet>
-  </component>
-  <component name="NewModuleRootManager" inherit-compiler-output="false">
-    <output url="file://$MODULE_DIR$/classes" />
-    <exclude-output />
-    <content url="file://$MODULE_DIR$">
-      <sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
-      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
-    </content>
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" exported="" name="TeamCity-openapi" level="project" />
-    <orderEntry type="library" exported="" name="IDEA-openapi" level="project" />
-    <orderEntry type="library" exported="" name="TeamCity-impl" level="project" />
-    <orderEntry type="library" exported="" name="Log4j" level="project" />
-    <orderEntry type="library" exported="" name="GNU Trove" level="project" />
-    <orderEntryProperties />
-  </component>
-</module>
-
--- a/mercurial/resources/buildServerResources/mercurialSettings.jsp	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-<%@include file="/include.jsp"%>
-<%@ taglib prefix="props" tagdir="/WEB-INF/tags/props" %>
-<jsp:useBean id="propertiesBean" scope="request" type="jetbrains.buildServer.controllers.BasePropertiesBean"/>
-<table class="runnerFormTable">
-
-  <l:settingsGroup title="Mercurial Settings">
-  <tr>
-    <th><label for="hgCommandPath">HG command path: <l:star/></label></th>
-    <td><props:textProperty name="hgCommandPath" className="longField" />
-      <span class="error" id="error_hgCommandPath"></span></td>
-  </tr>
-  <tr>
-    <th><label for="repositoryPath">Pull changes from: <l:star/></label></th>
-    <td><props:textProperty name="repositoryPath" className="longField" />
-      <span class="error" id="error_repositoryPath"></span></td>
-  </tr>
-  </l:settingsGroup>
-  
-</table>
--- a/mercurial/src/META-INF/build-server-plugin-mercurial.xml	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
-
-<beans default-autowire="constructor">
-  <bean id="svn" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport" />
-</beans>
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-/*
- * Copyright 2000-2007 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;
-
-public interface Constants {
-  String REPOSITORY_PROP = "repositoryPath";
-  String HG_COMMAND_PATH_PROP = "hgCommandPath";
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,444 +0,0 @@
-/*
- * Copyright 2000-2007 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.CollectChangesByIncludeRule;
-import jetbrains.buildServer.Used;
-import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor;
-import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*;
-import jetbrains.buildServer.log.Loggers;
-import jetbrains.buildServer.serverSide.InvalidProperty;
-import jetbrains.buildServer.serverSide.PropertiesProcessor;
-import jetbrains.buildServer.serverSide.SBuildServer;
-import jetbrains.buildServer.serverSide.ServerPaths;
-import jetbrains.buildServer.util.FileUtil;
-import jetbrains.buildServer.vcs.*;
-import jetbrains.buildServer.vcs.patches.PatchBuilder;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Mercurial VCS plugin for TeamCity works as follows:
- * <ul>
- * <li>clones repository to internal storage
- * <li>before any operation with working copy of repository pulls changes from the original repository
- * <li>executes corresponding hg command
- * </ul>
- *
- * <p>Working copy of repository is created in the $TEAMCITY_DATA_PATH/system/caches/mercurial folder.
- * <p>Personal builds (remote runs) are not yet supported, they require corresponding functionality from the IDE.
- * <p>Checkout on agent mode is not yet supported too.
- */
-public class MercurialVcsSupport extends VcsSupport implements CollectChangesByIncludeRule {
-  private ServerPaths myServerPaths;
-  private ConcurrentMap<String, Lock> myWorkDirLocks= new ConcurrentHashMap<String, Lock>();
-  private static final int OLD_WORK_DIRS_CLEANUP_PERIOD = 600;
-  private VcsManager myVcsManager;
-
-  public MercurialVcsSupport(@NotNull final VcsManager vcsManager,
-                             @NotNull ServerPaths paths,
-                             @NotNull SBuildServer server) {
-    vcsManager.registerVcsSupport(this);
-    myServerPaths = paths;
-    myVcsManager = vcsManager;
-    server.getExecutor().scheduleAtFixedRate(new Runnable() {
-      public void run() {
-        removeOldWorkFolders();
-      }
-    }, 0, OLD_WORK_DIRS_CLEANUP_PERIOD, TimeUnit.SECONDS);
-  }
-
-  public List<ModificationData> collectBuildChanges(final VcsRoot root,
-                                                    @NotNull final String fromVersion,
-                                                    @NotNull final String currentVersion,
-                                                    final CheckoutRules checkoutRules) throws VcsException {
-    updateWorkingDirectory(root);
-    return VcsSupportUtil.collectBuildChanges(root, fromVersion, currentVersion, checkoutRules, this);
-  }
-
-  public List<ModificationData> collectBuildChanges(final VcsRoot root,
-                                                    final String fromVersion,
-                                                    final String currentVersion,
-                                                    final IncludeRule includeRule) throws VcsException {
-    // first obtain changes between specified versions
-    List<ModificationData> result = new ArrayList<ModificationData>();
-    Settings settings = new Settings(myServerPaths, root);
-    LogCommand lc = new LogCommand(settings);
-    lc.setFromRevId(new ChangeSet(fromVersion).getId());
-    lc.setToRevId(new ChangeSet(currentVersion).getId());
-    List<ChangeSet> changeSets = lc.execute();
-    if (changeSets.isEmpty()) {
-      return result;
-    }
-
-    // invoke status command for each changeset and determine what files were modified in these changesets
-    Iterator<ChangeSet> it = changeSets.iterator();
-    ChangeSet prev = it.next(); // skip first changeset (cause it was already reported)
-    StatusCommand st = new StatusCommand(settings);
-    while (it.hasNext()) {
-      ChangeSet cur = it.next();
-      st.setFromRevId(prev.getId());
-      st.setToRevId(cur.getId());
-      List<ModifiedFile> modifiedFiles = st.execute();
-      // changeset full version will be set into VcsChange structure and
-      // stored in database (note that getContent method will be invoked with this version)
-      List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), includeRule);
-      if (files.isEmpty()) continue;
-      ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getSummary(), cur.getUser(), root, cur.getFullVersion(), cur.getFullVersion());
-      result.add(md);
-      prev = cur;
-    }
-
-    return result;
-  }
-
-  private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, final IncludeRule includeRule) {
-    List<VcsChange> files = new ArrayList<VcsChange>();
-    for (ModifiedFile mf: modifiedFiles) {
-      String normalizedPath = PathUtil.normalizeSeparator(mf.getPath());
-      if (!normalizedPath.startsWith(includeRule.getFrom())) continue; // skip files which do not match include rule
-
-      VcsChangeInfo.Type changeType = getChangeType(mf.getStatus());
-      if (changeType == null) {
-        Loggers.VCS.warn("Unable to convert status: " + mf.getStatus() + " to VCS change type");
-        changeType = VcsChangeInfo.Type.NOT_CHANGED;
-      }
-      files.add(new VcsChange(changeType, mf.getStatus().getName(), normalizedPath, normalizedPath, prevVer, curVer));
-    }
-    return files;
-  }
-
-  private VcsChangeInfo.Type getChangeType(final ModifiedFile.Status status) {
-    switch (status) {
-      case ADDED:return VcsChangeInfo.Type.ADDED;
-      case MODIFIED:return VcsChangeInfo.Type.CHANGED;
-      case REMOVED:return VcsChangeInfo.Type.REMOVED;
-    }
-    return null;
-  }
-
-  @NotNull
-  public byte[] getContent(final VcsModification vcsModification,
-                           final VcsChangeInfo change,
-                           final VcsChangeInfo.ContentType contentType,
-                           final VcsRoot vcsRoot) throws VcsException {
-    updateWorkingDirectory(vcsRoot);
-    String version = contentType == VcsChangeInfo.ContentType.AFTER_CHANGE ? change.getAfterChangeRevisionNumber() : change.getBeforeChangeRevisionNumber();
-    return getContent(change.getRelativeFileName(), vcsRoot, version);
-  }
-
-  @NotNull
-  public byte[] getContent(final String filePath, final VcsRoot vcsRoot, final String version) throws VcsException {
-    updateWorkingDirectory(vcsRoot);
-    Settings settings = new Settings(myServerPaths, vcsRoot);
-    CatCommand cc = new CatCommand(settings);
-    ChangeSet cs = new ChangeSet(version);
-    cc.setRevId(cs.getId());
-    File parentDir = cc.execute(Collections.singletonList(filePath));
-    File file = new File(parentDir, filePath);
-    if (file.isFile()) {
-      try {
-        return FileUtil.loadFileBytes(file);
-      } catch (IOException e) {
-        throw new VcsException("Failed to load content of file: " + file.getAbsolutePath(), e);
-      }
-    } else {
-      Loggers.VCS.warn("Unable to obtain content of the file: " + filePath);
-    }
-    return new byte[0];
-  }
-
-  public String getName() {
-    return "mercurial";
-  }
-
-  @Used("jsp")
-  public String getDisplayName() {
-    return "Mercurial";
-  }
-
-  @Nullable
-  public PropertiesProcessor getVcsPropertiesProcessor() {
-    return new AbstractVcsPropertiesProcessor() {
-      public Collection<InvalidProperty> process(final Map<String, String> properties) {
-        List<InvalidProperty> result = new ArrayList<InvalidProperty>();
-        if (isEmpty(properties.get(Constants.HG_COMMAND_PATH_PROP))) {
-          result.add(new InvalidProperty(Constants.HG_COMMAND_PATH_PROP, "Path to 'hg' command must be specified"));
-        } 
-        if (isEmpty(properties.get(Constants.REPOSITORY_PROP))) {
-          result.add(new InvalidProperty(Constants.REPOSITORY_PROP, "Repository must be specified"));
-        }
-        return result;
-      }
-    };
-  }
-
-  public String getVcsSettingsJspFilePath() {
-    return "mercurialSettings.jsp";
-  }
-
-  @NotNull
-  public String getCurrentVersion(final VcsRoot root) throws VcsException {
-    // we will return full version of the most recent change as current version
-    updateWorkingDirectory(root);
-    Settings settings = new Settings(myServerPaths, root);
-    TipCommand lc = new TipCommand(settings);
-    ChangeSet changeSet = lc.execute();
-    return changeSet.getFullVersion();
-  }
-
-  public String describeVcsRoot(final VcsRoot vcsRoot) {
-    return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP);
-  }
-
-  public boolean isTestConnectionSupported() {
-    return true;
-  }
-
-  @Nullable
-  public String testConnection(final VcsRoot vcsRoot) throws VcsException {
-    Settings settings = new Settings(myServerPaths, vcsRoot);
-    IdentifyCommand id = new IdentifyCommand(settings);
-    StringBuilder res = new StringBuilder();
-    res.append(quoteIfNeeded(settings.getHgCommandPath()));
-    res.append(" identify ");
-    res.append(quoteIfNeeded(settings.getRepository()));
-    res.append('\n').append(id.execute());
-    return res.toString();
-  }
-
-  private String quoteIfNeeded(@NotNull String str) {
-    if (str.indexOf(' ') != -1) {
-      return "\"" + str + "\"";
-    }
-
-    return str;
-  }
-
-  @Nullable
-  public Map<String, String> getDefaultVcsProperties() {
-    return Collections.singletonMap(Constants.HG_COMMAND_PATH_PROP, "hg");
-  }
-
-  public String getVersionDisplayName(final String version, final VcsRoot root) throws VcsException {
-    return version;
-  }
-
-  @NotNull
-  public Comparator<String> getVersionComparator() {
-    // comparator is called when TeamCity needs to sort modifications in the order of their appearance,
-    // currently we sort changes by revision number, not sure however that this is a good idea,
-    // probably it would be better to sort them by timestamp (and to add timestamp into the version).
-    return new Comparator<String>() {
-      public int compare(final String o1, final String o2) {
-        try {
-          return new ChangeSet(o1).getRevNumber() - new ChangeSet(o2).getRevNumber();
-        } catch (Exception e) {
-          return 1;
-        }
-      }
-    };
-  }
-
-  public void buildPatch(final VcsRoot root,
-                         @Nullable final String fromVersion,
-                         @NotNull final String toVersion,
-                         final PatchBuilder builder,
-                         final CheckoutRules checkoutRules) throws IOException, VcsException {
-    updateWorkingDirectory(root);
-    Settings settings = new Settings(myServerPaths, root);
-    if (fromVersion == null) {
-      buildFullPatch(settings, new ChangeSet(toVersion), builder);
-    } else {
-      buildIncrementalPatch(settings, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder);
-    }
-  }
-
-  // builds patch from version to version
-  private void buildIncrementalPatch(final Settings settings, @NotNull final ChangeSet fromVer, @NotNull final ChangeSet toVer, final PatchBuilder builder)
-    throws VcsException, IOException {
-    StatusCommand st = new StatusCommand(settings);
-    st.setFromRevId(fromVer.getId());
-    st.setToRevId(toVer.getId());
-    List<ModifiedFile> modifiedFiles = st.execute();
-    List<String> notDeletedFiles = new ArrayList<String>();
-    for (ModifiedFile f: modifiedFiles) {
-      if (f.getStatus() != ModifiedFile.Status.REMOVED) {
-        notDeletedFiles.add(f.getPath());
-      }
-    }
-
-    CatCommand cc = new CatCommand(settings);
-    cc.setRevId(toVer.getId());
-    File parentDir = cc.execute(notDeletedFiles);
-
-    try {
-      for (ModifiedFile f: modifiedFiles) {
-        final File virtualFile = new File(f.getPath());
-        if (f.getStatus() == ModifiedFile.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();
-          }
-        }
-      }
-    } finally {
-      FileUtil.delete(parentDir);
-    }
-  }
-
-  // builds patch by exporting files using specified version
-  private void buildFullPatch(final Settings settings, @NotNull final ChangeSet toVer, final PatchBuilder builder)
-    throws IOException, VcsException {
-    CloneCommand cl = new CloneCommand(settings);
-    cl.setToId(toVer.getId());
-    File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId());
-    try {
-      final File repRoot = new File(tempDir, "rep");
-      cl.setDestDir(repRoot.getAbsolutePath());
-      cl.execute();
-      buildPatchFromDirectory(builder, repRoot, new FileFilter() {
-        public boolean accept(final File file) {
-          return !(file.isDirectory() && ".hg".equals(file.getName()));
-        }
-      });
-    } finally {
-      FileUtil.delete(tempDir);
-    }
-  }
-
-  private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException {
-    buildPatchFromDirectory(repRoot, builder, repRoot, filter);
-  }
-
-  private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final FileFilter filter) throws IOException {
-    File[] files = curDir.listFiles(filter);
-    if (files != null) {
-      for (File realFile: files) {
-        String relPath = realFile.getAbsolutePath().substring(repRoot.getAbsolutePath().length());
-        final File virtualFile = new File(relPath);
-        if (realFile.isDirectory()) {
-          builder.createDirectory(virtualFile);
-          buildPatchFromDirectory(realFile, builder, repRoot, filter);
-        } else {
-          final FileInputStream is = new FileInputStream(realFile);
-          try {
-            builder.createBinaryFile(virtualFile, null, is, realFile.length());
-          } finally {
-            is.close();
-          }
-        }
-      }
-    }
-  }
-
-  // updates current working copy of repository by pulling changes from the repository specified in VCS root
-  private void updateWorkingDirectory(final VcsRoot root) throws VcsException {
-    Settings settings = new Settings(myServerPaths, root);
-    File workDir = settings.getWorkingDir();
-    lockWorkDir(workDir);
-    try {
-      if (hasRepositoryCopy(workDir)) {
-        // update
-        PullCommand pull = new PullCommand(settings);
-        pull.execute();
-      } else {
-        // clone
-        CloneCommand cl = new CloneCommand(settings);
-        cl.setDestDir(workDir.getAbsolutePath());
-        cl.setUpdateWorkingDir(false);
-        cl.execute();
-      }
-    } finally {
-      unlockWorkDir(workDir);
-    }
-  }
-
-  private void lockWorkDir(@NotNull File workDir) {
-    getWorkDirLock(workDir).lock();
-  }
-
-  private void unlockWorkDir(@NotNull File workDir) {
-    getWorkDirLock(workDir).unlock();
-  }
-
-  private Lock getWorkDirLock(final File workDir) {
-    String path = workDir.getAbsolutePath();
-    Lock lock = myWorkDirLocks.get(path);
-    if (lock == null) {
-      lock = new ReentrantLock();
-      Lock curLock = myWorkDirLocks.putIfAbsent(path, lock);
-      if (curLock != null) {
-        lock = curLock;
-      }
-    }
-    return lock;
-  }
-
-  private boolean hasRepositoryCopy(final File workDir) {
-    // need better way to check that repository copy is ok
-    return workDir.isDirectory() && new File(workDir, ".hg").isDirectory();
-  }
-
-  private void removeOldWorkFolders() {
-    File workFoldersParent = new File(myServerPaths.getCachesDir(), "mercurial");
-    if (!workFoldersParent.isDirectory()) return;
-
-    Set<File> workDirs = new HashSet<File>();
-    File[] files = workFoldersParent.listFiles(new FileFilter() {
-      public boolean accept(final File file) {
-        return file.isDirectory() && file.getName().startsWith(Settings.DEFAULT_WORK_DIR_PREFIX);
-      }
-    });
-    if (files != null) {
-      for (File f: files) {
-        workDirs.add(FileUtil.getCanonicalFile(f));
-      }
-    }
-
-    for (VcsRoot vcsRoot: myVcsManager.getAllRegisteredVcsRoots()) {
-      if (getName().equals(vcsRoot.getVcsName())) {
-        Settings s = new Settings(myServerPaths, vcsRoot);
-        workDirs.remove(FileUtil.getCanonicalFile(s.getWorkingDir()));
-      }
-    }
-
-    for (File f: workDirs) {
-      lockWorkDir(f);
-      try {
-        FileUtil.delete(f);
-      } finally {
-        unlockWorkDir(f);
-      }
-    }
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright 2000-2007 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 org.jetbrains.annotations.NotNull;
-
-public class PathUtil {
-  @NotNull
-  public static String normalizeSeparator(@NotNull String repPath) {
-    return repPath.replace('\\', '/');
-  }
-  }
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.util.FileUtil;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-public class CatCommand {
-  private Settings mySettings;
-  private String myRevId;
-
-  public CatCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public void setRevId(final String revId) {
-    myRevId = revId;
-  }
-
-  public File execute(List<String> relPaths) throws VcsException {
-    File tempDir;
-    try {
-      tempDir = FileUtil.createTempDirectory("mercurial", "catresult");
-    } catch (IOException e) {
-      throw new VcsException("Unable to create temporary directory");
-    }
-    for (String path: relPaths) {
-      final File parentFile = new File(tempDir, path).getParentFile();
-      if (!parentFile.isDirectory() && !parentFile.mkdirs()) {
-        throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath());
-      }
-    }
-
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.addParameter("cat");
-    cli.addParameter("-o");
-    cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p");
-    if (myRevId != null) {
-      cli.addParameter("-r");
-      cli.addParameter(myRevId);
-    }
-    for (String p: relPaths) {
-      cli.addParameter(FileUtil.normalizeSeparator(p));
-    }
-    CommandUtil.runCommand(cli);
-    return tempDir;
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/*
- * Copyright 2000-2007 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;
-
-import java.util.Date;
-
-/**
- * Represents Mercurial change set
- */
-public class ChangeSet {
-  private int myRevNumber;
-  @NotNull private String myId;
-  @NotNull private String myUser;
-  @NotNull private Date myTimestamp;
-  private String mySummary;
-
-  public ChangeSet(final int revNumber, @NotNull final String id) {
-    myRevNumber = revNumber;
-    myId = id;
-  }
-
-  /**
-   * Constructor for version in the form revnum:changeset_id
-   * @param fullVersion full changeset version as reported by hg log command
-   */
-  public ChangeSet(@NotNull final String fullVersion) {
-    try {
-      String[] parts = fullVersion.split(":");
-      myRevNumber = Integer.parseInt(parts[0]);
-      myId = parts[1];
-    } catch (Throwable e) {
-      throw new IllegalArgumentException(e);
-    }
-  }
-
-  public void setUser(@NotNull final String user) {
-    myUser = user;
-  }
-
-  public void setTimestamp(@NotNull final Date timestamp) {
-    myTimestamp = timestamp;
-  }
-
-  public void setSummary(final String summary) {
-    mySummary = summary;
-  }
-
-  /**
-   * Returns changeset revision id
-   * @return changeset revision id
-   */
-  @NotNull
-  public String getId() {
-    return myId;
-  }
-
-  /**
-   * Returns changeset revision number
-   * @return changeset revision number
-   */
-  public int getRevNumber() {
-    return myRevNumber;
-  }
-
-  /**
-   * Returns full changeset version as reported by hg log command: revnum:revid
-   * @return full changeset version as reported by hg log
-   */
-  @NotNull
-  public String getFullVersion() {
-    return myRevNumber + ":" + myId;
-  }
-
-  /**
-   * Returns user who made changeset
-   * @return user who made changeset
-   */
-  @NotNull
-  public String getUser() {
-    return myUser;
-  }
-
-  /**
-   * Returns changeset timestamp
-   * @return changeset timestamp
-   */
-  @NotNull
-  public Date getTimestamp() {
-    return myTimestamp;
-  }
-
-  /**
-   * Returns changeset summary specified by user
-   * @return changeset summary
-   */
-  public String getSummary() {
-    return mySummary;
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-
-public class CloneCommand {
-  private Settings mySettings;
-  private String myDestDir;
-  private String myToId;
-  private boolean myUpdateWorkingDir = true;
-
-  public CloneCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public void setDestDir(@NotNull String destDir) {
-    myDestDir = destDir;
-  }
-
-  public void setToId(final String toId) {
-    myToId = toId;
-  }
-
-  public void setUpdateWorkingDir(final boolean updateWorkingDir) {
-    myUpdateWorkingDir = updateWorkingDir;
-  }
-
-  public void execute() throws VcsException {
-    if (myDestDir == null) throw new IllegalStateException("Destination dir must be specified");
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    File dir = new File(myDestDir);
-    File parent = dir.getParentFile();
-    cli.setWorkDirectory(parent.getAbsolutePath());
-    cli.addParameter("clone");
-    if (myToId != null) {
-      cli.addParameter("-r");
-      cli.addParameter(myToId);
-    }
-    cli.addParameter("--pull");
-    if (!myUpdateWorkingDir) {
-      cli.addParameter("-U");
-    }
-    cli.addParameter(mySettings.getRepository());
-    cli.addParameter(dir.getName());
-
-    CommandUtil.runCommand(cli);
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.SimpleCommandLineProcessRunner;
-import jetbrains.buildServer.log.Loggers;
-import jetbrains.buildServer.util.StringUtil;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-public class CommandUtil {
-  public static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res) throws VcsException {
-    if (res.getExitCode() > 0 || res.getException() != null) {
-      commandFailed(cmdName, res);
-    } 
-  }
-
-  public static void commandFailed(final String cmdName, final ExecResult res) throws VcsException {
-    Throwable exception = res.getException();
-    String stderr = res.getStderr();
-    String stdout = res.getStdout();
-    final String message = "'" + cmdName + "' command failed.\n" +
-            (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") +
-            (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") +
-            (exception != null ? "exception: " + exception.getLocalizedMessage() : "");
-    Loggers.VCS.warn(message);
-    throw new VcsException(message);
-  }
-
-  public static ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException {
-    String cmdStr = cli.getCommandLineString();
-    Loggers.VCS.debug("Run command: " + cmdStr);
-    ExecResult res = SimpleCommandLineProcessRunner.runCommand(cli, null);
-    CommandUtil.checkCommandFailed(cmdStr, res);
-    return res;
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * @author Pavel.Sher
- *         Date: 16.07.2008
- */
-public class IdentifyCommand {
-  private Settings mySettings;
-
-  public IdentifyCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public String execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.addParameter("identify");
-    cli.addParameter(mySettings.getRepository());
-    ExecResult res = CommandUtil.runCommand(cli);
-    if (res.getStderr().length() > 0) {
-      CommandUtil.commandFailed(cli.getCommandLineString(), res);
-    }
-    return res.getStdout();
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.openapi.diagnostic.Logger;
-import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-public class LogCommand {
-  private final static Logger LOG = Logger.getInstance(LogCommand.class.getName());
-  private String myFromId;
-  private String myToId;
-  private Settings mySettings;
-  private static final String CHANGESET_PREFIX = "changeset:";
-  private static final String USER_PREFIX = "user:";
-  private static final String DATE_PREFIX = "date:";
-  private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z";
-  private static final String SUMMARY_PREFIX = "summary:";
-
-  public LogCommand(@NotNull Settings settings) {
-    mySettings = settings;
-  }
-
-  public void setFromRevId(String id) {
-    myFromId = id;
-  }
-
-  public void setToRevId(String id) {
-    myToId = id;
-  }
-
-  public List<ChangeSet> execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.addParameter("log");
-    cli.addParameter("-r");
-    String from = myFromId;
-    if (from == null) from = "0";
-    String to = myToId;
-    if (to == null) to = "0";
-    cli.addParameter(from + ":" + to);
-
-    ExecResult res = CommandUtil.runCommand(cli);
-    return parseChangeSets(res.getStdout());
-  }
-
-  public static List<ChangeSet> parseChangeSets(final String stdout) {
-    List<ChangeSet> result = new ArrayList<ChangeSet>();
-    String[] lines = stdout.split("\n");
-    ChangeSet current = null;
-    int lineNum = 0;                  
-    while (lineNum < lines.length) {
-      String line = lines[lineNum];
-      lineNum++;
-
-      if (line.startsWith(CHANGESET_PREFIX)) {
-        String revAndId = line.substring(CHANGESET_PREFIX.length()).trim();
-        try {
-          current = new ChangeSet(revAndId);
-          result.add(current);
-        } catch (IllegalArgumentException e) {
-          LOG.warn("Unable to extract changeset id from the line: " + line);
-        }
-
-        continue;
-      }
-
-      if (current == null) continue;
-
-      if (line.startsWith(USER_PREFIX)) {
-        current.setUser(line.substring(USER_PREFIX.length()).trim());
-        continue;
-      }
-
-      if (line.startsWith(DATE_PREFIX)) {
-        String date = line.substring(DATE_PREFIX.length()).trim();
-        try {
-          Date parsedDate = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH).parse(date);
-          current.setTimestamp(parsedDate);
-        } catch (ParseException e) {
-          LOG.warn("Unable to parse date: " + date);
-          current = null;
-        }
-
-        continue;
-      }
-
-      if (line.startsWith(SUMMARY_PREFIX)) {
-        String summary = line.substring(SUMMARY_PREFIX.length()).trim();
-        current.setSummary(summary);
-
-        continue;
-      }
-    }
-
-    return result;
-  }
-
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright 2000-2007 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;
-
-/**
- * Represents repository modified file
- */
-public class ModifiedFile {
-  /**
-   * Type of modification
-   */
-  public static enum Status {
-    ADDED("added"),
-    MODIFIED("modified"),
-    REMOVED("removed"),
-    UNKNOWN("unknown");
-    private String myName;
-
-    Status(@NotNull final String name) {
-      myName = name;
-    }
-
-    @NotNull
-    public String getName() {
-      return myName;
-    }
-  }
-
-  @NotNull private Status myStatus;
-  @NotNull private String myPath;
-
-  public ModifiedFile(@NotNull final Status status, @NotNull final String path) {
-    myStatus = status;
-    myPath = path;
-  }
-
-  /**
-   * Returns type of modification
-   * @return type of modification
-   */
-  @NotNull
-  public Status getStatus() {
-    return myStatus;
-  }
-
-  /**
-   * Returns file path
-   * @return file path
-   */
-  @NotNull
-  public String getPath() {
-    return myPath;
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * @author Pavel.Sher
- *         Date: 14.07.2008
- */
-public class PullCommand {
-  private Settings mySettings;
-
-  public PullCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public void execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.addParameter("pull");
-    cli.addParameter(mySettings.getRepository());
-    CommandUtil.runCommand(cli);
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright 2000-2007 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.buildTriggers.vcs.mercurial.PathUtil;
-import jetbrains.buildServer.serverSide.ServerPaths;
-import jetbrains.buildServer.vcs.VcsRoot;
-import jetbrains.buildServer.util.Hash;
-import jetbrains.buildServer.util.FileUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-
-/**
- * Represents Mercurial repository settings
- */
-public class Settings {
-  private String myRepository;
-  private String myHgCommandPath;
-  private ServerPaths myServerPaths;
-  private File myWorkingDir;
-
-  public Settings(@NotNull ServerPaths paths, @NotNull VcsRoot vcsRoot) {
-    myServerPaths = paths;
-    setRepository(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
-    setHgCommandPath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
-  }
-
-  public Settings() {
-  }
-
-  public void setRepository(@NotNull final String repository) {
-    myRepository = repository;
-  }
-
-  /**
-   * Returns repository path
-   * @return repository path
-   */
-  @NotNull
-  public String getRepository() {
-    return myRepository;
-  }
-
-  /**
-   * Returns path to hg command
-   * @return path to hg command
-   */
-  @NotNull
-  public String getHgCommandPath() {
-    return myHgCommandPath;
-  }
-
-  public void setHgCommandPath(@NotNull final String hgCommandPath) {
-    myHgCommandPath = hgCommandPath;
-  }
-
-  public void setWorkingDir(@NotNull final File workingDir) {
-    myWorkingDir = FileUtil.getCanonicalFile(workingDir);
-  }
-
-  /**
-   * Returns repository working directory where all mercurial commands should be invoked
-   * @return repository working directory
-   */
-  @NotNull
-  public File getWorkingDir() {
-    if (myWorkingDir != null) {
-      return myWorkingDir;
-    }
-
-    return getDefaultWorkDir(myServerPaths, myRepository);
-  }
-
-  public static String DEFAULT_WORK_DIR_PREFIX = "hg_";
-
-  private static File getDefaultWorkDir(@NotNull ServerPaths serverPaths, @NotNull String repPath) {
-    String workingDirname = DEFAULT_WORK_DIR_PREFIX + String.valueOf(Hash.calc(normalize(repPath)));
-    File workFoldersRootDir = new File(serverPaths.getCachesDir(), "mercurial");
-    if (!workFoldersRootDir.mkdirs() && !workFoldersRootDir.isDirectory()) {
-      throw new RuntimeException("Cannot create directory: " + workFoldersRootDir.getAbsolutePath());
-    }
-    return FileUtil.getCanonicalFile(new File(workFoldersRootDir, workingDirname));
-  }
-
-  private static String normalize(final String path) {
-    String normalized = PathUtil.normalizeSeparator(path);
-    if (path.endsWith("/")) {
-      return normalized.substring(0, normalized.length()-1);
-    }
-    return normalized;
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class StatusCommand {
-  private Settings mySettings;
-  private String myFromId;
-  private String myToId;
-
-  public StatusCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public void setFromRevId(final String fromId) {
-    myFromId = fromId;
-  }
-
-  public void setToRevId(final String toId) {
-    myToId = toId;
-  }
-
-  public List<ModifiedFile> execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.addParameter("status");
-    cli.addParameter("--rev");
-    String from = myFromId;
-    if (from == null) from = "0";
-    String to = myToId;
-    if (to == null) to = "0";
-    cli.addParameter(from + ":" + to);
-    ExecResult res = CommandUtil.runCommand(cli);
-    return parseFiles(res.getStdout());
-  }
-
-  private List<ModifiedFile> parseFiles(final String stdout) {
-    List<ModifiedFile> result = new ArrayList<ModifiedFile>();
-    String[] lines = stdout.split("\n");
-    for (String line: lines) {
-      if (line.length() == 0) continue;
-      char modifier = line.charAt(0);
-      String path = line.substring(2);
-      ModifiedFile.Status status = toStatus(modifier);
-      if (status == ModifiedFile.Status.UNKNOWN) continue;
-      result.add(new ModifiedFile(status, path));
-    }
-    return result;
-  }
-
-  private ModifiedFile.Status toStatus(final char modifier) {
-    switch (modifier) {
-      case 'A': return ModifiedFile.Status.ADDED;
-      case 'M': return ModifiedFile.Status.MODIFIED;
-      case 'R': return ModifiedFile.Status.REMOVED;
-      default: return ModifiedFile.Status.UNKNOWN;
-    }
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TipCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.ExecResult;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * @author Pavel.Sher
- *         Date: 14.07.2008
- */
-public class TipCommand {
-  @NotNull
-  private Settings mySettings;
-
-  public TipCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  @NotNull
-  public ChangeSet execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.addParameter("tip");
-    ExecResult res = CommandUtil.runCommand(cli);
-    List<ChangeSet> changeSets = LogCommand.parseChangeSets(res.getStdout());
-    if (changeSets.isEmpty()) {
-      CommandUtil.commandFailed("hg tip", res);
-    }
-
-    return changeSets.get(0);
-  }
-}
--- a/mercurial/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java	Mon Jul 21 21:22:25 2008 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright 2000-2007 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 com.intellij.execution.configurations.GeneralCommandLine;
-import jetbrains.buildServer.vcs.VcsException;
-import org.jetbrains.annotations.NotNull;
-
-public class UpdateCommand {
-  private Settings mySettings;
-
-  public UpdateCommand(@NotNull final Settings settings) {
-    mySettings = settings;
-  }
-
-  public void execute() throws VcsException {
-    GeneralCommandLine cli = new GeneralCommandLine();
-    cli.setExePath(mySettings.getHgCommandPath());
-    cli.setWorkDirectory(mySettings.getWorkingDir().getAbsolutePath());
-    cli.addParameter("update");
-    cli.addParameter("-C");
-    CommandUtil.runCommand(cli);
-  }
-}