Mercurial > hg > mercurial
changeset 842:951ace007006
Merge branch Gaya-8.1.x
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Wed, 18 Jun 2014 12:14:56 +0200 |
parents | e36e8d036ebd (diff) 46eee4b37e58 (current diff) |
children | eb4a87121757 |
files | mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java |
diffstat | 86 files changed, 1888 insertions(+), 501 deletions(-) [+] |
line wrap: on
line diff
--- a/.idea/libraries/TeamCity_impl.xml Tue Jun 17 22:30:00 2014 +0200 +++ b/.idea/libraries/TeamCity_impl.xml Wed Jun 18 12:14:56 2014 +0200 @@ -3,6 +3,7 @@ <CLASSES> <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/patches-impl.jar!/" /> <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove4j.jar!/" /> + <root url="jar://$TeamCityDistribution$/webapps/ROOT/WEB-INF/lib/trove-3.0.3.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.idea/runConfigurations/tests_via_file.xml Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,32 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="tests via file" type="TestNG" factoryName="TestNG"> + <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" /> + <module name="mercurial-tests" /> + <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> + <option name="ALTERNATIVE_JRE_PATH" value="" /> + <option name="SUITE_NAME" value="$PROJECT_DIR$/mercurial-tests/src/testng-via-cmd.xml" /> + <option name="PACKAGE_NAME" value="" /> + <option name="MAIN_CLASS_NAME" value="" /> + <option name="METHOD_NAME" value="" /> + <option name="GROUP_NAME" value="" /> + <option name="TEST_OBJECT" value="SUITE" /> + <option name="VM_PARAMETERS" value="-ea -Dteamcity.mercurial.use.commandline.via.file.wrapper=true" /> + <option name="PARAMETERS" value="" /> + <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" /> + <option name="OUTPUT_DIRECTORY" value="" /> + <option name="ANNOTATION_TYPE" /> + <option name="ENV_VARIABLES" /> + <option name="PASS_PARENT_ENVS" value="true" /> + <option name="TEST_SEARCH_SCOPE"> + <value defaultName="moduleWithDependencies" /> + </option> + <option name="USE_DEFAULT_REPORTERS" value="false" /> + <option name="PROPERTIES_FILE" value="" /> + <envs /> + <properties /> + <listeners /> + <RunnerSettings RunnerId="Run" /> + <ConfigurationWrapper RunnerId="Run" /> + <method /> + </configuration> +</component> \ No newline at end of file
--- a/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Wed Jun 18 12:14:56 2014 +0200 @@ -26,4 +26,8 @@ <bean id="mirrorCleaner" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentMirrorCleaner" /> <bean id="commandSettingsFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentCommandSettingsFactory" /> <bean id="agentRepoFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentRepoFactory"/> + + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver"/> </beans>
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentCommandSettingsFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentCommandSettingsFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -18,9 +18,11 @@ import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettings; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import org.jetbrains.annotations.NotNull; public class AgentCommandSettingsFactory implements CommandSettingsFactory { + @NotNull public CommandSettings create() { return new CommandSettings().setLogLevel("info"); }
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentRepoFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentRepoFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,8 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRoot; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -26,23 +25,16 @@ public class AgentRepoFactory implements HgRepoFactory { - private final CommandSettingsFactory myCommandSettingsFactory; + private final CommandSettingsForRoot myCommandSettingsFactory; private final HgPathProvider myHgPathProvider; - public AgentRepoFactory(@NotNull CommandSettingsFactory commandSettingsFactory, + public AgentRepoFactory(@NotNull CommandSettingsForRoot commandSettingsFactory, @NotNull HgPathProvider hgPathProvider) { myCommandSettingsFactory = commandSettingsFactory; myHgPathProvider = hgPathProvider; } public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException { - return new HgRepo(myCommandSettingsFactory, workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); + return new HgRepo(myCommandSettingsFactory.forRoot(root), workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); } - - public HgRepo create(@NotNull File workingDir, - @NotNull String hgPath, - @NotNull AuthSettings authSettings) { - return new HgRepo(myCommandSettingsFactory, workingDir, hgPath, authSettings); - } - }
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Wed Jun 18 12:14:56 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 Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java Wed Jun 18 12:14:56 2014 +0200 @@ -32,6 +32,8 @@ String USE_TAGS_AS_BRANCHES = "useTagsAsBranches"; String INCLUDE_SUBREPOS_IN_PATCH = "includeSubreposInPatch"; 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/HgFileUtil.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java Wed Jun 18 12:14:56 2014 +0200 @@ -44,12 +44,15 @@ * @return created dir * @throws IOException in case of I/O error */ + @NotNull public static File createTempDir() throws IOException { File parentDir = new File(FileUtil.getTempDirectory()); return createTempDir(parentDir); } - public static File createTempDir(@NotNull File parentDir) throws IOException { + @NotNull + public static File createTempDir(@NotNull final File parentDir) throws IOException { + //noinspection ResultOfMethodCallIgnored parentDir.mkdirs(); int suffix = 0; @@ -80,15 +83,15 @@ } } - - private static Object getTmpDirLock(@NotNull String tmpDirName) { + @NotNull + private static Object getTmpDirLock(@NotNull final String tmpDirName) { Object tmpDirLock = new Object(); Object existingLock = myTmpDirLocks.putIfAbsent(tmpDirName, tmpDirLock); return existingLock != null ? existingLock : tmpDirLock; } - public static void deleteDir(@Nullable File dir, @NotNull Logger logger) { + public static void deleteDir(@Nullable final File dir, @NotNull final Logger logger) { if (dir == null) return; final String dirPath;
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Wed Jun 18 12:14:56 2014 +0200 @@ -24,7 +24,10 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -166,6 +169,10 @@ FileUtil.delete(new File(dotHg, "bookmarks.current")); } + public PurgeCommand purge() { + return new PurgeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); + } + public String getHgPath() { return myHgPath; } @@ -184,8 +191,13 @@ return files; } + @NotNull public String getWorkingDirRevision() throws VcsException { - return id().inLocalRepository().call(); + List<String> workingDirParents = parents().call(); + if (workingDirParents.isEmpty()) + return LogCommand.ZERO_PARENT_SHORT_ID;//'hg id' shows zeroid when a working dir has no parents + //if a working dir is in an uncommitted merge state, choose the first parent + return workingDirParents.get(0); } public boolean containsRevision(@NotNull String revision) { @@ -313,16 +325,19 @@ } //path->subrepo - public Map<String, SubRepo> getSubrepositories(@NotNull ChangeSet cset) { - String revId = cset.getId(); + @NotNull + public Map<String, SubRepo> getSubrepositories(@NotNull final ChangeSet cset) { + final String revId = cset.getId(); + Map<String, SubRepo> subrepos = mySubreposCache.get(revId); - if (subrepos != null) + if (subrepos != null) { return new HashMap<String, SubRepo>(subrepos); - CatCommand cc = cat(); - cc.setRevId(revId); + } + File catDir = null; + final CatCommand cc = cat().setRevId(revId).files(asList(".hgsub", ".hgsubstate")).checkForFailure(false); try { - catDir = cc.execute(asList(".hgsub", ".hgsubstate"), false); + catDir = cc.call(); subrepos = HgSubs.readSubrepositories(new File(catDir, ".hgsub"), new File(catDir, ".hgsubstate")); mySubreposCache.put(revId, subrepos); return new HashMap<String, SubRepo>(subrepos);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialClasspathTemplate.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +import static com.intellij.openapi.util.io.FileUtil.createTempFile; +import static com.intellij.openapi.util.io.FileUtil.delete; + +/** +* Created 25.02.14 11:29 +* +* @author Eugene Petrenko (eugene.petrenko@jetbrains.com) +*/ +public class MercurialClasspathTemplate implements MercurialTemplate { + private final String myResourcePath; + private final String myTmpFileSuffix; + + public MercurialClasspathTemplate(@NotNull final String resourcePath, + @NotNull final String tmpFileSuffix) { + myResourcePath = resourcePath; + myTmpFileSuffix = tmpFileSuffix; + } + + @NotNull + public <T> T withTemplate(@NotNull final WithTemplate<T> action) throws VcsException { + //TODO: we may pack plugin and use jetbrains.buildServer.web.openapi.PluginDescriptor.getPluginRoot() + //TODO: to get path to existing file + final File template = copyTemplate(); + try { + return action.action(template); + } finally { + delete(template); + } + } + + private File copyTemplate() throws VcsException { + try { + final File template = createTempFile("teamcity", myTmpFileSuffix); + FileUtil.copyResource(getClass(), myResourcePath, template); + return template; + } catch (IOException e) { + throw new VcsException("Cannot create mercurial log template", e); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialTemplate.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Created 25.02.14 11:51 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public interface MercurialTemplate { + @NotNull + <T> T withTemplate(@NotNull WithTemplate<T> action) throws VcsException; + + interface WithTemplate<T> { + @NotNull + T action(@NotNull final File template) throws VcsException; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OS.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OS.java Wed Jun 18 12:14:56 2014 +0200 @@ -29,7 +29,7 @@ private static int _COMMAND_LINE_LIMIT() { final String OS_NAME = System.getProperty("os.name").toLowerCase(); ///http://partmaps.org/era/unix/arg-max.html - if (!OS_NAME.startsWith("windows")) return 128 * 1024 - 1; //128kb + if (!OS_NAME.contains("windows")) return 128 * 1024 - 1; //128kb //http://support.microsoft.com/kb/830473/en-us if (OS_NAME.matches("windows\\s+(2000|xp|nt)")) {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -29,7 +29,6 @@ */ 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; @@ -39,8 +38,6 @@ import java.util.List; public class ArchiveCommand extends AuthCommand { - private final static int MAX_CMD_LEN = 900; - private File myDestination; private String myToId; private String myType = "files"; @@ -68,11 +65,14 @@ return this; } - public boolean addIncludeRule(@NotNull String rule) { - MercurialCommandLine cmd = createCmd(); - int cmdSize = cmd.getCommandLineString().length(); - if (cmdSize + rule.length() + (myIncludeRules.isEmpty() ? 0 : "-I ".length()) > MAX_CMD_LEN) + public boolean addIncludeRule(@NotNull final String rule) { + final MercurialCommandLine cmd = createCmd(); + + final int cmdSize = cmd.getCommandLineLength(); + if (cmdSize + rule.length() + 3 + (myIncludeRules.isEmpty() ? 0 : "-I ".length()) > getMaxCommandLineSize()) { return false; + } + myIncludeRules.add(rule); return true; } @@ -86,40 +86,30 @@ deleteHgArchival(); } + @NotNull private MercurialCommandLine createCmd() { - MercurialCommandLine cli = createCommandLine(); - addHttpAuthParams(cli); - cli.addParameter("archive"); - setType(cli); - setRevision(cli); - setDestination(cli); - addIncludeRules(cli); - return cli; - } + final MercurialCommandLine cli = createCommandLine(); - private void addIncludeRules(@NotNull MercurialCommandLine cli) { - if (myIncludeRules.isEmpty()) - return; - cli.addParameter("-I"); - cli.addParameters(myIncludeRules); - } + addHttpAuthParams(cli); - private void setDestination(GeneralCommandLine cli) { - cli.addParameter(myDestination.getAbsolutePath()); - } + cli.addParameter("archive"); + cli.addParameter("-t"); + cli.addParameter(myType); + cli.addParameter("-r"); - private void setRevision(GeneralCommandLine cli) { - cli.addParameter("-r"); if (myToId != null) { cli.addParameter(myToId); } else { cli.addParameter("tip"); } - } - private void setType(GeneralCommandLine cli) { - cli.addParameter("-t"); - cli.addParameter(myType); + for (String include : myIncludeRules) { + cli.addParameter("-I"); + cli.addParameter(include); + } + cli.addParameter(myDestination.getAbsolutePath()); + + return cli; } /**
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AuthCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AuthCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,7 +16,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import com.intellij.execution.configurations.GeneralCommandLine; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -33,13 +32,14 @@ super(commandSettings, hgPath, workingDir, authSettings); } + @NotNull protected MercurialCommandLine createCL() { MercurialCommandLine cmd = super.createCL(); cmd.addParameters("--config", "ui.interactive=False"); return cmd; } - protected void addHttpAuthParams(@NotNull GeneralCommandLine cmd) { + protected void addHttpAuthParams(@NotNull final MercurialCommandLine cmd) { if (myAuthSettings.getUsername() == null || myAuthSettings.getPassword() == null) return; cmd.addParameters("--config", "auth.tc.prefix=*");
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -32,37 +32,70 @@ private final String myHgPath; private final File myWorkDirectory; - public BaseCommand(@NotNull CommandSettings commandSettings, + public BaseCommand(@NotNull final CommandSettings commandSettings, @NotNull final String hgPath, - @NotNull File workingDir) { + @NotNull final File workingDir) { myCommandSettings = commandSettings; myHgPath = hgPath; myWorkDirectory = workingDir; } + protected final int getMaxCommandLineSize() { + return allowCommandlineViaFileWrapper() + ? Integer.MAX_VALUE + : myCommandSettings.getMaxCommandLineSize(); + } + + protected boolean allowCommandlineViaFileWrapper() { + return true; + } public File getWorkDirectory() { return myWorkDirectory; } + @NotNull protected MercurialCommandLine createCommandLine() { MercurialCommandLine cli = createCL(); cli.setWorkDirectory(myWorkDirectory.getAbsolutePath()); return cli; } + @NotNull protected MercurialCommandLine createCL() { - MercurialCommandLine cl = new MercurialCommandLine(getPrivateData()); + final MercurialCommandLine cl = new MercurialCommandLine(getPrivateData()); cl.setExePath(myHgPath); cl.setEnvParams(myCommandSettings.getHgEnv()); - cl.setPassParentEnvs(true); + + //include global arguments if any + cl.addParameters(myCommandSettings.getGlobalArguments()); + return cl; } - protected CommandResult runCommand(@NotNull MercurialCommandLine cli) throws VcsException { - return CommandUtil.runCommand(cli, myCommandSettings); + @NotNull + protected final CommandResult runCommand(@NotNull MercurialCommandLine cli) throws VcsException { + return runCommand(cli, myCommandSettings); } + @NotNull + protected final CommandResult runCommand(@NotNull final MercurialCommandLine cli, + @NotNull final CommandSettings commandSettings) throws VcsException { + + if (!myCommandSettings.getUseCommandlineViaFileWrapper() || !allowCommandlineViaFileWrapper()) { + return CommandUtil.runCommand(cli, commandSettings.setPrivateData(getPrivateData())); + } + + return CommandUtil.runWrappedCommand(cli, commandSettings); + } + + protected void setupExtensionsFromResource(@NotNull final MercurialCommandLine cli, + @NotNull final File tempDir, + @NotNull final String commandPy) throws VcsException{ + CommandUtil.setupExtensionsFromResource(cli, tempDir, commandPy); + } + + @NotNull protected Set<String> getPrivateData() { return emptySet(); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,7 +16,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.OS; import jetbrains.buildServer.log.Loggers; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -44,45 +43,43 @@ super(commandSettings, hgPath, workingDir, authSettings); } + @NotNull public CatCommand files(@NotNull String relativePath) { myRelativePaths = singletonList(relativePath); return this; } + @NotNull public CatCommand files(@NotNull List<String> relativePaths) { myRelativePaths = relativePaths; return this; } + @NotNull public CatCommand setRevId(final String revId) { myRevId = revId; return this; } + @NotNull public CatCommand atRevision(@NotNull ChangeSet cset) { myRevId = cset.getId(); return this; } + @NotNull public CatCommand checkForFailure(boolean doCheckForFailure) { myCheckForFailure = doCheckForFailure; return this; } + @NotNull public File call() throws VcsException { - return execute(myRelativePaths, myCheckForFailure); - } - - public File execute(List<String> relPaths) throws VcsException { - return execute(relPaths, true); - } - - public File execute(List<String> relPaths, boolean checkFailure) throws VcsException { File tempDir = null; try { tempDir = createTmpDir(); - createDirectories(relPaths, tempDir); - catFiles(relPaths, checkFailure, tempDir); + createDirectories(myRelativePaths, tempDir); + catFiles(myRelativePaths, myCheckForFailure, tempDir); return tempDir; } catch (VcsException e) { deleteDir(tempDir, Loggers.VCS); @@ -90,6 +87,7 @@ } } + @NotNull private File createTmpDir() throws VcsException { try { return HgFileUtil.createTempDir(); @@ -98,7 +96,7 @@ } } - private void createDirectories(List<String> relPaths, File tempDir) throws VcsException { + private void createDirectories(@NotNull final List<String> relPaths, @NotNull final File tempDir) throws VcsException { for (String path: relPaths) { File parentFile = new File(tempDir, path).getParentFile(); if (!parentFile.isDirectory() && !parentFile.mkdirs()) @@ -106,24 +104,27 @@ } } - private void catFiles(List<String> relPaths, boolean checkFailure, File tempDir) throws VcsException { - Queue<String> paths = new LinkedList<String>(relPaths); + private void catFiles(@NotNull final List<String> relPaths, + final boolean checkFailure, + @NotNull final File tempDir) throws VcsException { + final Queue<String> paths = new LinkedList<String>(relPaths); while (!paths.isEmpty()) { MercurialCommandLine cli = createCommandLine(tempDir); - int cmdSize = cli.getCommandLineString().length() + 42; + int cmdSize = cli.getCommandLineLength() + 42; do { String path = paths.poll(); cli.addParameter(path); cmdSize += path.length() + 3; //quotes + space - } while (cmdSize < OS.getMaxCommandLineSize() && !paths.isEmpty()); + } while (cmdSize < getMaxCommandLineSize() && !paths.isEmpty()); runCommand(cli, myCommandSettings.setCheckForFailure(checkFailure)); } } - private MercurialCommandLine createCommandLine(final File tempDir) { - MercurialCommandLine cli = createCommandLine(); + @NotNull + private MercurialCommandLine createCommandLine(@NotNull final File tempDir) { + final MercurialCommandLine cli = createCommandLine(); addHttpAuthParams(cli); cli.addParameter("cat"); cli.addParameter("-o");
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -29,6 +29,7 @@ private boolean myUsePullProtocol = true; private boolean myUseUncompressedTransfer = false; private boolean myTraceback; + private ProgressParser.ProgressConsumer myProgressConsumer; public CloneCommand(@NotNull CommandSettings commandSettings, @NotNull String hgPath, @@ -76,6 +77,11 @@ return this; } + public CloneCommand withProgressConsumer(ProgressParser.ProgressConsumer progressConsumer) { + myProgressConsumer = progressConsumer; + return this; + } + public void call() throws VcsException { myWorkingDir.mkdirs(); MercurialCommandLine cli = createCommandLine(); @@ -96,10 +102,20 @@ if (myUseUncompressedTransfer) { cli.addParameter("--uncompressed"); } + + CommandSettings settings = myCommandSettings.setTimeout(24 * 3600); // some repositories are quite large, we set timeout to 24 hours + if (myProgressConsumer != null) { + cli.addParameters("--config", "extensions.progress="); + cli.addParameters("--config", "progress.format=topic number"); + cli.addParameters("--config", "progress.delay=0"); + cli.addParameters("--config", "progress.assume-tty=True"); + settings.setProgressConsumer(myProgressConsumer); + } + String repositoryUrl = myAuthSettings.getRepositoryUrlWithCredentials(myRepository); cli.addParameter(repositoryUrl); cli.addParameter(myWorkingDir.getName()); - runCommand(cli, myCommandSettings.setTimeout(24 * 3600)); // some repositories are quite large, we set timeout to 24 hours + runCommand(cli, settings); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettings.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettings.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,12 +16,10 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.OS; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author dmitry.neverov @@ -29,28 +27,29 @@ public class CommandSettings { private int myTimeout = 3600; - private Set<String> myPrivateData = new HashSet<String>(); + private final Set<String> myPrivateData = new HashSet<String>(); private boolean myCheckForFailure = true; private boolean myFailWhenStderrNotEmpty = false; private String myLogLevel = "debug"; private Map<String, String> myHgEnv = new HashMap<String, String>(); private int myLogOutputLimit = -1; private int myExceptionOutputLimit = 5000; + private List<String> myGlobalArguments = new ArrayList<String>(0); + private ProgressParser.ProgressConsumer myProgressConsumer; + private boolean myUseCommandlineViaFileWrapper = false; - public CommandSettings() { - + public final int getMaxCommandLineSize() { + return OS.getMaxCommandLineSize(); } - public CommandSettings(int timeout, - @NotNull Set<String> privateData, - boolean checkForFailure, - boolean failWhenStderrNotEmpty, - @NotNull String logLevel) { - myTimeout = timeout; - myPrivateData = privateData; - myCheckForFailure = checkForFailure; - myFailWhenStderrNotEmpty = failWhenStderrNotEmpty; - myLogLevel = logLevel; + public boolean getUseCommandlineViaFileWrapper() { + return myUseCommandlineViaFileWrapper; + } + + @NotNull + public CommandSettings setUseCommandlineViaFileWrapper(final boolean useCommandlineViaFileWrapper) { + myUseCommandlineViaFileWrapper = useCommandlineViaFileWrapper; + return this; } public CommandSettings setTimeout(int timeout) { @@ -58,12 +57,23 @@ return this; } + @NotNull + public List<String> getGlobalArguments() { + return myGlobalArguments; + } + + @NotNull + public CommandSettings withGlobalArguments(@NotNull String... argz) { + myGlobalArguments.addAll(Arrays.asList(argz)); + return this; + } + public int getTimeout() { return myTimeout; } public CommandSettings setPrivateData(@NotNull Set<String> privateData) { - myPrivateData = privateData; + myPrivateData.addAll(privateData); return this; } @@ -124,4 +134,12 @@ public void setExceptionOutputLimit(int limit) { myExceptionOutputLimit = limit; } + + public ProgressParser.ProgressConsumer getProgressConsumer() { + return myProgressConsumer; + } + + public void setProgressConsumer(ProgressParser.ProgressConsumer progressConsumer) { + myProgressConsumer = progressConsumer; + } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,8 +16,11 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import org.jetbrains.annotations.NotNull; + public interface CommandSettingsFactory { + @NotNull CommandSettings create(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsForRoot.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +/** + * Created 25.02.14 12:58 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public interface CommandSettingsForRoot { + @NotNull CommandSettingsFactory forRoot(@NotNull HgVcsRoot root); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsForRootImpl.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +/** + * Created 25.02.14 13:01 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class CommandSettingsForRootImpl implements CommandSettingsForRoot { + private final CommandSettingsFactory myFactory; + private final CommandSettingsWeaver[] myWeavers; + + public CommandSettingsForRootImpl(@NotNull CommandSettingsFactory factory, + @NotNull final CommandSettingsWeaver... weavers) { + myFactory = factory; + myWeavers = weavers; + } + + @NotNull + public CommandSettingsFactory forRoot(@NotNull final HgVcsRoot root) { + return new CommandSettingsFactory() { + @NotNull + public CommandSettings create() { + CommandSettings settings = myFactory.create(); + for (CommandSettingsWeaver weaver : myWeavers) { + settings = weaver.update(root, settings); + } + return settings; + } + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandSettingsWeaver.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +/** + * Created 25.02.14 13:02 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public interface CommandSettingsWeaver { + @NotNull + CommandSettings update(@NotNull HgVcsRoot root, @NotNull CommandSettings settings); +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,20 +16,94 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.LineAwareByteArrayOutputStream; import jetbrains.buildServer.SimpleCommandLineProcessRunner; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil; import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; import java.util.Set; public class CommandUtil { - public static CommandResult runCommand(@NotNull MercurialCommandLine cli, @NotNull CommandSettings settings) throws VcsException { - final String command = removePrivateData(cli.getCommandLineString(), settings.getPrivateData()); - logRunCommand(cli, command, settings); + @NotNull + private static File extractCommandPy(@NotNull final File root, @NotNull final String commandPy) throws VcsException { + try { + final File py = new File(root, commandPy); + FileUtil.copyResource(CommandUtil.class, "/python/" + commandPy, py); + + if (py.length() < 100) throw new IOException("Failed to unpack command resource"); + return py; + } catch (IOException e) { + throw new VcsException("Failed to extract .py file: " + e.getMessage(), e); + } + } + + public static void setupExtensionsFromResource(@NotNull final MercurialCommandLine cli, + @NotNull final File tempDir, + @NotNull final String commandPy) throws VcsException { + final File file = extractCommandPy(tempDir, commandPy); + final String extName = commandPy.replaceAll("[^a-zA-Z]+", ""); + cli.addParameters("--config", "extensions." + extName + "=" + file); + } + + @NotNull + public static CommandResult runWrappedCommand(@NotNull final MercurialCommandLine originalCommandLine, + @NotNull final CommandSettings settings) throws VcsException { + final String realCommand = logRunCommand(originalCommandLine, settings); + + final File tempDir = createTempDir(); + try { + final File commands = writeCommandArguments(originalCommandLine, tempDir); + + final MercurialCommandLine fork = originalCommandLine.forkWithoutCommandlineArguments(); + setupExtensionsFromResource(fork, tempDir, "load-commands-command.py"); + fork.addParameters("CMD", commands.getAbsolutePath()); + + String forkCommand = logRunCommand(fork, settings); + + return runCommandWithName(fork, settings, forkCommand + " \n|| for command: " + realCommand); + } finally { + FileUtil.delete(tempDir); + } + } + + @NotNull + private static File writeCommandArguments(@NotNull MercurialCommandLine originalCommandLine, + @NotNull File tempDir) throws VcsException { + try { + final File commands = new File(tempDir, "command.args"); + FileUtil.writeFile(commands, StringUtil.join("\n", originalCommandLine.getArguments()), "utf-8"); + return commands; + } catch (IOException e) { + throw new VcsException("Failed to generate commands file. " + e.getMessage(), e); + } + + } + + @NotNull + private static File createTempDir() throws VcsException { + try { + return HgFileUtil.createTempDir(); + } catch (IOException e) { + throw new VcsException("Failed to create temp file. " + e.getMessage(), e); + } + } + + @NotNull + public static CommandResult runCommand(@NotNull final MercurialCommandLine cli, + @NotNull final CommandSettings settings) throws VcsException { + return runCommandWithName(cli, settings, logRunCommand(cli, settings)); + } + + private static CommandResult runCommandWithName(MercurialCommandLine cli, CommandSettings settings, String command) throws VcsException { CommandResult res = run(cli, settings.getTimeout(), command, settings.getPrivateData(), settings); if (settings.isCheckForFailure() || settings.isFailWithNonEmptyStderr()) res.checkFailure(settings.isFailWithNonEmptyStderr()); @@ -37,23 +111,34 @@ return res; } + @NotNull private static CommandResult run(@NotNull final MercurialCommandLine cli, final int executionTimeout, @NotNull final String command, @NotNull final Set<String> privateData, @NotNull CommandSettings settings) { final long start = System.currentTimeMillis(); - ExecResult res = SimpleCommandLineProcessRunner.runCommand(cli, null, new SimpleCommandLineProcessRunner.ProcessRunCallbackAdapter() { + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + ProgressParser.ProgressConsumer progressConsumer = settings.getProgressConsumer(); + ByteArrayOutputStream stderrBuffer; + if (progressConsumer != null) { + stderrBuffer = new LineAwareByteArrayOutputStream(Charset.forName("UTF-8"), new ProgressParser(progressConsumer)); + ((LineAwareByteArrayOutputStream) stderrBuffer).setCREndsLine(true); + } else { + stderrBuffer = new ByteArrayOutputStream(); + } + ExecResult res = SimpleCommandLineProcessRunner.runCommandSecure(cli.toGeneralCommandLine(), command, null, new SimpleCommandLineProcessRunner.ProcessRunCallbackAdapter() { @Override public Integer getOutputIdleSecondsTimeout() { return executionTimeout; } + @Override - public void onProcessFinished(Process ps) { + public void onProcessFinished(@NotNull Process ps) { long duration = System.currentTimeMillis() - start; Loggers.VCS.debug("Command " + command + " took " + duration + "ms"); } - }); + }, stdoutBuffer, stderrBuffer); return new CommandResult(Loggers.VCS, command, res, privateData, settings); } @@ -77,6 +162,14 @@ } } + @NotNull + private static String logRunCommand(@NotNull final MercurialCommandLine cli, + @NotNull final CommandSettings settings) { + final String command = removePrivateData(cli.getCommandLineString(), settings.getPrivateData()); + logRunCommand(cli, command, settings); + return command; + } + private static void logCommandOutput(@NotNull String command, @NotNull CommandResult result, @NotNull CommandSettings settings) { int limit = settings.getLogOutputLimit(); if (limit == -1) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandlineViaFileWrapperWeaver.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; +import jetbrains.buildServer.serverSide.TeamCityProperties; +import jetbrains.buildServer.util.StringUtil; +import org.jetbrains.annotations.NotNull; + +/** + * Created 30.05.2014 11:26 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class CommandlineViaFileWrapperWeaver implements CommandSettingsWeaver { + @NotNull + public CommandSettings update(@NotNull HgVcsRoot root, @NotNull CommandSettings settings) { + final String pass = root.getProperty(Constants.HG_COMMANDLINE_VIA_FILE); + return settings.setUseCommandlineViaFileWrapper( + TeamCityProperties.getBoolean("teamcity.mercurial.use.commandline.via.file.wrapper") + || !StringUtil.isEmpty(pass)); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitsAndMountPointsCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommitsAndMountPointsCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,9 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.*; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -58,20 +56,6 @@ } } - @NotNull - private File extractCommandPy(@NotNull final File root) throws VcsException { - try { - final File py = new File(root, "load-substates-command.py"); - - FileUtil.copyResource(getClass(), "/python/load-substates-command.py", py); - - if (py.length() < 100) throw new IOException("Failed to unpack command resource"); - return py; - } catch (IOException e) { - throw new VcsException("Failed to extract .py file: " + e.getMessage(), e); - } - } - public void call(@NotNull final Callback consumer) throws VcsException { final HgVersion hgVersion = myRepo.version().call(); if (!hgVersion.isEqualsOrGreaterThan(REQUIRED_VERSION)) { @@ -81,9 +65,7 @@ final File root = createTmpDir(); try { - final File py = extractCommandPy(root); - - callImpl(root, py, consumer); + callImpl(root, consumer); } finally { FileUtil.delete(root); } @@ -106,12 +88,12 @@ } private void callImpl(@NotNull final File root, - @NotNull final File commandPy, @NotNull final Callback consumer) throws VcsException { final MercurialCommandLine cli = createCommandLine(); cli.addParameter("--debug"); - cli.addParameter("--config"); - cli.addParameter("extensions.logextcj=" + commandPy); + + setupExtensionsFromResource(cli, root, "load-substates-command.py"); + cli.addParameter("load-substates"); cli.addParameter(new File(root, "result").getPath());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ExtensionsWeaver.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; +import jetbrains.buildServer.util.StringUtil; +import org.jetbrains.annotations.NotNull; + +/** + * Created 25.02.14 13:03 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class ExtensionsWeaver implements CommandSettingsWeaver { + @NotNull + public CommandSettings update(@NotNull HgVcsRoot root, @NotNull CommandSettings settings) { + String extensions = root.getProperty(Constants.HG_EXTENSIONS); + if (StringUtil.isEmpty(extensions)) return settings; + + for (String _line : extensions.split("[\\r\\n]+")) { + String line = _line.trim(); + if (line.isEmpty()) continue; + + if (!line.contains("=")) line += "="; + + settings = settings.withGlobalArguments("--config", "extensions." + line); + } + + return settings; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java Wed Jun 18 12:14:56 2014 +0200 @@ -46,6 +46,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()); @@ -65,6 +66,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) { @@ -174,7 +184,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 + } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LoadDagCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LoadDagCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -17,6 +17,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -27,14 +28,14 @@ public class LoadDagCommand extends VcsRootCommand { - private final File myDagLogTemplate; + private final MercurialTemplate myDagLogTemplate; private int myMaxDagNodesCount; public LoadDagCommand(@NotNull CommandSettings commandSettings, @NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings, - @NotNull File dagLogTemplate) { + @NotNull MercurialTemplate dagLogTemplate) { super(commandSettings, hgPath, workingDir, authSettings); myDagLogTemplate = dagLogTemplate; } @@ -45,31 +46,42 @@ @NotNull public List<Pair<String, String>> call() throws VcsException { - List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>(); - MercurialCommandLine cli = createCommandLine(); - cli.addParameter("log"); - cli.addParameter("--style=" + myDagLogTemplate.getAbsolutePath()); - if (myMaxDagNodesCount > 0) - cli.addParameters("--limit", String.valueOf(myMaxDagNodesCount)); - CommandResult res = runCommand(cli); - String output = res.getStdout(); - String fromNode = null; - for (String line : StringUtil.splitByLines(output)) { - String[] revs = line.split(" "); - if (revs.length == 0) - continue; - if (fromNode != null) { - edges.add(Pair.create(fromNode, revs[0])); - fromNode = null; + return myDagLogTemplate.withTemplate(new MercurialTemplate.WithTemplate<List<Pair<String, String>>>() { + @NotNull + public List<Pair<String, String>> action(@NotNull File template) throws VcsException { + final List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>(); + final MercurialCommandLine cli = createCommandLine(); + cli.addParameter("log"); + cli.addParameter("--style=" + template.getAbsolutePath()); + if (myMaxDagNodesCount > 0) { + cli.addParameters("--limit", String.valueOf(myMaxDagNodesCount)); + } + + final CommandResult res = runCommand(cli); + + + final String output = res.getStdout(); + String fromNode = null; + for (String line : StringUtil.splitByLines(output)) { + final String[] revs = line.split(" "); + if (revs.length == 0) continue; + + if (fromNode != null) { + edges.add(Pair.create(fromNode, revs[0])); + fromNode = null; + } + + if (revs.length == 1) { + fromNode = revs[0]; + } else { + edges.add(Pair.create(revs[0], revs[1])); + if (revs.length == 3) { + edges.add(Pair.create(revs[0], revs[2])); + } + } + } + return edges; } - if (revs.length == 1) { - fromNode = revs[0]; - } else { - edges.add(Pair.create(revs[0], revs[1])); - if (revs.length == 3) - edges.add(Pair.create(revs[0], revs[2])); - } - } - return edges; + }); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,6 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -44,7 +45,7 @@ private String myBranchName; private boolean myCalculateParents = true; private String myRevsets; - private File myTemplate; + private MercurialTemplate myTemplate; private List<String> myFiles = new ArrayList<String>(); public LogCommand(@NotNull CommandSettings commandSettings, @@ -54,7 +55,7 @@ super(commandSettings, hgPath, workingDir, authSettings); } - public LogCommand withTemplate(@NotNull File template) { + public LogCommand withTemplate(@NotNull MercurialTemplate template) { myTemplate = template; return this; } @@ -104,49 +105,57 @@ return this; } + @NotNull public List<ChangeSet> call() throws VcsException { - MercurialCommandLine cli = createCommandLine(); - cli.setCharset(Charset.forName("UTF-8")); - cli.addParameters("--encoding", "UTF-8"); - cli.addParameter("log"); - cli.addParameter("-v"); - if (myTemplate != null) - cli.addParameter("--style=" + myTemplate.getAbsolutePath()); - if (myBranchName != null) { - cli.addParameter("-b"); - cli.addParameter(myBranchName); - } - cli.addParameter("-r"); - if (myRevsets != null) { - cli.addParameter(myRevsets); - } else { - String from = myFromId != null ? myFromId : "0"; - String to = myToId != null ? myToId : "tip"; - cli.addParameter(from + ":" + to); - } - if (myLimit != null) { - cli.addParameter("--limit"); - cli.addParameter(myLimit.toString()); - } + return myTemplate.withTemplate(new MercurialTemplate.WithTemplate<List<ChangeSet>>() { + @NotNull + public List<ChangeSet> action(@NotNull File template) throws VcsException { + final MercurialCommandLine cli = createCommandLine(); + cli.setCharset(Charset.forName("UTF-8")); + cli.addParameters("--encoding", "UTF-8"); + cli.addParameter("log"); + cli.addParameter("-v"); + if (myTemplate != null) { + cli.addParameter("--style=" + template.getAbsolutePath()); + } - cli.addParameters(myFiles); + if (myBranchName != null) { + cli.addParameter("-b"); + cli.addParameter(myBranchName); + } + cli.addParameter("-r"); + if (myRevsets != null) { + cli.addParameter(myRevsets); + } else { + String from = myFromId != null ? myFromId : "0"; + String to = myToId != null ? myToId : "tip"; + cli.addParameter(from + ":" + to); + } + if (myLimit != null) { + cli.addParameter("--limit"); + cli.addParameter(myLimit.toString()); + } - CommandResult res = runCommand(cli); - String output = res.getStdout(); - try { - List<ChangeSet> changes = parseChangeSetsXml(output); - if (myCalculateParents) - assignTrivialParents(changes); - return changes; - } catch (Exception e) { - int limit = myCommandSettings.getLogOutputLimit(); - if (limit == -1) { - LOG.error("Error while parsing log output:\n" + output, e); - } else { - LOG.error("Error while parsing log output:\n" + StringUtil.truncateStringValueWithDotsAtEnd(output, limit), e); + cli.addParameters(myFiles); + + final CommandResult res = runCommand(cli); + final String output = res.getStdout(); + try { + List<ChangeSet> changes = parseChangeSetsXml(output); + if (myCalculateParents) + assignTrivialParents(changes); + return changes; + } catch (Exception e) { + int limit = myCommandSettings.getLogOutputLimit(); + if (limit == -1) { + LOG.error("Error while parsing log output:\n" + output, e); + } else { + LOG.error("Error while parsing log output:\n" + StringUtil.truncateStringValueWithDotsAtEnd(output, limit), e); + } + throw new VcsException("Error while parsing log output, see teamcity-vcs.log for details", e); + } } - throw new VcsException("Error while parsing log output, see teamcity-vcs.log for details", e); - } + }); } private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws SAXException, ParserConfigurationException, IOException {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MercurialCommandLine.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MercurialCommandLine.java Wed Jun 18 12:14:56 2014 +0200 @@ -22,49 +22,94 @@ import org.jetbrains.annotations.NotNull; import java.nio.charset.Charset; -import java.util.Collections; -import java.util.Set; +import java.util.*; -public class MercurialCommandLine extends GeneralCommandLine { +public class MercurialCommandLine { + private String myExePath; + private final List<String> myArguments = new ArrayList<String>(); + private final Map<String, String> myEnvPatch = new TreeMap<String, String>(); private String myWorkingDirectory; private final Set<String> myPrivateData; private Charset myCharset; - public MercurialCommandLine() { - this(Collections.<String>emptySet()); - } - - public MercurialCommandLine(@NotNull Set<String> privateData) { + public MercurialCommandLine(@NotNull final Set<String> privateData) { myPrivateData = privateData; } - @Override - public String getCommandLineString() { - String original = super.getCommandLineString(); - return CommandUtil.removePrivateData(original, myPrivateData); + @NotNull + public MercurialCommandLine forkWithoutCommandlineArguments() { + final MercurialCommandLine fork = fork(); + fork.myArguments.clear(); + return fork; } - @Override - public void addParameter(@NotNull String parameter) { - String escaped = escape(parameter); - super.addParameter(escaped); + @NotNull + public MercurialCommandLine fork() { + final MercurialCommandLine line = new MercurialCommandLine(myPrivateData); + line.myExePath = myExePath; + line.myArguments.addAll(myArguments); + line.myEnvPatch.putAll(myEnvPatch); + line.myWorkingDirectory = myWorkingDirectory; + line.myCharset = myCharset; + return line; } - @Override + public int getCommandLineLength() { + return getCommandLineString().length() + 42; + } + + @NotNull + public String getCommandLineString() { + return toGeneralCommandLine().getCommandLineString(); + } + + public void setExePath(@NotNull final String hgPath) { + myExePath = hgPath; + } + + @NotNull + public List<String> getArguments() { + return new ArrayList<String>(myArguments); + } + + public void addParameter(@NotNull final String parameter) { + String escaped = escape(parameter); + myArguments.add(escaped); + } + + public void addParameters(@NotNull final Collection<String> argz) { + for (String s : argz) { + addParameter(s); + } + } + + public void addParameters(@NotNull final String... argz) { + for (String s : argz) { + addParameter(s); + } + } + + public void addParameters(@NotNull final String a, @NotNull final String b) { + addParameter(a); + addParameter(b); + } + + public void setEnvParams(@NotNull final Map<String, String> hgEnv) { + myEnvPatch.clear(); + myEnvPatch.putAll(hgEnv); + } + + public void addEnvParam(@NotNull final String key, @NotNull final String value) { + myEnvPatch.put(key, value); + } + public void setCharset(@NotNull Charset charset) { myCharset = charset; } - @Override - public Charset getCharset() { - return myCharset != null ? myCharset : super.getCharset(); - } - - @Override public void setWorkDirectory(@NonNls String path) { myWorkingDirectory = path; - super.setWorkDirectory(path); } public String getWorkingDirectory() { @@ -74,4 +119,45 @@ private String escape(String s) { return StringUtil.escapeQuotesIfWindows(s); } + + @NotNull + public GeneralCommandLine toGeneralCommandLine() { + final Charset charset = myCharset; + final GeneralCommandLine cmd = new GeneralCommandLine() { + @Override + public String getCommandLineParams() { + return CommandUtil.removePrivateData(super.getCommandLineParams(), myPrivateData); + } + + @Override + public String getCommandLineString() { + return CommandUtil.removePrivateData(super.getCommandLineString(), myPrivateData); + } + + @Override + public Charset getCharset() { + if (charset != null) return charset; + return super.getCharset(); + } + }; + + if (myExePath != null) { + cmd.setExePath(myExePath); + } + + if (myWorkingDirectory != null) { + cmd.setWorkDirectory(myWorkingDirectory); + } + + for (String argument : myArguments) { + cmd.addParameter(argument); + } + + if (!myEnvPatch.isEmpty()) { + cmd.setPassParentEnvs(true); + cmd.setEnvParams(new TreeMap<String, String>(myEnvPatch)); + } + + return cmd; + } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ParentsCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ParentsCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,6 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -47,6 +48,8 @@ CommandResult res = runCommand(cli); List<String> parentRevisions = new ArrayList<String>(); for (String line : res.getStdout().split("\n")) { + if (StringUtil.isEmpty(line)) + continue; parentRevisions.add(new ChangeSet(line).getId()); } return parentRevisions;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ProgressParser.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,61 @@ +/* + * 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.LineAwareByteArrayOutputStream; +import org.jetbrains.annotations.NotNull; + +public class ProgressParser implements LineAwareByteArrayOutputStream.LineListener { + + private final ProgressConsumer myConsumer; + + public ProgressParser(@NotNull ProgressConsumer consumer) { + myConsumer = consumer; + } + + public interface ProgressConsumer { + void consume(float progress, @NotNull String stage); + } + + public void newLineDetected(@NotNull String line) { + String trimmed = line.trim(); + if (trimmed.isEmpty()) + return; + + int spaceIdx = trimmed.indexOf(' '); + if (spaceIdx == -1) { + myConsumer.consume(-1, trimmed); + return; + } + + String stage = trimmed.substring(0, spaceIdx); + String progress = trimmed.substring(spaceIdx).trim(); + int ratioIdx = progress.indexOf('/'); + if (ratioIdx == -1 || ratioIdx == trimmed.length() - 1) { + myConsumer.consume(-1, stage); + return; + } + + try { + int nom = Integer.parseInt(progress.substring(0, ratioIdx)); + int denom = Integer.parseInt(progress.substring(ratioIdx+1)); + myConsumer.consume(nom * 1.0f / denom, stage); + } catch (NumberFormatException e) { + myConsumer.consume(-1, stage); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -32,6 +32,7 @@ private String myPullUrl; private int myTimeout; private boolean myTraceback; + private ProgressParser.ProgressConsumer myProgressConsumer; public PullCommand(@NotNull CommandSettings commandSettings, @NotNull String hgPath, @@ -60,15 +61,30 @@ return this; } + public PullCommand withProgressConsumer(ProgressParser.ProgressConsumer progressConsumer) { + myProgressConsumer = progressConsumer; + return this; + } + public void call() throws VcsException { ensureRepositoryIsNotLocked(); MercurialCommandLine cli = createCommandLine(); cli.addParameter("pull"); if (myTraceback) cli.addParameter("--traceback"); - String pullUrl = myAuthSettings != null ? myAuthSettings.getRepositoryUrlWithCredentials(myPullUrl) : myPullUrl; + + CommandSettings settings = myCommandSettings.setTimeout(myTimeout); + if (myProgressConsumer != null) { + cli.addParameters("--config", "extensions.progress="); + cli.addParameters("--config", "progress.format=topic number"); + cli.addParameters("--config", "progress.delay=0"); + cli.addParameters("--config", "progress.assume-tty=True"); + settings.setProgressConsumer(myProgressConsumer); + } + + String pullUrl = myAuthSettings.getRepositoryUrlWithCredentials(myPullUrl); cli.addParameter(pullUrl); - runCommand(cli, myCommandSettings.setTimeout(myTimeout)); + runCommand(cli, settings); } private void ensureRepositoryIsNotLocked() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PurgeCommand.java Wed Jun 18 12:14:56 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-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -37,21 +37,25 @@ super(commandSettings, hgPath, workingDir, authSettings); } + @NotNull public StatusCommand fromRevision(@NotNull ChangeSet fromCset) { myFromId = fromCset.getId(); return this; } + @NotNull public StatusCommand fromRevision(@NotNull String fromRevision) { myFromId = new ChangeSet(fromRevision).getId(); return this; } + @NotNull public StatusCommand toRevision(@NotNull ChangeSet toCset) { myToId = toCset.getId(); return this; } + @NotNull public StatusCommand toRevision(@NotNull String toRevision) { myToId = new ChangeSet(toRevision).getId(); return this; @@ -61,6 +65,7 @@ * Adds option -A (--all) * @return self */ + @NotNull public StatusCommand showAllFiles() { myShowAllFiles = true; return this; @@ -70,32 +75,43 @@ * Adds option -n (--no-status) * @return self */ + @NotNull public StatusCommand hideStatus() { myHideStatus = true; return this; } + @NotNull public List<FileStatus> call() throws VcsException { - MercurialCommandLine cli = createCommandLine(); + final MercurialCommandLine cli = createCommandLine(); cli.addParameter("status"); - if (myShowAllFiles) + + if (myShowAllFiles) { cli.addParameter("-A"); - if (myHideStatus) + } + + if (myHideStatus) { cli.addParameter("-n"); + } cli.addParameter("--rev"); + String from = myFromId; if (from == null) from = "0"; + String to = myToId; - if (to == null) + if (to == null) { to = "0"; + } cli.addParameter(from + ":" + to); - CommandResult res = runCommand(cli); + + final CommandResult res = runCommand(cli); return parseFiles(res.getStdout()); } - private List<FileStatus> parseFiles(@NotNull String stdout) { - List<FileStatus> result = new ArrayList<FileStatus>(); + @NotNull + private List<FileStatus> parseFiles(@NotNull final String stdout) { + final List<FileStatus> result = new ArrayList<FileStatus>(); String[] lines = stdout.split("\n"); for (String line : lines) { if (isEmpty(line)) @@ -109,12 +125,12 @@ } @NotNull - private FileStatus parseLine(@NotNull String line) { - if (myHideStatus) - return new FileStatus(Status.UNKNOWN, line); - char modifier = line.charAt(0); - String path = line.substring(2); - Status status = Status.makeStatus(modifier); + private FileStatus parseLine(@NotNull final String line) { + if (myHideStatus) return new FileStatus(Status.UNKNOWN, line); + + final char modifier = line.charAt(0); + final String path = line.substring(2); + final Status status = Status.makeStatus(modifier); return new FileStatus(status, path); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -15,7 +15,6 @@ */ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import com.intellij.execution.configurations.GeneralCommandLine; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,15 +51,12 @@ public void call() throws VcsException { MercurialCommandLine cli = createCommandLine(); cli.addParameter("tag"); - setUser(cli); + if (myUsername != null) { + cli.addParameters("--user", myUsername); + } cli.addParameter("-r"); cli.addParameter(myRevId); cli.addParameter(myTag); runCommand(cli); } - - private void setUser(GeneralCommandLine cli) { - if (myUsername != null) - cli.addParameters("--user", myUsername); - } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,7 +16,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -40,12 +39,7 @@ myAuthSettings = authSettings; } - - protected CommandResult runCommand(@NotNull MercurialCommandLine cli, @NotNull CommandSettings s) throws VcsException { - s.setPrivateData(getPrivateData()); - return CommandUtil.runCommand(cli, s); - } - + @NotNull protected Set<String> getPrivateData() { String password = myAuthSettings.getPassword(); if (password == null)
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,15 +16,12 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import com.intellij.execution.configurations.GeneralCommandLine; import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ParseHgVersionException; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.HashMap; -import java.util.Map; /** * @author dmitry.neverov @@ -38,24 +35,16 @@ } + @NotNull public HgVersion call() throws VcsException, ParseHgVersionException { MercurialCommandLine cli = createCommandLine(); cli.addParameter("version"); cli.addParameter("--quiet"); - setDefaultLocale(cli); - CommandResult result = CommandUtil.runCommand(cli, myCommandSettings); + cli.addEnvParam("LANG", "en_US"); + cli.addEnvParam("LANGUAGE", "en_US"); + cli.addEnvParam("LC_MESSAGE", "en_US"); + + CommandResult result = runCommand(cli, myCommandSettings); return HgVersion.parse(result.getStdout()); } - - - private void setDefaultLocale(GeneralCommandLine commandLine) { - Map<String, String> env = commandLine.getEnvParams(); - if (env == null) - env = new HashMap<String, String>(); - env.put("LANG", "en_US"); - env.put("LANGUAGE", "en_US"); - env.put("LC_MESSAGE", "en_US"); - commandLine.setEnvParams(env); - } - }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/python/load-commands-command.py Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,56 @@ +#!/usr/bin/env python +## +## Copyright 2000-2014 JetBrains +## +## 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. +## +## +## http://www.gnu.org/licenses/gpl-faq.html#GPLModuleLicense +## http://www.gnu.org/licenses/license-list.html#apache2 +## http://en.wikipedia.org/wiki/Apache_License#GPL_compatibility +## +## +""" +load-commands-command +""" + +import codecs +from mercurial import dispatch +from mercurial import commands + +def loadArguments(ui, params_file): + file_commands = [] + with codecs.open(params_file, "r", "utf-8") as f: + for _line in f: + line = _line.strip() + if len(line) <= 0: + continue + + file_commands.append(str(line)) + return file_commands + + +def load_commands_command(ui, params_file, *params): + command_arguments = loadArguments(ui, params_file) + return dispatch.dispatch(dispatch.request(command_arguments)) + +#so here goes command registration and options +cmdtable = { + "CMD": (load_commands_command, [], " OUTPUT_FILE") +} + +commands.norepo += " CMD" + +testedwith = '2.2.2' +buglink = "@jonnyzzz" +
--- a/mercurial-server-tc/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSubrepoUsageStatistics.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server-tc/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSubrepoUsageStatistics.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,29 +16,30 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import jetbrains.buildServer.usageStatistics.impl.providers.BaseVCSFeatureUsageStatisticsProvider; import jetbrains.buildServer.vcs.SVcsRoot; import jetbrains.buildServer.vcs.VcsManager; import org.jetbrains.annotations.NotNull; -public class MercurialSubrepoUsageStatistics /*extends BaseVCSFeatureUsageStatisticsProvider*/ { +public class MercurialSubrepoUsageStatistics extends BaseVCSFeatureUsageStatisticsProvider { public MercurialSubrepoUsageStatistics(@NotNull VcsManager vcsManager) { -// super(vcsManager); + super(vcsManager); } @NotNull -// @Override + @Override protected String getFeatureName() { return "subRepoSupport-mercurial"; } @NotNull -// @Override + @Override protected String getFeatureDisplayName() { return "Mercurial VCS roots with subrepo support enabled"; } -// @Override + @Override protected boolean hasFeature(@NotNull SVcsRoot root) { return Boolean.parseBoolean(root.getProperty(Constants.DETECT_SUBREPO_CHANGES)); }
--- a/mercurial-server/resources/buildServerResources/mercurialSettings.jsp Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/resources/buildServerResources/mercurialSettings.jsp Wed Jun 18 12:14:56 2014 +0200 @@ -39,7 +39,7 @@ <th><label for="branchName">Default branch: </label></th> <td> <props:textProperty name="branchName" className="longField"/> - <div class="smallNote" style="margin: 0;">Branch to be used if no branch from Branch Specification is set</div> + <div class="smallNote" style="margin: 0;">The main branch to be monitored</div> </td> </tr> <bs:branchSpecTableRow/> @@ -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-server/src/META-INF/build-server-plugin-mercurial.xml Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Wed Jun 18 12:14:56 2014 +0200 @@ -31,4 +31,10 @@ <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialCommitsInfoBuilderSupport"/> <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialModificationInfoBuilder"/> + + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver"/> + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver"/> + + <bean class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialFetchService"/> </beans>
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java Wed Jun 18 12:14:56 2014 +0200 @@ -47,8 +47,8 @@ public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException { - HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot); - HgRepo repo = createRepo(root); + final HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot); + final HgRepo repo = createRepo(root); try { repo.id().repository(root.getRepository()) .withAuthSettings(root.getAuthSettings()) @@ -64,8 +64,9 @@ return new VcsException("Cannot find mercurial executable at path '" + myHgPathProvider.getHgPath(root) + "'", e); } - private ServerHgRepo createRepo(HgVcsRoot root) throws VcsException { - return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); + @NotNull + private HgRepo createRepo(HgVcsRoot root) throws VcsException { + return myRepoFactory.createRepo(root, getWorkingDir(root)); } private File getWorkingDir(HgVcsRoot root) {
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCollectChangesPolicy.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCollectChangesPolicy.java Wed Jun 18 12:14:56 2014 +0200 @@ -61,11 +61,12 @@ @NotNull public RepositoryStateData getCurrentState(@NotNull VcsRoot root) throws VcsException { final HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); - Map<String, String> revisions = myVcs.syncRepository(hgRoot, new VcsCallable<Map<String, String>>() { + VcsCallable<Map<String, String>> cmd = new VcsCallable<Map<String, String>>() { public Map<String, String> call() throws VcsException { return getHeads(hgRoot); } - }); + }; + Map<String, String> revisions = myVcs.syncRepository(hgRoot, new SyncSettings<Map<String, String>>(cmd)); String defaultBranchName = hgRoot.getBranchName(); if (revisions.get(defaultBranchName) == null) { throw new VcsException("Cannot find revision of the default branch '" +
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCommitsInfoBuilderSupport.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialCommitsInfoBuilderSupport.java Wed Jun 18 12:14:56 2014 +0200 @@ -59,11 +59,12 @@ final HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); final ServerHgRepo repo = mySupport.createRepo(hgRoot); - final MultiMapToList<String, String> heads = mySupport.syncRepository(hgRoot, new VcsCallable<MultiMapToList<String, String>>() { + VcsCallable<MultiMapToList<String, String>> cmd = new VcsCallable<MultiMapToList<String, String>>() { public MultiMapToList<String, String> call() throws VcsException { return commitToBranchs(mySupport.getCollectChangesPolicy().getHeads(hgRoot)); } - }); + }; + final MultiMapToList<String, String> heads = mySupport.syncRepository(hgRoot, new SyncSettings<MultiMapToList<String, String>>(cmd)); repo.logSubstates().call(new CommitsAndMountPointsCommand.Callback() { private final MercurialCommitsInfoBuilderStates subs = new MercurialCommitsInfoBuilderStates();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialFetchService.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,56 @@ +/* + * 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.ProgressParser; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.FetchService; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +public class MercurialFetchService implements FetchService, MercurialServerExtension { + + private final MercurialVcsSupport myVcs; + private final HgVcsRootFactory myHgVcsRootFactory; + + public MercurialFetchService(@NotNull MercurialVcsSupport vcs, + @NotNull HgVcsRootFactory hgVcsRootFactory) { + myVcs = vcs; + myHgVcsRootFactory = hgVcsRootFactory; + vcs.addExtension(this); + } + + public void fetchRepository(@NotNull VcsRoot root, + @NotNull CheckoutRules rules, + @NotNull FetchRepositoryCallback callback) throws VcsException { + SyncSettings<Void> settings = new SyncSettings<Void>(VcsCallable.NO_OP); + settings.setProgressConsumer(new FetchProgressConsumer(callback)); + myVcs.syncRepository(myHgVcsRootFactory.createHgRoot(root)); + } + + private class FetchProgressConsumer implements ProgressParser.ProgressConsumer { + private final FetchRepositoryCallback myCallback; + private FetchProgressConsumer(@NotNull FetchRepositoryCallback callback) { + myCallback = callback; + } + + public void consume(float progress, @NotNull String stage) { + myCallback.update(progress, stage); + } + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Wed Jun 18 12:14:56 2014 +0200 @@ -38,10 +38,7 @@ 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.io.*; import java.util.*; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir; @@ -123,7 +120,7 @@ @NotNull public byte[] getContent(@NotNull final String filePath, @NotNull final VcsRoot vcsRoot, @NotNull final String version) throws VcsException { ChangeSet cset = new ChangeSet(version); - HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot); + HgVcsRoot root = getHgRoot(vcsRoot); syncRepository(root, cset); HgRepo repo = createRepo(root); File parentDir = repo.cat().files(filePath).atRevision(cset).call(); @@ -138,6 +135,11 @@ } @NotNull + public HgVcsRoot getHgRoot(@NotNull final VcsRoot vcsRoot) throws VcsException { + return myHgVcsRootFactory.createHgRoot(vcsRoot); + } + + @NotNull public String getName() { return Constants.VCS_NAME; } @@ -174,11 +176,12 @@ } @NotNull - public String describeVcsRoot(final VcsRoot vcsRoot) { + public String describeVcsRoot(@NotNull final VcsRoot vcsRoot) { return "mercurial: " + vcsRoot.getProperty(Constants.REPOSITORY_PROP); } @Override + @NotNull public TestConnectionSupport getTestConnectionSupport() { return myTestConnection; } @@ -218,30 +221,37 @@ @NotNull final ChangeSet toVer, @NotNull final PatchBuilder builder, @NotNull final CheckoutRules checkoutRules) throws VcsException, IOException { - HgRepo repo = createRepo(root); - List<FileStatus> modifiedFiles = repo.status().fromRevision(fromVer).toRevision(toVer).call(); - List<String> notDeletedFiles = new ArrayList<String>(); + final HgRepo repo = createRepo(root); + final List<FileStatus> modifiedFiles = repo.status().fromRevision(fromVer).toRevision(toVer).call(); + final List<String> notDeletedFiles = new ArrayList<String>(); for (FileStatus f: modifiedFiles) { if (f.getStatus() != Status.REMOVED) { notDeletedFiles.add(f.getPath()); } } - File parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call(); + File parentDir = null; try { - for (FileStatus f: modifiedFiles) { - String mappedPath = checkoutRules.map(f.getPath()); - if (mappedPath == null) continue; // skip - final File virtualFile = new File(mappedPath); - if (f.getStatus() == Status.REMOVED) { - builder.deleteFile(virtualFile, true); - } else { - File realFile = new File(parentDir, f.getPath()); - FileInputStream is = new FileInputStream(realFile); - try { - builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length()); - } finally { - is.close(); + if (root.useArchiveForPatch()) { + parentDir = HgFileUtil.createTempDir(); + final File archFile = new File(parentDir, "arch.tar"); + buildIncrementalPatchWithArchive(builder, repo, toVer, checkoutRules, modifiedFiles, notDeletedFiles, archFile); + } else { + parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call(); + for (FileStatus f: modifiedFiles) { + String mappedPath = checkoutRules.map(f.getPath()); + if (mappedPath == null) continue; // skip + final File virtualFile = new File(mappedPath); + if (f.getStatus() == Status.REMOVED) { + builder.deleteFile(virtualFile, true); + } else { + final File realFile = new File(parentDir, f.getPath()); + final InputStream is = new BufferedInputStream(new FileInputStream(realFile)); + try { + builder.changeOrCreateBinaryFile(virtualFile, null, is, realFile.length()); + } finally { + FileUtil.close(is); + } } } } @@ -253,7 +263,50 @@ builder.deleteDirectory(new File(""), true);//clean patch buildFullPatch(root, toVer, builder, checkoutRules); } finally { - deleteDir(parentDir, Loggers.VCS); + if (parentDir != null) + deleteDir(parentDir, Loggers.VCS); + } + } + + private void buildIncrementalPatchWithArchive(@NotNull final PatchBuilder builder, + @NotNull final HgRepo repo, + @NotNull final ChangeSet toVer, + @NotNull final CheckoutRules checkoutRules, + @NotNull final List<FileStatus> modifiedFiles, + @NotNull final List<String> notDeletedFiles, + @NotNull final File archiveFile) throws VcsException, IOException { + ArchiveCommand archive = repo.archive().revision(toVer).type("tar").destination(archiveFile); + int i = 0; + while (i < notDeletedFiles.size()) { + String mappedPath = checkoutRules.map(notDeletedFiles.get(i)); + if (mappedPath == null) { + i++; + continue; + } + if (archive.addIncludeRule(notDeletedFiles.get(i))) { + i++; + continue; + } + //archive command is full, call it + archive.call(); + buildPatchFromArchive(builder, archiveFile, checkoutRules, new ExcludeHgArchival()); + FileUtil.delete(archiveFile); + archive = repo.archive().revision(toVer).type("tar").destination(archiveFile); + } + if (!notDeletedFiles.isEmpty()) { + archive.call(); + buildPatchFromArchive(builder, archiveFile, checkoutRules, new ExcludeHgArchival()); + FileUtil.delete(archiveFile); + } + + //delete removed files + for (FileStatus f: modifiedFiles) { + if (f.getStatus() != Status.REMOVED) continue; //other files processed below + + final String mappedPath = checkoutRules.map(f.getPath()); + if (mappedPath == null) continue; // skip + + builder.deleteFile(new File(mappedPath), true); } } @@ -315,15 +368,15 @@ @NotNull final ChangeSet toVer, @NotNull final PatchBuilder builder, @NotNull final CheckoutRules checkoutRules) throws IOException, VcsException { - File tempDir = HgFileUtil.createTempDir(); + final File tempDir = HgFileUtil.createTempDir(); try { - HgRepo repo = createRepo(root); + final HgRepo repo = createRepo(root); if (root.includeSubreposInPatch()) { - Map<String, SubRepo> subrepos = repo.getSubrepositories(toVer); + final Map<String, SubRepo> subrepos = repo.getSubrepositories(toVer); if (!subrepos.isEmpty()) { Loggers.VCS.debug("Repository '" + root.getRepository() + "' has subrepos at revision " + toVer.getId() + ", use 'hg clone' to build clean patch"); - File mirrorDir = getWorkingDir(root); - HgRepo cloneOfTheMirror = createRepo(root, tempDir); + final File mirrorDir = getWorkingDir(root); + final HgRepo cloneOfTheMirror = createRepo(root, tempDir); cloneOfTheMirror.doClone().fromRepository(mirrorDir) .setUpdateWorkingDir(false) .setUsePullProtocol(false) @@ -338,11 +391,7 @@ if (root.useArchiveForPatch()) { File archive = new File(tempDir, "arch.tar"); repo.archive().revision(toVer).type("tar").destination(archive).call(); - buildPatchFromArchive(builder, archive, checkoutRules, new FileFilter() { - public boolean accept(File f) { - return !f.getName().equals(".hg_archival.txt"); - } - }); + buildPatchFromArchive(builder, archive, checkoutRules, new ExcludeHgArchival()); } else { repo.archive().revision(toVer).destination(tempDir).call(); buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter); @@ -351,13 +400,9 @@ } else { Loggers.VCS.debug("Subrepos disabled in VCS root, use 'hg archive' to build clean patch"); if (root.useArchiveForPatch()) { - File archive = new File(tempDir, "arch.tar"); + final File archive = new File(tempDir, "arch.tar"); repo.archive().revision(toVer).type("tar").destination(archive).call(); - buildPatchFromArchive(builder, archive, checkoutRules, new FileFilter() { - public boolean accept(File f) { - return !f.getName().equals(".hg_archival.txt"); - } - }); + buildPatchFromArchive(builder, archive, checkoutRules, new ExcludeHgArchival()); } else { repo.archive().revision(toVer).destination(tempDir).call(); buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter); @@ -401,37 +446,48 @@ } } - private void buildPatchFromArchive(@NotNull PatchBuilder builder, - @NotNull File archive, - @NotNull CheckoutRules checkoutRules, - @NotNull FileFilter filter) throws IOException { - FileInputStream fis = new FileInputStream(archive); + private void buildPatchFromArchive(@NotNull final PatchBuilder builder, + @NotNull final File archive, + @NotNull final CheckoutRules checkoutRules, + @NotNull final FileFilter filter) throws IOException { + InputStream fis = null; ArchiveInputStream is = null; try { + fis = new BufferedInputStream(new FileInputStream(archive)); is = new TarArchiveInputStream(fis); - ArchiveEntry entry = null; + + ArchiveEntry entry; while ((entry = is.getNextEntry()) != null) { + if (entry.isDirectory()) continue; + String fileName = entry.getName(); - if (fileName.startsWith("arch/")) - fileName = fileName.substring(5); - if (!filter.accept(new File(fileName))) - continue; - String mappedFile = checkoutRules.map(fileName); - if (!StringUtil.isEmpty(mappedFile)) + //TODO: does it work if I have arch/ in my repo? + if (fileName.startsWith("arch/")) fileName = fileName.substring(5); + + if (!filter.accept(new File(fileName))) continue; + + final String mappedFile = checkoutRules.map(fileName); + if (!StringUtil.isEmpty(mappedFile)) { builder.createBinaryFile(new File(mappedFile), null, is, entry.getSize()); + } } } finally { - fis.close(); - if (is != null) - is.close(); + FileUtil.closeAll(is, fis); } } - private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { + private void buildPatchFromDirectory(@NotNull final PatchBuilder builder, + @NotNull final File repRoot, + @NotNull final CheckoutRules checkoutRules, + @NotNull final FileFilter filter) throws IOException { buildPatchFromDirectory(repRoot, builder, repRoot, checkoutRules, filter); } - private void buildPatchFromDirectory(File curDir, final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { + private void buildPatchFromDirectory(@NotNull final File curDir, + @NotNull final PatchBuilder builder, + @NotNull final File repRoot, + @NotNull final CheckoutRules checkoutRules, + @NotNull final FileFilter filter) throws IOException { File[] files = curDir.listFiles(filter); if (files != null) { for (File realFile: files) { @@ -490,21 +546,21 @@ } public void syncRepository(@NotNull final VcsRoot root) throws VcsException { - syncRepository(myHgVcsRootFactory.createHgRoot(root)); + syncRepository(getHgRoot(root)); } public void syncRepository(@NotNull final HgVcsRoot root) throws VcsException { - syncRepository(root, VcsCallable.NO_OP); + syncRepository(root, new SyncSettings<Void>(VcsCallable.NO_OP)); } - public <T> T syncRepository(@NotNull HgVcsRoot root, @NotNull VcsCallable<T> cmd) throws VcsException { + public <T> T syncRepository(@NotNull HgVcsRoot root, @NotNull SyncSettings<T> settings) throws VcsException { boolean customWorkingDir = root.getCustomWorkingDir() != null; File workingDir = getWorkingDir(root); int attemptsLeft = 3; VcsException lastError = null; while (attemptsLeft-- > 0) { try { - return syncRepositoryOnce(root, cmd, workingDir); + return syncRepositoryOnce(root, settings, workingDir); } catch (UnrelatedRepositoryException e) { if (customWorkingDir) throw new VcsException(e.getMessage() + ". VCS root uses a custom clone dir, manual recovery is required.", e); @@ -525,7 +581,7 @@ } - private <T> T syncRepositoryOnce(@NotNull HgVcsRoot root, @NotNull VcsCallable<T> cmd, @NotNull File workingDir) throws VcsException { + private <T> T syncRepositoryOnce(@NotNull HgVcsRoot root, @NotNull SyncSettings<T> settings, @NotNull File workingDir) throws VcsException { lockWorkDir(workingDir); HgRepo repo = createRepo(root); try { @@ -533,15 +589,17 @@ resetBookmarks(repo); repo.pull().fromRepository(root.getRepository()) .withTimeout(myConfig.getPullTimeout()) + .withProgressConsumer(settings.getProgressConsumer()) .call(); } else { repo.doClone().fromRepository(root.getRepository()) .setUpdateWorkingDir(false) .useUncompressedTransfer(root.isUncompressedTransfer()) + .withProgressConsumer(settings.getProgressConsumer()) .call(); repo.setDefaultPath(root.getRepository()); } - return cmd.call(); + return settings.getCmd().call(); } finally { unlockWorkDir(workingDir); } @@ -577,31 +635,39 @@ return this; } - public void buildPatch(@NotNull VcsRoot root, @Nullable String fromVersion, @NotNull String toVersion, @NotNull PatchBuilder builder, @NotNull CheckoutRules checkoutRules) throws IOException, VcsException { - HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + public void buildPatch(@NotNull final VcsRoot root, + @Nullable final String fromVersion, + @NotNull final String toVersion, + @NotNull final PatchBuilder builder, + @NotNull final CheckoutRules checkoutRules) throws IOException, VcsException { + final HgVcsRoot hgRoot = getHgRoot(root); buildPatch(hgRoot, fromVersion, toVersion, builder, checkoutRules); } - public void buildPatch(@NotNull HgVcsRoot hgRoot, - @Nullable String fromVersion, - @NotNull String toVersion, - @NotNull PatchBuilder builder, - @NotNull CheckoutRules checkoutRules) throws IOException, VcsException { + public void buildPatch(@NotNull final HgVcsRoot hgRoot, + @Nullable final String fromVersion, + @NotNull final String toVersion, + @NotNull final PatchBuilder builder, + @NotNull final CheckoutRules checkoutRules) throws IOException, VcsException { syncRepository(hgRoot); - ChangeSet to = new ChangeSet(toVersion); + + final ChangeSet to = new ChangeSet(toVersion); + if (fromVersion == null) { buildFullPatch(hgRoot, to, builder, checkoutRules); - } else { - ChangeSet from = new ChangeSet(fromVersion); - HgRepo repo = createRepo(hgRoot); - if (!repo.containsRevision(from)) { - Loggers.VCS.info("Cannot find revision " + fromVersion + " in repository " + hgRoot.getRepository() + ", will build a full patch"); - cleanCheckoutDir(builder, checkoutRules); - buildFullPatch(hgRoot, to, builder, checkoutRules); - } else { - buildIncrementalPatch(hgRoot, from, to, builder, checkoutRules); - } + return; } + + final ChangeSet from = new ChangeSet(fromVersion); + final HgRepo repo = createRepo(hgRoot); + if (repo.containsRevision(from)) { + buildIncrementalPatch(hgRoot, from, to, builder, checkoutRules); + return; + } + + Loggers.VCS.info("Cannot find revision " + fromVersion + " in repository " + hgRoot.getRepository() + ", will build a full patch"); + cleanCheckoutDir(builder, checkoutRules); + buildFullPatch(hgRoot, to, builder, checkoutRules); } private void cleanCheckoutDir(@NotNull PatchBuilder builder, @NotNull CheckoutRules checkoutRules) throws IOException { @@ -621,11 +687,12 @@ return myConfig.allowSourceCaching(); } + @NotNull public String label(@NotNull String label, @NotNull String version, @NotNull VcsRoot root, @NotNull CheckoutRules checkoutRules) throws VcsException { File tmpDir = null; try { tmpDir = createLabelingTmpDir(); - HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + HgVcsRoot hgRoot = getHgRoot(root); hgRoot.setCustomWorkingDir(tmpDir); syncRepository(hgRoot); HgRepo repo = createRepo(hgRoot); @@ -660,7 +727,7 @@ return label.replace(':', '_').replace('\r', '_').replace('\n', '_'); } - public File getWorkingDir(@NotNull HgVcsRoot root) { + public File getWorkingDir(HgVcsRoot root) { File customDir = root.getCustomWorkingDir(); return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository()); } @@ -703,17 +770,19 @@ } } + @NotNull public ServerHgRepo createRepo(@NotNull HgVcsRoot root) throws VcsException { - return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); + return myRepoFactory.createRepo(root, getWorkingDir(root)); } + @NotNull public ServerHgRepo createRepo(@NotNull OperationContext ctx, @NotNull HgVcsRoot root) throws VcsException { - return ctx.createRepo(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); + return ctx.createRepo(root, getWorkingDir(root)); } - - public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File customDir) throws VcsException { - return myRepoFactory.create(customDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); + @NotNull + public ServerHgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File customDir) throws VcsException { + return myRepoFactory.createRepo(root, customDir); } @NotNull @@ -746,4 +815,11 @@ } return super.getVcsCustomExtension(extensionClass); } + + + private static class ExcludeHgArchival implements FileFilter { + public boolean accept(File f) { + return !f.getName().equals(".hg_archival.txt"); + } + } }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/OperationContext.java Wed Jun 18 12:14:56 2014 +0200 @@ -18,10 +18,10 @@ import com.intellij.openapi.util.Pair; import gnu.trove.TLongObjectHashMap; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.util.Hash; -import jetbrains.buildServer.util.graph.*; +import jetbrains.buildServer.util.graph.BFSVisitorAdapter; +import jetbrains.buildServer.util.graph.DAG; import jetbrains.buildServer.vcs.ModificationData; import jetbrains.buildServer.vcs.RepositoryStateData; import jetbrains.buildServer.vcs.VcsException; @@ -117,11 +117,13 @@ } @NotNull - public ServerHgRepo createRepo(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) throws VcsException { + public ServerHgRepo createRepo(@NotNull final HgVcsRoot root, @NotNull final File workingDir) throws VcsException { ServerHgRepo repo = myRepos.get(workingDir); - if (repo != null) + if (repo != null) { return repo; - repo = myRepoFactory.create(workingDir, hgPath, authSettings); + } + + repo = myRepoFactory.createRepo(root, workingDir); repo.setOperationContext(this); myRepos.put(workingDir, repo); return repo; @@ -208,7 +210,7 @@ @NotNull String fromRevision, @NotNull String toRevision) throws VcsException { syncRepository(root); - ServerHgRepo repo = createRepo(myVcs.getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); + ServerHgRepo repo = createRepo(root, myVcs.getWorkingDir(root)); if (!repo.supportRevsets()) return singleton(fromRevision);
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/RepoFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/RepoFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -18,33 +18,26 @@ import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRoot; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; -import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import static com.intellij.openapi.util.io.FileUtil.createTempFile; -import static com.intellij.openapi.util.io.FileUtil.delete; - /** * @author dmitry.neverov */ public class RepoFactory implements HgRepoFactory { protected final ServerPluginConfig myConfig; - protected final CommandSettingsFactory myCommandSettingsFactory; + protected final CommandSettingsForRoot myCommandSettingsFactory; protected final HgPathProvider myHgPathProvider; - protected final MercurialLogTemplate myLogTemplate = new MercurialLogTemplate("/buildServerResources/log.template", "hg.log.template"); - protected final MercurialLogTemplate myLogNoFilesTemplate = new MercurialLogTemplate("/buildServerResources/log.no.files.template", "hg.short.log.template"); - protected final MercurialLogTemplate myDagTemplate = new MercurialLogTemplate("/buildServerResources/dag.template", "hg.dag.template"); - protected final MercurialLogTemplate myFastLogTemplate = new MercurialLogTemplate("/buildServerResources/fastlog.template", "hg.fastlog.template"); public RepoFactory(@NotNull ServerPluginConfig config, - @NotNull CommandSettingsFactory commandSettingsFactory, + @NotNull CommandSettingsForRoot commandSettingsFactory, @NotNull HgPathProvider hgPathProvider) throws IOException { myConfig = config; myCommandSettingsFactory = commandSettingsFactory; @@ -52,58 +45,20 @@ } @NotNull - public ServerHgRepo create(@NotNull File workingDir, - @NotNull String hgPath, - @NotNull AuthSettings authSettings) throws VcsException { - return new ServerHgRepo(myCommandSettingsFactory, myConfig, workingDir, hgPath, authSettings) - .withLogTemplates(myLogTemplate.getTemplate(), - myLogNoFilesTemplate.getTemplate(), - myDagTemplate.getTemplate(), - myFastLogTemplate.getTemplate()); + protected ServerHgRepo create(@NotNull File workingDir, + @NotNull String hgPath, + @NotNull AuthSettings authSettings, + @NotNull CommandSettingsFactory commandSettingsFactory, + @NotNull ServerPluginConfig config) { + return new ServerHgRepo(commandSettingsFactory, config, workingDir, hgPath, authSettings); } - public HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException { - return create(workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); + @NotNull + public ServerHgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File workingDir) throws VcsException { + return create(workingDir, myHgPathProvider.getHgPath(root), root.getAuthSettings(), myCommandSettingsFactory.forRoot(root), myConfig); } public void dispose() { - myLogTemplate.dispose(); - myLogNoFilesTemplate.dispose(); - myDagTemplate.dispose(); - myFastLogTemplate.dispose(); } - static class MercurialLogTemplate { - private final String myResourcePath; - private final String myTmpFileSuffix; - private File myFile; - - private MercurialLogTemplate(@NotNull String resourcePath, @NotNull String tmpFileSuffix) throws IOException { - myResourcePath = resourcePath; - myTmpFileSuffix = tmpFileSuffix; - copyTemplate(); - } - - @NotNull - public File getTemplate() throws VcsException { - if (myFile.isFile() && myFile.exists()) - return myFile; - try { - copyTemplate(); - return myFile; - } catch (IOException e) { - throw new VcsException("Cannot create mercurial log template", e); - } - } - - public void dispose() { - delete(myFile); - } - - private void copyTemplate() throws IOException { - File template = createTempFile("teamcity", myTmpFileSuffix); - FileUtil.copyResource(RepoFactory.class, myResourcePath, template); - myFile = template; - } - } }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerCommandSettingsFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerCommandSettingsFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -28,6 +28,7 @@ myConfig = config; } + @NotNull public CommandSettings create() { return new CommandSettings().setLogLevel("debug").setLogOutputLimit(myConfig.getLogOutputLimit()); }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java Wed Jun 18 12:14:56 2014 +0200 @@ -39,10 +39,10 @@ private final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0); private final CommandSettingsFactory myCommandSettingsFactory; private final ServerPluginConfig myConfig; - private File myLogTemplate; - private File myLogNoFilesTemplate; - private File myDagTemplate; - private File myFastLogTemplate; + protected final MercurialClasspathTemplate myLogTemplate = new MercurialClasspathTemplate("/buildServerResources/log.template", "hg.log.template"); + protected final MercurialClasspathTemplate myLogNoFilesTemplate = new MercurialClasspathTemplate("/buildServerResources/log.no.files.template", "hg.short.log.template"); + protected final MercurialClasspathTemplate myDagTemplate = new MercurialClasspathTemplate("/buildServerResources/dag.template", "hg.dag.template"); + protected final MercurialClasspathTemplate myFastLogTemplate = new MercurialClasspathTemplate("/buildServerResources/fastlog.template", "hg.fastlog.template"); private OperationContext myContext; public ServerHgRepo(@NotNull CommandSettingsFactory commandSettingsFactory, @@ -59,17 +59,6 @@ myContext = context; } - public ServerHgRepo withLogTemplates(@NotNull File logTemplate, - @NotNull File logNoFilesTemplate, - @NotNull File dagTemplate, - @NotNull File fastLogTemplate) { - myLogTemplate = logTemplate; - myLogNoFilesTemplate = logNoFilesTemplate; - myDagTemplate = dagTemplate; - myFastLogTemplate = fastLogTemplate; - return this; - } - public LogCommand log() { return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings).withTemplate(myLogTemplate); } @@ -80,7 +69,7 @@ } public LogCommand log(@NotNull HgVcsRoot root) { - File template = root.isSubrepo() && !myConfig.reportSubrepoChangesFileStatus() ? myFastLogTemplate : myLogTemplate; + final MercurialTemplate template = root.isSubrepo() && !myConfig.reportSubrepoChangesFileStatus() ? myFastLogTemplate : myLogTemplate; return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings).withTemplate(template); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SyncSettings.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,46 @@ +/* + * 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.ProgressParser; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class SyncSettings<T> { + private VcsCallable<T> myCmd; + private ProgressParser.ProgressConsumer myProgressConsumer; + + public SyncSettings(@NotNull VcsCallable<T> cmd) { + myCmd = cmd; + } + + @NotNull + public VcsCallable<T> getCmd() { + return myCmd; + } + + @Nullable + public ProgressParser.ProgressConsumer getProgressConsumer() { + return myProgressConsumer; + } + + @NotNull + public SyncSettings<T> setProgressConsumer(ProgressParser.ProgressConsumer progressConsumer) { + myProgressConsumer = progressConsumer; + return this; + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesNoRevsets.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesNoRevsets.java Wed Jun 18 12:14:56 2014 +0200 @@ -17,6 +17,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate; import jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgRepo; import jetbrains.buildServer.util.graph.DAG; import jetbrains.buildServer.util.graph.DAGIterator; @@ -24,7 +25,6 @@ import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; -import java.io.File; import java.util.*; /** @@ -34,9 +34,9 @@ private final HgVcsRoot myRoot; private final ServerHgRepo myRepo; - private final File myLogNoFilesTemplate; + private final MercurialTemplate myLogNoFilesTemplate; - public CollectChangesNoRevsets(@NotNull HgVcsRoot root, @NotNull ServerHgRepo repo, @NotNull File logNoFilesTemplate) { + public CollectChangesNoRevsets(@NotNull HgVcsRoot root, @NotNull ServerHgRepo repo, @NotNull MercurialTemplate logNoFilesTemplate) { myRoot = root; myRepo = repo; myLogNoFilesTemplate = logNoFilesTemplate;
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleanerTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleanerTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -17,6 +17,9 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.agent.*; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory; import jetbrains.buildServer.vcs.*; import jetbrains.buildServer.vcs.impl.VcsRootImpl; @@ -62,7 +65,7 @@ AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig); myMirrorManager = new MirrorManagerImpl(pluginConfig); - AgentRepoFactory repoFactory = new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig)); + AgentRepoFactory repoFactory = new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), new AgentHgPathProvider(agentConfig)); myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, myMirrorManager, repoFactory); myCleaner = new AgentMirrorCleaner(myMirrorManager); myLogger = myContext.mock(BuildProgressLogger.class);
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -18,6 +18,9 @@ import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.util.TestFor; @@ -75,7 +78,7 @@ final AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig); myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, new MirrorManagerImpl(pluginConfig), - new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig))); + new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), new AgentHgPathProvider(agentConfig))); myLogger = myContext.mock(BuildProgressLogger.class); myContext.checking(new Expectations() {{ @@ -127,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()); }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -20,8 +20,7 @@ import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ConnectionRefusedException; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.CheckoutRules; @@ -83,7 +82,7 @@ myMirrorManager = new MirrorManagerImpl(pluginConfig); myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, myMirrorManager, - new AgentRepoFactory(new TestCommandSettingsFactory(), new AgentHgPathProvider(agentConfig))); + new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), new AgentHgPathProvider(agentConfig))); myLogger = myContext.mock(BuildProgressLogger.class); myContext.checking(new Expectations() {{
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseAgentSideCheckoutTestCase.java Wed Jun 18 12:14:56 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/ExtensionsTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import junit.framework.Assert; +import org.jetbrains.annotations.NotNull; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; + +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialSupportBuilder.mercurialSupport; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigBuilder.serverPluginConfig; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot; + +/** + * Created 25.02.14 13:17 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +@RequiredHgVersion(min = "2.0.0") +public class ExtensionsTest extends BaseMercurialTestCase { + + @Test(dataProviderClass = HgVersionConstraint.class, dataProvider = "installedHgVersion") + public void test_no_extension(HgVersion _) throws IOException, VcsException { + String extension = "HGExtensionThatDoesNotExits"; + + try { + runWithExtensions(extension); + Assert.fail(); + } catch (VcsException e) { + Assert.assertTrue(e.getMessage().contains(extension)); + } + } + + @Test(dataProviderClass = HgVersionConstraint.class, dataProvider = "installedHgVersion") + public void test_extension(HgVersion _) throws IOException, VcsException { + runWithExtensions("mq", "largefiles"); + } + + private void runWithExtensions(@NotNull String... extensions) throws IOException, VcsException { + ServerPluginConfig config = serverPluginConfig() + .cachesDir(myTempFiles.createTempDir()) + .hgPath(Util.getHgPath()) + .build(); + + final File myRemoteRepository = myTempFiles.createTempDir(); + Util.copyRepository(new File("mercurial-tests/testData/rep2"), myRemoteRepository); + + + final MercurialSupportBuilder hgBuilder = mercurialSupport().withConfig(config); + final MercurialVcsSupport vcs = hgBuilder.build(); + final VcsRoot root = vcsRoot().withUrl(myRemoteRepository.getAbsolutePath()).withBranch("default").withExtensions(extensions).build(); + + vcs.getCollectChangesPolicy().getCurrentState(root); + vcs.getTestConnectionSupport().testConnection(root); + } + + +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialSupportBuilder.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,6 +16,9 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +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.serverSide.ServerListener; import jetbrains.buildServer.util.EventDispatcher; @@ -52,7 +55,7 @@ MirrorManagerImpl mirrorManager = new MirrorManagerImpl(myConfig); myHgPathProvider = new ServerHgPathProvider(myConfig); if (myRepoFactory == null) - myRepoFactory = new RepoFactory(myConfig, new TestCommandSettingsFactory(), myHgPathProvider); + myRepoFactory = new RepoFactory(myConfig, new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), myHgPathProvider); HgTestConnectionSupport testConnection = new HgTestConnectionSupport(myHgRootFactory, myRepoFactory, mirrorManager, myHgPathProvider); final ResetCacheRegister resetCacheManager = myContext.mock(ResetCacheRegister.class); myContext.checking(new Expectations() {{
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -264,11 +264,10 @@ assertEquals(actualTag, "new_tag"); // check the tag is pushed to the parent repository - MercurialCommandLine cli = new MercurialCommandLine(); + MercurialCommandLine cli = new MercurialCommandLine(Collections.<String>emptySet()); cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP)); cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP)); cli.setEnvParams(map("HGRCPATH", "")); - cli.setPassParentEnvs(true); cli.addParameter("tags"); CommandResult res = CommandUtil.runCommand(cli, new CommandSettings()); assertTrue(res.getStdout().contains("new_tag")); @@ -282,12 +281,11 @@ assertEquals(actualTag, "branch_tag"); // check the tag is pushed to the parent repository - MercurialCommandLine cli = new MercurialCommandLine(); + MercurialCommandLine cli = new MercurialCommandLine(Collections.<String>emptySet()); cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP)); cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP)); cli.addParameter("tags"); cli.setEnvParams(map("HGRCPATH", "")); - cli.setPassParentEnvs(true); CommandResult res = CommandUtil.runCommand(cli, new CommandSettings()); assertTrue(res.getStdout().contains("branch_tag")); assertTrue(res.getStdout().contains("7:376dcf05cd2a")); @@ -601,8 +599,6 @@ if (!SystemInfo.isUnix) return; - RepoFactory repoFactory = new RepoFactory(myPluginConfig, new TestCommandSettingsFactory(), myHgPathProvider); - //create a file on the server File dirOnTheServer = myTempFiles.createTempDir(); File fileOnTheServer = new File(dirOnTheServer, "file.on.server"); @@ -610,7 +606,7 @@ //create a remote repository with symlink pointing to the file on the server File repository = copyRepository(myTempFiles, simpleRepo()); - ServerHgRepo repo = repoFactory.create(repository, getHgPath(), new AuthSettings()); + ServerHgRepo repo = new ServerHgRepo(new TestCommandSettingsFactory(), myPluginConfig, repository, getHgPath(), new AuthSettings()); repo.update().toRevision("9c6a6b4aede0").call(); new ProcessBuilder("ln", "-s", dirOnTheServer.getCanonicalPath()).directory(repository).start().waitFor(); new ProcessBuilder(getHgPath(), "add", dirOnTheServer.getName()).directory(repository).start().waitFor(); @@ -634,17 +630,14 @@ VersionCommand russianLocalVersion = new VersionCommand(new TestCommandSettingsFactory().create(), Util.getHgPath(), new File(simpleRepo())) { @Override + @NotNull protected MercurialCommandLine createCommandLine() { - MercurialCommandLine commandLine = super.createCommandLine(); - Map<String, String> env = commandLine.getEnvParams(); - if (env == null) - env = new HashMap<String, String>(); - env.put("LANG", "ru_RU"); - env.put("LANGUAGE", "ru_RU"); - env.put("LC_MESSAGE", "ru_RU"); - env.put("HGRCPATH", ""); - commandLine.setEnvParams(env); - return commandLine; + final MercurialCommandLine env = super.createCommandLine(); + env.addEnvParam("LANG", "ru_RU"); + env.addEnvParam("LANGUAGE", "ru_RU"); + env.addEnvParam("LC_MESSAGE", "ru_RU"); + env.addEnvParam("HGRCPATH", ""); + return env; } };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PurgeTest.java Wed Jun 18 12:14:56 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:1db20368ddc7"); + + File unknownFile = createUnknownFile(myWorkDir); + File ignoredFile = createIgnoredFile(myWorkDir); + + checkout(vcsRoot, "1:1db20368ddc7"); + + 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:1db20368ddc7"); + + File unknownFile = createUnknownFile(myWorkDir); + File ignoredFile = createIgnoredFile(myWorkDir); + + checkout(vcsRoot, "1:1db20368ddc7"); + + 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:47e24ed2a4a9"); + + 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:47e24ed2a4a9"); + + 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:47e24ed2a4a9"); + + 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:47e24ed2a4a9"); + + 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/SubrepoChangesTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SubrepoChangesTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,10 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CatCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsFactory; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; import jetbrains.buildServer.vcs.*; import org.jetbrains.annotations.NotNull; import org.testng.annotations.BeforeMethod; @@ -230,15 +227,11 @@ .build(); final AtomicInteger catCallCounter = new AtomicInteger(0); - RepoFactory repoFactory = new RepoFactory(pluginConfig, new TestCommandSettingsFactory(), myHgPathProvider) { + RepoFactory repoFactory = new RepoFactory(pluginConfig, new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), myHgPathProvider) { @NotNull @Override - public ServerHgRepo create(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) throws VcsException { - return new CountingServerHgRepo(myCommandSettingsFactory, myConfig, workingDir, hgPath, authSettings, catCallCounter) - .withLogTemplates(myLogTemplate.getTemplate(), - myLogNoFilesTemplate.getTemplate(), - myDagTemplate.getTemplate(), - myFastLogTemplate.getTemplate()); + protected ServerHgRepo create(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings, @NotNull CommandSettingsFactory commandSettingsFactory, @NotNull ServerPluginConfig config) { + return new CountingServerHgRepo(commandSettingsFactory, config, workingDir, hgPath, authSettings, catCallCounter); } };
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,6 +16,8 @@ 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; import org.jetbrains.annotations.NotNull; @@ -30,6 +32,7 @@ */ public class VcsRootBuilder { + private String myExtensions; private String myRepository; private String myUsername; private String myPassword; @@ -43,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(); @@ -60,9 +64,12 @@ vcsRoot.addProperty(Constants.DETECT_SUBREPO_CHANGES, String.valueOf(myDetectSubrepoChanges)); vcsRoot.addProperty(Constants.INCLUDE_SUBREPOS_IN_PATCH, String.valueOf(myIncludeSubreposInPatch)); vcsRoot.addProperty(Constants.USE_ARCHIVE_FOR_PATCH, String.valueOf(myUseArchiveForPatch)); + vcsRoot.addProperty(Constants.HG_EXTENSIONS, myExtensions); if (myCloneRepositoryTo != null) vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, String.valueOf(myCloneRepositoryTo.getAbsolutePath())); vcsRoot.addProperty(Constants.USE_TAGS_AS_BRANCHES, String.valueOf(myTagsAsBranches)); + if (myPurgePolicy != null) + vcsRoot.addProperty(Constants.PURGE_POLICY, myPurgePolicy.name()); return vcsRoot; } @@ -82,6 +89,7 @@ allowing(root).getProperty(with(Constants.USER_FOR_TAG)); will(returnValue(myUserForTag)); allowing(root).getProperty(with(Constants.DETECT_SUBREPO_CHANGES)); will(returnValue(String.valueOf(myDetectSubrepoChanges))); allowing(root).getProperty(with(Constants.USE_TAGS_AS_BRANCHES)); will(returnValue(String.valueOf(myTagsAsBranches))); + allowing(root).getProperty(with(Constants.HG_EXTENSIONS)); will(returnValue(myExtensions)); }}); if (myCloneRepositoryTo != null) { context.checking(new Expectations() {{ @@ -97,6 +105,12 @@ return this; } + @NotNull + public VcsRootBuilder withExtensions(@NotNull String... extensions) { + myExtensions = StringUtil.join(extensions, "\n"); + return this; + } + public VcsRootBuilder withLocalRepository(@NotNull final File repo) { return withUrl(repo.getPath()).withCloneRepositoryTo(repo.getParentFile()); @@ -173,4 +187,10 @@ myTagsAsBranches = useTagsAsBranches; return this; } + + + public VcsRootBuilder withPurgePolicy(HgVcsRoot.PurgePolicy policy) { + myPurgePolicy = policy; + return this; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ViaCMDInterceptor.java Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,56 @@ +/* + * 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.TestCommandSettingsFactory; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommand; +import org.testng.IMethodInstance; +import org.testng.IMethodInterceptor; +import org.testng.ITestContext; + +import java.io.File; +import java.util.Collections; +import java.util.List; + +/** + * Created 03.06.2014 13:22 + * + * @author Eugene Petrenko (eugene.petrenko@jetbrains.com) + */ +public class ViaCMDInterceptor implements IMethodInterceptor { + public List<IMethodInstance> intercept(List<IMethodInstance> list, ITestContext iTestContext) { + if (!"true".equalsIgnoreCase(System.getProperty("teamcity.mercurial.use.commandline.via.file.wrapper"))) { + return list; + } + + try { + final String path = Util.getHgPath(); + final VersionCommand versionCommand = new VersionCommand(new TestCommandSettingsFactory().create(), path, new File("..")); + final HgVersion version = versionCommand.call(); + + if (!version.isEqualsOrGreaterThan(new HgVersion(2,5,0))) { + System.out.println("!!! Mercurial version is too old: " + version + " @ " + path); + return Collections.emptyList(); + } + + return list; + } catch (Throwable t) { + System.out.println("Invalid mercurial: " + t.getMessage()); + return Collections.emptyList(); + } + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,7 +16,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; -import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.util.SystemInfo; import junit.framework.TestCase; import org.testng.annotations.Test; @@ -33,13 +32,15 @@ public void should_quote_command_line_arguments() throws IOException { File workingDir = new File("some dir"); BaseCommand command = new BaseCommand(new CommandSettings(), "/path/to/hg", workingDir); - GeneralCommandLine cl = command.createCommandLine(); + MercurialCommandLine cl = command.createCommandLine(); cl.addParameter("param with spaces"); cl.addParameter("param with quote \" rm -rf /"); if (SystemInfo.isWindows) { assertTrue(cl.getCommandLineString().endsWith(" \"param with spaces\" \"param with quote \\\" rm -rf /\"")); + assertTrue(cl.toGeneralCommandLine().getCommandLineString().endsWith(" \"param with spaces\" \"param with quote \\\" rm -rf /\"")); } else { assertTrue(cl.getCommandLineString().endsWith(" param with spaces param with quote \" rm -rf /")); + assertTrue(cl.toGeneralCommandLine().getCommandLineString().endsWith(" param with spaces param with quote \" rm -rf /")); } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -80,11 +80,12 @@ }); } + @NotNull private File runCat(@NotNull final List<String> paths) throws IOException, VcsException { return runCommand(new CommandExecutor<File>() { public File execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { - CatCommand cat = new CatCommand(new CommandSettings(), hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()); - return cat.execute(paths); + final CatCommand cat = new CatCommand(new CommandSettings(), hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()); + return cat.files(paths).checkForFailure(true).call(); } }); }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Wed Jun 18 12:14:56 2014 +0200 @@ -17,8 +17,8 @@ import jetbrains.buildServer.TempFiles; import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport; -import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialClasspathTemplate; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialTemplate; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.testng.annotations.AfterMethod; @@ -35,7 +35,7 @@ public class LogCommandTest extends BaseCommandTestCase { private TempFiles myTempFiles = new TempFiles(); - private File myTemplateFile; + private MercurialTemplate myTemplateFile; @BeforeMethod @@ -43,8 +43,7 @@ protected void setUp() throws Exception { super.setUp(); setRepository("mercurial-tests/testData/rep1", true); - myTemplateFile = myTempFiles.createTempFile(); - FileUtil.copyResource(MercurialVcsSupport.class, "/buildServerResources/log.template", myTemplateFile); + myTemplateFile = new MercurialClasspathTemplate("/buildServerResources/log.template", "log.template") {}; }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TestCommandSettingsFactory.java Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TestCommandSettingsFactory.java Wed Jun 18 12:14:56 2014 +0200 @@ -16,8 +16,11 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import org.jetbrains.annotations.NotNull; + public class TestCommandSettingsFactory implements CommandSettingsFactory { + @NotNull public CommandSettings create() { return new CommandSettings().addHgEnv("HGRCPATH", ""); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/testng-via-cmd.xml Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,46 @@ +<!-- + ~ 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. + --> + +<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> +<suite name="Mercurial Suite"> + <listeners> + <listener class-name="jetbrains.buildServer.buildTriggers.vcs.mercurial.ViaCMDInterceptor"/> + </listeners> + + <test name="Mercurial via commands file tests"> + <classes> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CatCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CloneCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.StatusCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.PushCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.IdentifyCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupportTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.DagFeaturesTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.UnrelatedResitoriesTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.ListFilesSupportTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.SubrepoChangesTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.SubrepoPatchTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MergeSupportTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.TagsTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.CommitsInfoBuilderSupportTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialModificationInfoBuilderTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialUrlSupportTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.PurgeTest"/> + </classes> + </test> +</suite>
--- a/mercurial-tests/src/testng.xml Tue Jun 17 22:30:00 2014 +0200 +++ b/mercurial-tests/src/testng.xml Wed Jun 18 12:14:56 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 Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,5 @@ +o changeset: 2:47e24ed2a4a9 //add same repo as a subrepo at path self +| +o changeset: 1:1db20368ddc7 //ignores ignoredFile +| +o changeset: 0:acefc1a0763c //contains file a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/testPurge/hg/cache/tags Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,2 @@ +2 47e24ed2a4a91d036e740d4a8bdcd7fd156ed3dc +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/testPurge/hg/last-message.txt Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,1 @@ +add same repo as a 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 Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/testPurge/hg/store/fncache Wed Jun 18 12:14:56 2014 +0200 @@ -0,0 +1,4 @@ +data/a.i +data/.hgignore.i +data/.hgsub.i +data/.hgsubstate.i