changeset 834:80ae3dc66685

TW-18605 add support for 'hg purge'
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Sun, 01 Jun 2014 22:16:18 +0200
parents 44e82363484c
children c08b42bb792f
files mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PurgeCommand.java mercurial-server/resources/buildServerResources/mercurialSettings.jsp mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseAgentSideCheckoutTestCase.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PurgeTest.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java mercurial-tests/src/testng.xml mercurial-tests/testData/testPurge/README mercurial-tests/testData/testPurge/hg/00changelog.i mercurial-tests/testData/testPurge/hg/bookmarks mercurial-tests/testData/testPurge/hg/branch mercurial-tests/testData/testPurge/hg/cache/branchheads-served mercurial-tests/testData/testPurge/hg/cache/tags mercurial-tests/testData/testPurge/hg/dirstate mercurial-tests/testData/testPurge/hg/last-message.txt mercurial-tests/testData/testPurge/hg/requires mercurial-tests/testData/testPurge/hg/store/00changelog.i mercurial-tests/testData/testPurge/hg/store/00manifest.i mercurial-tests/testData/testPurge/hg/store/data/a.i mercurial-tests/testData/testPurge/hg/store/data/~2ehgignore.i mercurial-tests/testData/testPurge/hg/store/data/~2ehgsub.i mercurial-tests/testData/testPurge/hg/store/data/~2ehgsubstate.i mercurial-tests/testData/testPurge/hg/store/fncache mercurial-tests/testData/testPurge/hg/store/phaseroots mercurial-tests/testData/testPurge/hg/store/undo mercurial-tests/testData/testPurge/hg/store/undo.phaseroots mercurial-tests/testData/testPurge/hg/undo.bookmarks mercurial-tests/testData/testPurge/hg/undo.branch mercurial-tests/testData/testPurge/hg/undo.desc mercurial-tests/testData/testPurge/hg/undo.dirstate
diffstat 32 files changed, 369 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java	Sun Jun 01 22:16:18 2014 +0200
@@ -31,6 +31,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 import static com.intellij.openapi.util.io.FileUtil.delete;
@@ -152,11 +154,29 @@
 
   private void updateWorkingDir(@NotNull File workingDir, @NotNull String toVersion, @NotNull String repositoryUrl) throws VcsException, IOException {
     HgRepo repo = myRepoFactory.createRepo(myRoot, workingDir);
-    updateSubrepositories(repo, toVersion, repositoryUrl);
+    List<File> repos = new ArrayList<File>();
+    updateSubrepositories(repo, toVersion, repositoryUrl, repos);
     doUpdateWorkingDir(repo, toVersion);
+    purge(repos);
   }
 
-  private void updateSubrepositories(@NotNull HgRepo repo, @NotNull String toVersion, @NotNull String parentRepositoryUrl) throws VcsException, IOException {
+  private void purge(@NotNull List<File> dirs) throws VcsException {
+    HgVcsRoot.PurgePolicy purgePolicy = myRoot.getPurgePolicy();
+    if (purgePolicy == HgVcsRoot.PurgePolicy.DONT_RUN)
+      return;
+    for (File dir : dirs) {
+      myLogger.message("Run purge in " + dir.getAbsolutePath());
+      HgRepo repo = myRepoFactory.createRepo(myRoot, dir);
+      repo.purge().withPolicy(purgePolicy).call();
+      myLogger.message("Purge in " + dir.getAbsolutePath() + " is finished");
+    }
+  }
+
+  private void updateSubrepositories(@NotNull HgRepo repo,
+                                     @NotNull String toVersion,
+                                     @NotNull String parentRepositoryUrl,
+                                     @NotNull List<File> repoAccumulator) throws VcsException, IOException {
+    repoAccumulator.add(repo.getWorkingDir());
     if (!repo.hasSubreposAtRevision(toVersion))
       return;
     myLogger.message("Process subrepos of " + parentRepositoryUrl);
@@ -183,7 +203,7 @@
         Loggers.VCS.warn("Failed to resolve subrepo url '" + subrepoConfig.url() + "'", e);
         subrepoUrl = subrepoConfig.url();
       }
-      updateSubrepositories(subrepository, subrepoConfig.revision(), subrepoUrl);
+      updateSubrepositories(subrepository, subrepoConfig.revision(), subrepoUrl, repoAccumulator);
     }
   }
 
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java	Sun Jun 01 22:16:18 2014 +0200
@@ -34,6 +34,6 @@
   String USE_ARCHIVE_FOR_PATCH = "useArchiveForPatch";
   String HG_EXTENSIONS = "hg.extensions";
   String HG_COMMANDLINE_VIA_FILE = "hg.pass.commandline.via.file";
-
+  String PURGE_POLICY = "purgePolicy";
   String GLOBAL_DETECT_SUBREPO_CHANGES = "teamcity.hg.detectSubrepoChanges";
 }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java	Sun Jun 01 22:16:18 2014 +0200
@@ -166,6 +166,10 @@
     FileUtil.delete(new File(dotHg, "bookmarks.current"));
   }
 
+  public PurgeCommand purge() {
+    return new PurgeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir);
+  }
+
   public String getHgPath() {
     return myHgPath;
   }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java	Sun Jun 01 22:16:18 2014 +0200
@@ -45,6 +45,7 @@
   private final boolean myUseTagsAsBranches;
   private final boolean myIncludeSubreposInPatch;
   private final boolean myUseArchiveForPatch;
+  private final PurgePolicy myPurgePolicy;
 
   public HgVcsRoot(@NotNull final VcsRoot vcsRoot) {
     this(vcsRoot.getProperties());
@@ -64,6 +65,15 @@
     String includeSubreposProp = getProperty(Constants.INCLUDE_SUBREPOS_IN_PATCH);
     myIncludeSubreposInPatch = includeSubreposProp == null ? true : Boolean.parseBoolean(includeSubreposProp);//true by default
     myUseArchiveForPatch = Boolean.parseBoolean(getProperty(Constants.USE_ARCHIVE_FOR_PATCH));
+    myPurgePolicy = readPurgePolicy(vcsRootProperties);
+  }
+
+  @NotNull
+  private PurgePolicy readPurgePolicy(@NotNull Map<String, String> properties) {
+    String policy = properties.get(Constants.PURGE_POLICY);
+    if (StringUtil.isEmpty(policy))
+      return PurgePolicy.DONT_RUN;
+    return PurgePolicy.valueOf(policy);
   }
 
   public HgVcsRoot withUrl(@NotNull String repositoryUrl) {
@@ -171,7 +181,19 @@
   }
 
   @NotNull
+  public PurgePolicy getPurgePolicy() {
+    return myPurgePolicy;
+  }
+
+  @NotNull
   public Map<String, String> getProperties() {
     return myVcsRootProperties;
   }
+
+
+  public static enum PurgePolicy {
+    DONT_RUN,
+    PURGE_UNKNOWN,
+    PURGE_ALL
+  }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PurgeCommand.java	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jetbrains.buildServer.buildTriggers.vcs.mercurial.command;
+
+import jetbrains.buildServer.vcs.VcsException;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+public class PurgeCommand extends BaseCommand {
+
+  private HgVcsRoot.PurgePolicy myPolicy;
+
+  public PurgeCommand(@NotNull CommandSettings commandSettings,
+                      @NotNull String hgPath,
+                      @NotNull File workingDir) {
+    super(commandSettings, hgPath, workingDir);
+  }
+
+  @NotNull
+  public PurgeCommand withPolicy(@NotNull HgVcsRoot.PurgePolicy policy) {
+    myPolicy = policy;
+    return this;
+  }
+
+  public void call() throws VcsException {
+    if (myPolicy == null || myPolicy == HgVcsRoot.PurgePolicy.DONT_RUN)
+      return;
+    MercurialCommandLine cmd = createCommandLine();
+    cmd.addParameters("--config", "extensions.purge=");
+    cmd.addParameter("purge");
+    if (myPolicy == HgVcsRoot.PurgePolicy.PURGE_ALL)
+      cmd.addParameter("--all");
+    runCommand(cmd);
+  }
+}
--- a/mercurial-server/resources/buildServerResources/mercurialSettings.jsp	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-server/resources/buildServerResources/mercurialSettings.jsp	Sun Jun 01 22:16:18 2014 +0200
@@ -101,5 +101,21 @@
     </td>
   </tr>
   </l:settingsGroup>
-
+  <l:settingsGroup title="Agent Settings" className="advancedSetting">
+    <tr class="advancedSetting">
+      <td colspan="2">Agent-specific settings that are used in case of agent checkout.</td>
+    </tr>
+    <tr class="advancedSetting">
+      <th>
+        <label for="purgePolicy">Purge settings:</label>
+      </th>
+      <td>
+        <props:selectProperty name="purgePolicy" enableFilter="true" className="mediumField">
+          <props:option value="">Don't run purge</props:option>
+          <props:option value="PURGE_UNKNOWN">Purge unknown files</props:option>
+          <props:option value="PURGE_ALL">Purge ignored & unknown files</props:option>
+        </props:selectProperty>
+      </td>
+    </tr>
+  </l:settingsGroup>
 </table>
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java	Sun Jun 01 22:16:18 2014 +0200
@@ -130,7 +130,7 @@
     return future.get();
   }
 
-  private File doUpdate(@NotNull VcsRoot root, @NotNull String version) throws VcsException {
+  protected File doUpdate(@NotNull VcsRoot root, @NotNull String version) throws VcsException {
     return doUpdate(root, version, IncludeRule.createDefaultInstance());
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseAgentSideCheckoutTestCase.java	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.agent.AgentRunningBuild;
+import jetbrains.buildServer.agent.BuildAgentConfiguration;
+import jetbrains.buildServer.agent.BuildProgressLogger;
+import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
+import jetbrains.buildServer.vcs.CheckoutRules;
+import jetbrains.buildServer.vcs.IncludeRule;
+import jetbrains.buildServer.vcs.VcsException;
+import jetbrains.buildServer.vcs.VcsRoot;
+import org.jetbrains.annotations.NotNull;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.testng.annotations.BeforeMethod;
+
+import java.io.File;
+import java.util.HashMap;
+
+public abstract class BaseAgentSideCheckoutTestCase extends BaseMercurialTestCase {
+
+  protected Mockery myContext;
+  protected BuildProgressLogger myLogger;
+  protected UpdateByIncludeRules2 myVcsSupport;
+  private int myBuildCounter = 0;
+  protected File myWorkDir;
+
+  @Override
+  @BeforeMethod
+  public void setUp() throws Exception {
+    super.setUp();
+
+    myContext = new Mockery();
+
+    final BuildAgentConfiguration agentConfig = myContext.mock(BuildAgentConfiguration.class);
+    myContext.checking(new Expectations() {{
+      allowing(agentConfig).getCacheDirectory("mercurial"); will(returnValue(myTempFiles.createTempDir()));
+      allowing(agentConfig).getParametersResolver(); will(returnValue(new HgPathResolver()));
+    }});
+
+    final AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig);
+    MirrorManager mirrorManager = new MirrorManagerImpl(pluginConfig);
+    CommandSettingsForRootImpl commandSettingsFactory = new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver());
+    myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, mirrorManager, new AgentRepoFactory(commandSettingsFactory, new AgentHgPathProvider(agentConfig)));
+
+    myLogger = myContext.mock(BuildProgressLogger.class);
+    myContext.checking(new Expectations() {{
+      allowing(myLogger).message(with(any(String.class)));
+      allowing(myLogger).warning(with(any(String.class)));
+    }});
+
+    myWorkDir = myTempFiles.createTempDir();
+  }
+
+
+  protected void checkout(@NotNull VcsRoot vcsRoot, @NotNull String toVersion) throws VcsException {
+    checkout(vcsRoot, toVersion, false);
+  }
+
+  protected void checkout(@NotNull VcsRoot vcsRoot, @NotNull String toVersion, final boolean useLocalMirrors) throws VcsException {
+    final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++);
+    myContext.checking(new Expectations() {{
+      allowing(build).getBuildLogger(); will(returnValue(myLogger));
+      allowing(build).getSharedConfigParameters(); will(returnValue(new HashMap<String, String>() {{
+        put("teamcity.hg.use.local.mirrors", useLocalMirrors ? "true" : "false");
+      }}));
+    }});
+    myVcsSupport.getUpdater(vcsRoot, CheckoutRules.DEFAULT, toVersion, myWorkDir, build, false).process(IncludeRule.createDefaultInstance(), myWorkDir);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PurgeTest.java	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package jetbrains.buildServer.buildTriggers.vcs.mercurial;
+
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
+import jetbrains.buildServer.util.FileUtil;
+import jetbrains.buildServer.vcs.VcsRoot;
+import org.jetbrains.annotations.NotNull;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;
+import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+@Test
+public class PurgeTest extends BaseAgentSideCheckoutTestCase {
+
+  private String myRemoteRepository;
+
+  @Override
+  @BeforeMethod
+  public void setUp() throws Exception {
+    super.setUp();
+
+    File tmp = myTempFiles.createTempDir();
+    File remoteRepo = new File(tmp, "testPurge");
+    copyRepository(new File("mercurial-tests/testData/testPurge"), remoteRepo);
+    myRemoteRepository = remoteRepo.getAbsolutePath();
+  }
+
+
+  public void purge_unknown() throws Exception {
+    VcsRoot vcsRoot = vcsRoot().withUrl(myRemoteRepository).withPurgePolicy(HgVcsRoot.PurgePolicy.PURGE_UNKNOWN).build();
+    checkout(vcsRoot, "1:80a857d1f74b");
+
+    File unknownFile = createUnknownFile(myWorkDir);
+    File ignoredFile = createIgnoredFile(myWorkDir);
+
+    checkout(vcsRoot, "1:80a857d1f74b");
+
+    assertFalse(unknownFile.exists());
+    assertTrue(ignoredFile.exists());
+  }
+
+
+  public void purge_all() throws Exception {
+    VcsRoot vcsRoot = vcsRoot().withUrl(myRemoteRepository).withPurgePolicy(HgVcsRoot.PurgePolicy.PURGE_ALL).build();
+    checkout(vcsRoot, "1:80a857d1f74b");
+
+    File unknownFile = createUnknownFile(myWorkDir);
+    File ignoredFile = createIgnoredFile(myWorkDir);
+
+    checkout(vcsRoot, "1:80a857d1f74b");
+
+    assertFalse(unknownFile.exists());
+    assertFalse(ignoredFile.exists());
+  }
+
+
+  public void purge_unknown_subrepos() throws Exception {
+    VcsRoot vcsRoot = vcsRoot().withUrl(myRemoteRepository).withPurgePolicy(HgVcsRoot.PurgePolicy.PURGE_UNKNOWN).build();
+    checkout(vcsRoot, "2:5998f41141bc");
+
+    File unknownFile = createUnknownFile(myWorkDir);
+    File ignoredFile = createIgnoredFile(myWorkDir);
+    File unknownFileSubrepo = createUnknownFile(new File(myWorkDir, "self"));
+    File ignoredFileSubrepo = createIgnoredFile(new File(myWorkDir, "self"));
+
+    checkout(vcsRoot, "2:5998f41141bc");
+
+    assertFalse(unknownFile.exists());
+    assertFalse(unknownFileSubrepo.exists());
+    assertTrue(ignoredFile.exists());
+    assertTrue(ignoredFileSubrepo.exists());
+  }
+
+
+  public void purge_all_subrepos() throws Exception {
+    VcsRoot vcsRoot = vcsRoot().withUrl(myRemoteRepository).withPurgePolicy(HgVcsRoot.PurgePolicy.PURGE_ALL).build();
+    checkout(vcsRoot, "2:5998f41141bc");
+
+    File unknownFile = createUnknownFile(myWorkDir);
+    File ignoredFile = createIgnoredFile(myWorkDir);
+    File unknownFileSubrepo = createUnknownFile(new File(myWorkDir, "self"));
+    File ignoredFileSubrepo = createIgnoredFile(new File(myWorkDir, "self"));
+
+    checkout(vcsRoot, "2:5998f41141bc");
+
+    assertFalse(unknownFile.exists());
+    assertFalse(unknownFileSubrepo.exists());
+    assertFalse(ignoredFile.exists());
+    assertFalse(ignoredFileSubrepo.exists());
+  }
+
+
+  private File createUnknownFile(@NotNull File parentDir) throws IOException {
+    File unknownFile = new File(parentDir, "unknownFile");
+    FileUtil.writeFile(unknownFile, "some data", "UTF-8");
+    return unknownFile;
+  }
+
+
+  private File createIgnoredFile(@NotNull File parentDir) throws IOException {
+    File ignoredFile = new File(parentDir, "ignoredFile");
+    FileUtil.writeFile(ignoredFile, "some data", "UTF-8");
+    return ignoredFile;
+  }
+}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java	Sun Jun 01 22:16:18 2014 +0200
@@ -16,6 +16,7 @@
 
 package jetbrains.buildServer.buildTriggers.vcs.mercurial;
 
+import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot;
 import jetbrains.buildServer.util.StringUtil;
 import jetbrains.buildServer.vcs.SVcsRoot;
 import jetbrains.buildServer.vcs.impl.VcsRootImpl;
@@ -45,6 +46,7 @@
   private boolean myTagsAsBranches = false;
   private boolean myIncludeSubreposInPatch = true;
   private boolean myUseArchiveForPatch = false;
+  private HgVcsRoot.PurgePolicy myPurgePolicy;
 
   public static VcsRootBuilder vcsRoot() {
     return new VcsRootBuilder();
@@ -66,6 +68,8 @@
     if (myCloneRepositoryTo != null)
       vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, String.valueOf(myCloneRepositoryTo.getAbsolutePath()));
     vcsRoot.addProperty(Constants.USE_TAGS_AS_BRANCHES, String.valueOf(myTagsAsBranches));
+    if (myPurgePolicy != null)
+      vcsRoot.addProperty(Constants.PURGE_POLICY, myPurgePolicy.name());
     return vcsRoot;
   }
 
@@ -183,4 +187,10 @@
     myTagsAsBranches = useTagsAsBranches;
     return this;
   }
+
+
+  public VcsRootBuilder withPurgePolicy(HgVcsRoot.PurgePolicy policy) {
+    myPurgePolicy = policy;
+    return this;
+  }
 }
--- a/mercurial-tests/src/testng.xml	Fri May 30 18:42:53 2014 +0200
+++ b/mercurial-tests/src/testng.xml	Sun Jun 01 22:16:18 2014 +0200
@@ -54,6 +54,7 @@
       <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialModificationInfoBuilderTest"/>
       <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialUrlSupportTest"/>
       <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommitsAndMountPointsCommandParserTest"/>
+      <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.PurgeTest"/>
     </classes>
   </test>
 </suite>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/README	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,5 @@
+o  changeset:   2:5998f41141bc //add same repo as a subrepo at path self
+|
+o  changeset:   1:80a857d1f74b //ignores ignoredFile
+|
+o  changeset:   0:8a9ae2d32de0 //contains file a
Binary file mercurial-tests/testData/testPurge/hg/00changelog.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/branch	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,1 @@
+default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/cache/branchheads-served	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,2 @@
+5998f41141bcbe2fa5cd423902ddb75deb5ce4a6 2
+5998f41141bcbe2fa5cd423902ddb75deb5ce4a6 default
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/cache/tags	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,2 @@
+2 5998f41141bcbe2fa5cd423902ddb75deb5ce4a6
+
Binary file mercurial-tests/testData/testPurge/hg/dirstate has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/last-message.txt	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,1 @@
+Add same repo in rev 1 as subrepo at path self
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/requires	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,4 @@
+dotencode
+fncache
+revlogv1
+store
Binary file mercurial-tests/testData/testPurge/hg/store/00changelog.i has changed
Binary file mercurial-tests/testData/testPurge/hg/store/00manifest.i has changed
Binary file mercurial-tests/testData/testPurge/hg/store/data/a.i has changed
Binary file mercurial-tests/testData/testPurge/hg/store/data/~2ehgignore.i has changed
Binary file mercurial-tests/testData/testPurge/hg/store/data/~2ehgsub.i has changed
Binary file mercurial-tests/testData/testPurge/hg/store/data/~2ehgsubstate.i has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/store/fncache	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,4 @@
+data/.hgsubstate.i
+data/.hgignore.i
+data/.hgsub.i
+data/a.i
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/store/phaseroots	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,1 @@
+1 8a9ae2d32de0d0c80124f88ec18e376587b0ecdb
Binary file mercurial-tests/testData/testPurge/hg/store/undo has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/store/undo.phaseroots	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,1 @@
+1 8a9ae2d32de0d0c80124f88ec18e376587b0ecdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/undo.branch	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,1 @@
+default
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial-tests/testData/testPurge/hg/undo.desc	Sun Jun 01 22:16:18 2014 +0200
@@ -0,0 +1,2 @@
+2
+commit
Binary file mercurial-tests/testData/testPurge/hg/undo.dirstate has changed