Mercurial > hg > mercurial
changeset 339:b799355b4016
Merge branch Eluru-6.5.x
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Fri, 02 Dec 2011 15:35:00 +0300 |
parents | ae189ede9756 (diff) d31d7c81b637 (current diff) |
children | abfaa81ee52b |
files | mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java |
diffstat | 77 files changed, 4571 insertions(+), 2944 deletions(-) [+] |
line wrap: on
line diff
--- a/build.xml Fri Dec 02 15:12:49 2011 +0300 +++ b/build.xml Fri Dec 02 15:35:00 2011 +0300 @@ -1,72 +1,72 @@ -<project name="Mercurial VCS Support" default="dist" basedir="."> - <property file="mercurial.properties"/> - <import file="mercurial.xml"/> - - <property name="distPath" value="${basedir}/dist"/> - - <property name="plugin.name" value="mercurial"/> - - <property name="build.number" value=""/> - <tstamp> - <format property="timestamp" pattern="yyyyMMddhhmmss"/> - </tstamp> - <property name="snapshot.build.number" value="SNAPSHOT-${timestamp}"/> - <property name="build.vcs.number" value=""/> - - <condition property="plugin.version" value="${snapshot.build.number}" else="${build.number}"> - <matches pattern="snapshot-.*" string="${build.number}" casesensitive="false"/> - </condition> - - <import file="teamcity-common.xml"/> - - <target name="package" depends="define.version"> - <package.teamcity.plugin name="${plugin.name}" - server.output="${mercurial-server.output.dir}" - agent.output="${mercurial-agent.output.dir}" - common.output="${mercurial-common.output.dir}" - plugin.descriptor.file="${basedir}/teamcity-plugin.xml" - plugin.version="${plugin.version}"/> - </target> - - <target name="define.version" depends="define.version.if.under.teamcity"> - <tstamp> - <format property="current.time" pattern="yyyyMMddHHmm"/> - </tstamp> - <property name="plugin.version" value="SNAPSHOT-${current.time}"/> - </target> - - <target name="define.version.if.under.teamcity" if="build.number"> - <property name="plugin.version" value="${build.number}"/> - </target> - - <target name="dist" depends="check.teamcitydistribution,all,package"/> - - <target name="deploy" depends="dist"> - <deploy.teamcity.plugin name="${plugin.name}"/> - </target> - - <taskdef name="testng" classname="org.testng.TestNGAntTask" classpath="${basedir}/mercurial-tests/lib/testng-5.7-jdk15.jar"/> - - <path id="tests_classpath"> - <pathelement location="${agent.home.dir}/lib/runtime-util.jar"/> - <pathelement location="${agent.home.dir}/lib/buildServerRuntimeUtil.jar"/> - <path refid="mercurial-tests.runtime.module.classpath"/> - </path> - - <target name="run-tests" depends="clean, init, compile.module.mercurial-tests"> - <property name="suspend" value="n"/> - - <testng haltonfailure="no" failureProperty="failure_found" listener="org.testng.reporters.TestHTMLReporter" - outputdir="${basedir}/test-output" classpathref="tests_classpath" dumpcommand="true" workingDir="${basedir}"> - - <jvmarg value="-ea"/> - <!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=${suspend},address=5555"/>--> - - <sysproperty key="java.awt.headless" value="true"/> - - <xmlfileset dir="${basedir}/mercurial-tests/src"> - <include name="testng.xml"/> - </xmlfileset> - </testng> - </target> -</project> +<project name="Mercurial VCS Support" default="dist" basedir="."> + <property file="mercurial.properties"/> + <import file="mercurial.xml"/> + + <property name="distPath" value="${basedir}/dist"/> + + <property name="plugin.name" value="mercurial"/> + + <property name="build.number" value=""/> + <tstamp> + <format property="timestamp" pattern="yyyyMMddhhmmss"/> + </tstamp> + <property name="snapshot.build.number" value="SNAPSHOT-${timestamp}"/> + <property name="build.vcs.number" value=""/> + + <condition property="plugin.version" value="${snapshot.build.number}" else="${build.number}"> + <matches pattern="snapshot-.*" string="${build.number}" casesensitive="false"/> + </condition> + + <import file="teamcity-common.xml"/> + + <target name="package" depends="define.version"> + <package.teamcity.plugin name="${plugin.name}" + server.output="${mercurial-server.output.dir}" + agent.output="${mercurial-agent.output.dir}" + common.output="${mercurial-common.output.dir}" + plugin.descriptor.file="${basedir}/teamcity-plugin.xml" + plugin.version="${plugin.version}"/> + </target> + + <target name="define.version" depends="define.version.if.under.teamcity"> + <tstamp> + <format property="current.time" pattern="yyyyMMddHHmm"/> + </tstamp> + <property name="plugin.version" value="SNAPSHOT-${current.time}"/> + </target> + + <target name="define.version.if.under.teamcity" if="build.number"> + <property name="plugin.version" value="${build.number}"/> + </target> + + <target name="dist" depends="check.teamcitydistribution,all,package"/> + + <target name="deploy" depends="dist"> + <deploy.teamcity.plugin name="${plugin.name}"/> + </target> + + <taskdef name="testng" classname="org.testng.TestNGAntTask" classpath="${basedir}/mercurial-tests/lib/testng-5.7-jdk15.jar"/> + + <path id="tests_classpath"> + <pathelement location="${agent.home.dir}/lib/runtime-util.jar"/> + <pathelement location="${agent.home.dir}/lib/buildServerRuntimeUtil.jar"/> + <path refid="mercurial-tests.runtime.module.classpath"/> + </path> + + <target name="run-tests" depends="clean, init, compile.module.mercurial-tests"> + <property name="suspend" value="n"/> + + <testng haltonfailure="no" failureProperty="failure_found" listener="org.testng.reporters.TestHTMLReporter" + outputdir="${basedir}/test-output" classpathref="tests_classpath" dumpcommand="true" workingDir="${basedir}"> + + <jvmarg value="-ea"/> + <!--<jvmarg value="-Xrunjdwp:transport=dt_socket,server=y,suspend=${suspend},address=5555"/>--> + + <sysproperty key="java.awt.headless" value="true"/> + + <xmlfileset dir="${basedir}/mercurial-tests/src"> + <include name="testng.xml"/> + </xmlfileset> + </testng> + </target> +</project>
--- a/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Fri Dec 02 15:35:00 2011 +0300 @@ -1,6 +1,9 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> - -<beans default-autowire="constructor"> - <bean id="mercurialAgent" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> -</beans> +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> + +<beans default-autowire="constructor"> + <bean id="mercurialAgent" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> + <bean id="hgPathProvider" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentHgPathProvider" /> + <bean id="hgDetector" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgDetector" /> + <bean id="pluginConfig" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentPluginConfigImpl"/> +</beans>
--- a/mercurial-agent/src/build-agent-plugin.xml Fri Dec 02 15:12:49 2011 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -<!-- -PicoContainer configuration for old fashioned TeamCity agent plugins. -In TeamCity 4.0 Spring configuration must be created instead. ---> -<container> - <component class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialAgentSideVcsSupport" /> -</container> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentHgPathProvider.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,32 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.parameters.ProcessingResult; +import jetbrains.buildServer.parameters.ValueResolver; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class AgentHgPathProvider implements HgPathProvider { + + private final ValueResolver myResolver; + + + public AgentHgPathProvider(@NotNull final BuildAgentConfiguration agentConfig) { + myResolver = agentConfig.getParametersResolver(); + } + + + public String getHgPath(@NotNull final Settings settings) { + String pathFromRoot = settings.getHgPath(); + return resolve(pathFromRoot); + } + + + private String resolve(@NotNull final String value) { + ProcessingResult result = myResolver.resolve(value); + return result.getResult(); + } +}
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfig.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,10 +1,14 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import jetbrains.buildServer.agent.AgentRunningBuild; +import org.jetbrains.annotations.NotNull; + /** * @author dmitry.neverov */ public interface AgentPluginConfig extends PluginConfig { - boolean isUseLocalMirrors(); + boolean isUseLocalMirrors(@NotNull AgentRunningBuild build); + int getPullTimeout(@NotNull AgentRunningBuild build); }
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentPluginConfigImpl.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,9 +1,12 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.BuildAgentConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; + /** * @author dmitry.neverov */ @@ -12,18 +15,23 @@ private static final String PULL_TIMEOUT_SECONDS = "teamcity.hg.pull.timeout.seconds"; private final int DEFAULT_PULL_TIMEOUT_SECONDS = 3600; - private final AgentRunningBuild myBuild; + private final BuildAgentConfiguration myAgentConfig; - public AgentPluginConfigImpl(@NotNull AgentRunningBuild build) { - myBuild = build; + public AgentPluginConfigImpl(@NotNull BuildAgentConfiguration agentConfig) { + myAgentConfig = agentConfig; } - public boolean isUseLocalMirrors() { - return "true".equals(myBuild.getSharedConfigParameters().get("teamcity.hg.use.local.mirrors")); + public boolean isUseLocalMirrors(@NotNull AgentRunningBuild build) { + return "true".equals(build.getSharedConfigParameters().get("teamcity.hg.use.local.mirrors")); } - public int getPullTimeout() { - Integer timeout = parseTimeout(myBuild.getSharedConfigParameters().get(PULL_TIMEOUT_SECONDS)); + @NotNull + public File getCachesDir() { + return myAgentConfig.getCacheDirectory("mercurial"); + } + + public int getPullTimeout(@NotNull AgentRunningBuild build) { + Integer timeout = parseTimeout(build.getSharedConfigParameters().get(PULL_TIMEOUT_SECONDS)); if (timeout != null) return timeout; return DEFAULT_PULL_TIMEOUT_SECONDS; @@ -38,7 +46,7 @@ if (timeout > 0) return timeout; else - return null; + return null; } catch (NumberFormatException e) { return null; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgDetector.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,90 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.agent.AgentLifeCycleAdapter; +import jetbrains.buildServer.agent.AgentLifeCycleListener; +import jetbrains.buildServer.agent.BuildAgent; +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommand; +import jetbrains.buildServer.util.EventDispatcher; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +/** + * @author dmitry.neverov + */ +public class HgDetector extends AgentLifeCycleAdapter { + + final static String AGENT_HG_PATH_PROPERTY = "teamcity.hg.agent.path"; + private final static Logger LOG = Logger.getInstance(HgDetector.class.getName()); + private final static HgVersion LEAST_SUPPORTED_VERSION = new HgVersion(1, 5, 2); + private final List<String> myHgPaths = Arrays.asList("hg"); + + + public HgDetector(@NotNull final EventDispatcher<AgentLifeCycleListener> dispatcher) { + dispatcher.addListener(this); + } + + + @Override + public void beforeAgentConfigurationLoaded(@NotNull final BuildAgent agent) { + BuildAgentConfiguration config = agent.getConfiguration(); + String agentHgPath = config.getConfigurationParameters().get(AGENT_HG_PATH_PROPERTY); + File workDir = config.getTempDirectory(); + if (agentHgPath == null) { + String detectedHg = detectHg(workDir); + if (detectedHg != null) { + LOG.info("Detect installed mercurial at path " + detectedHg + ", provide it as a property " + AGENT_HG_PATH_PROPERTY); + config.addConfigurationParameter(AGENT_HG_PATH_PROPERTY, "hg"); + } else { + LOG.info("Cannot detect installed mercurial"); + } + } else { + if (!canRunHg(agentHgPath, workDir, true)) + LOG.warn("Mercurial executable at path " + agentHgPath + " cannot be run or not compatible with TeamCity"); + } + } + + + @Nullable + private String detectHg(@NotNull final File workDir) { + for (String path : myHgPaths) { + if (canRunHg(path, workDir)) + return path; + } + return null; + } + + + private boolean canRunHg(@NotNull final String hgPath, @NotNull final File workDir) { + return canRunHg(hgPath, workDir, false); + } + + private boolean canRunHg(@NotNull final String hgPath, @NotNull final File workDir, boolean logWarnings) { + VersionCommand versionCommand = new VersionCommand(hgPath, workDir); + try { + HgVersion version = versionCommand.execute(); + if (isCompatible(version)) { + return true; + } else { + if (logWarnings) + LOG.warn("Mercurial version at path " + hgPath + " is " + version + ", required version is " + LEAST_SUPPORTED_VERSION + "+"); + return false; + } + } catch (VcsException e) { + if (logWarnings) + LOG.warn("Error while trying to get hg version, hg path " + hgPath + ", error: " + e.getMessage()); + return false; + } + } + + + private boolean isCompatible(@NotNull final HgVersion version) { + return version.isEqualsOrGreaterThan(LEAST_SUPPORTED_VERSION); + } +}
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Fri Dec 02 15:35:00 2011 +0300 @@ -16,58 +16,32 @@ 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.AgentVcsSupport; import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2; import jetbrains.buildServer.agent.vcs.UpdatePolicy; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.util.FileUtil; 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 java.io.File; -import java.io.IOException; -import java.util.Collections; - -import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil.removePrivateData; public class MercurialAgentSideVcsSupport extends AgentVcsSupport implements UpdateByIncludeRules2 { + private final AgentPluginConfig myConfig; + private final HgPathProvider myHgPathProvider; private final MirrorManager myMirrorManager; - public MercurialAgentSideVcsSupport(BuildAgentConfiguration agentConfiguration) { - myMirrorManager = new MirrorManager(agentConfiguration.getCacheDirectory("mercurial")); + public MercurialAgentSideVcsSupport(@NotNull final AgentPluginConfig pluginConfig, + @NotNull final HgPathProvider hgPathProvider) { + myConfig = pluginConfig; + myHgPathProvider = hgPathProvider; + myMirrorManager = new MirrorManager(myConfig.getCachesDir()); } public IncludeRuleUpdater getUpdater(@NotNull final VcsRoot vcsRoot, @NotNull final CheckoutRules checkoutRules, @NotNull final String toVersion, @NotNull final File checkoutDirectory, @NotNull final AgentRunningBuild build, boolean cleanCheckoutRequested) throws VcsException { - final AgentPluginConfig config = new AgentPluginConfigImpl(build); - final BuildProgressLogger logger = build.getBuildLogger(); - return new IncludeRuleUpdater() { - public void process(@NotNull final IncludeRule includeRule, @NotNull final File workingDir) throws VcsException { - try { - checkRuleIsValid(includeRule); - Settings settings = new Settings(vcsRoot); - if (config.isUseLocalMirrors()) { - updateLocalMirror(vcsRoot, logger, config); - } - updateRepository(workingDir, settings, logger, config); - updateWorkingDir(settings, workingDir, toVersion, logger); - } catch (Exception e) { - if (e instanceof VcsException) - throw (VcsException) e; - else - throw new VcsException(e); - } - } - - public void dispose() throws VcsException { - } - }; + return new MercurialIncludeRuleUpdater(myConfig, myMirrorManager, myHgPathProvider, vcsRoot, toVersion, build); } @NotNull @@ -81,90 +55,4 @@ public UpdatePolicy getUpdatePolicy() { return this; } - - private void initRepository(File workingDir, Settings settings, BuildProgressLogger logger, boolean useLocalMirrors) throws VcsException { - try { - String defaultPullUrl = getDefaultPullUrl(settings, useLocalMirrors); - logger.message("Init repository at " + workingDir.getAbsolutePath() + ", remote repository is " + - removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new Init(settings, workingDir, defaultPullUrl).execute(); - } catch (IOException e) { - throw new VcsException("Error while initializing repository at " + workingDir.getAbsolutePath(), e); - } - } - - private void updateRepository(File workingDir, Settings settings, BuildProgressLogger logger, AgentPluginConfig config) throws VcsException, IOException { - if (!Settings.isValidRepository(workingDir)) { - initRepository(workingDir, settings, logger, config.isUseLocalMirrors()); - } else { - ensureUseRightRepository(workingDir, settings, logger, config.isUseLocalMirrors()); - } - String defaultPullUrl = getDefaultPullUrl(settings, config.isUseLocalMirrors()); - logger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new PullCommand(settings, workingDir).execute(config.getPullTimeout()); - logger.message("Changes successfully pulled"); - } - - private void ensureUseRightRepository(File workingDir, Settings settings, BuildProgressLogger logger, boolean useLocalMirrors) throws VcsException { - boolean clonedFromWrongRepository = useLocalMirrors && !isClonedFromLocalMirror(settings, workingDir) - || !useLocalMirrors && isClonedFromLocalMirror(settings, workingDir); - - if (clonedFromWrongRepository) { - String rightRepository = useLocalMirrors ? "local mirror" : "remote repository"; - String wrongRepository = useLocalMirrors ? "remote repository" : "local mirror"; - logger.message("Repository in working directory is cloned from " + wrongRepository + ", clone it from " + rightRepository); - FileUtil.delete(workingDir); - initRepository(workingDir, settings, logger, useLocalMirrors); - } - } - - private void updateLocalMirror(VcsRoot root, BuildProgressLogger logger, AgentPluginConfig config) throws VcsException, IOException { - Settings settings = new Settings(root); - File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepositoryUrl()); - logger.message("Update local mirror at " + mirrorDir); - if (!Settings.isValidRepository(mirrorDir)) { - initRepository(mirrorDir, settings, logger, false); - } - final String defaultPullUrl = getDefaultPullUrl(settings, true); - logger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new PullCommand(settings, mirrorDir).execute(config.getPullTimeout()); - logger.message("Local mirror changes successfully pulled"); - } - - private void updateWorkingDir(final Settings settings, File workingDir, @NotNull final String version, final BuildProgressLogger logger) throws VcsException { - logger.message("Updating folder " + workingDir.getAbsolutePath() + " to revision " + version); - UpdateCommand uc = new UpdateCommand(settings, workingDir); - ChangeSet cs = new ChangeSet(version); - uc.setToId(cs.getId()); - uc.execute(); - logger.message("Folder successfully updated"); - } - - private String getDefaultPullUrl(Settings settings, boolean useLocalMirror) throws IOException { - if (useLocalMirror) { - File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepositoryUrl()); - return mirrorDir.getCanonicalPath(); - } else { - return settings.getRepositoryUrl(); - } - } - - private void checkRuleIsValid(IncludeRule includeRule) throws VcsException { - if (includeRule.getTo() != null && includeRule.getTo().length() > 0) { - if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) { - throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); - } - } - } - - public boolean isClonedFromLocalMirror(Settings settings, File workingDir) { - try { - File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepositoryUrl()); - File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); - String config = FileUtil.readText(hgrc); - return config.contains("default = " + mirrorDir.getCanonicalPath()); - } catch (Exception e) { - return false; - } - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,306 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.BuildProgressLogger; +import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.IncludeRule; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil.removePrivateData; + +/** + * @author dmitry.neverov + */ +public class MercurialIncludeRuleUpdater implements IncludeRuleUpdater { + + private final AgentPluginConfig myConfig; + private final MirrorManager myMirrorManager; + private final HgPathProvider myHgPathProvider; + private final VcsRoot myRoot; + private final Settings mySettings; + private final String myToVersion; + private final BuildProgressLogger myLogger; + private final boolean myUseLocalMirrors; + private int myPullTimeout; + + public MercurialIncludeRuleUpdater(@NotNull final AgentPluginConfig pluginConfig, + @NotNull final MirrorManager mirrorManager, + @NotNull final HgPathProvider hgPathProvider, + @NotNull final VcsRoot root, + @NotNull final String toVersion, + @NotNull final AgentRunningBuild build) { + myConfig = pluginConfig; + myMirrorManager = mirrorManager; + myHgPathProvider = hgPathProvider; + myRoot = root; + mySettings = new Settings(myHgPathProvider, myRoot); + myToVersion = toVersion; + myLogger = build.getBuildLogger(); + myUseLocalMirrors = myConfig.isUseLocalMirrors(build); + myPullTimeout = myConfig.getPullTimeout(build); + } + + + public void process(@NotNull IncludeRule rule, @NotNull File workingDir) throws VcsException { + try { + checkRuleIsValid(rule); + if (myUseLocalMirrors) + updateLocalMirror(); + updateRepository(workingDir); + updateWorkingDir(workingDir); + } catch (Exception e) { + throwVcsException(e); + } + } + + + public void dispose() throws VcsException { + } + + + private void throwVcsException(Exception e) throws VcsException { + if (e instanceof VcsException) + throw (VcsException) e; + else + throw new VcsException(e); + } + + + private void initRepository(Settings settings, File workingDir, boolean useLocalMirrors) throws VcsException { + try { + String defaultPullUrl = getDefaultPullUrl(settings, useLocalMirrors); + myLogger.message("Init repository at " + workingDir.getAbsolutePath() + ", remote repository is " + + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); + new Init(settings, workingDir, defaultPullUrl).execute(); + } catch (IOException e) { + throw new VcsException("Error while initializing repository at " + workingDir.getAbsolutePath(), e); + } + } + + + private void updateRepository(File workingDir) throws VcsException, IOException { + if (!Settings.isValidRepository(workingDir)) { + initRepository(mySettings, workingDir, myUseLocalMirrors); + } else { + ensureUseRightRepository(workingDir); + } + String defaultPullUrl = getDefaultPullUrl(mySettings, myUseLocalMirrors); + myLogger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(mySettings.getPassword()))); + new PullCommand(mySettings, workingDir).execute(myPullTimeout); + myLogger.message("Changes successfully pulled"); + } + + + private void ensureUseRightRepository(File workingDir) throws VcsException { + boolean clonedFromWrongRepository = myUseLocalMirrors && !isClonedFromLocalMirror(workingDir) + || !myUseLocalMirrors && isClonedFromLocalMirror(workingDir); + + if (clonedFromWrongRepository) { + String rightRepository = myUseLocalMirrors ? "local mirror" : "remote repository"; + String wrongRepository = myUseLocalMirrors ? "remote repository" : "local mirror"; + myLogger.message("Repository in working directory is cloned from " + wrongRepository + ", clone it from " + rightRepository); + FileUtil.delete(workingDir); + initRepository(mySettings, workingDir, myUseLocalMirrors); + } + } + + + private void updateLocalMirror() throws VcsException, IOException { + Settings settings = new Settings(myHgPathProvider, myRoot); + File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepositoryUrl()); + myLogger.message("Update local mirror at " + mirrorDir); + if (!Settings.isValidRepository(mirrorDir)) { + initRepository(settings, mirrorDir, false); + } + final String defaultPullUrl = getDefaultPullUrl(settings, true); + myLogger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); + new PullCommand(settings, mirrorDir).execute(myPullTimeout); + myLogger.message("Local mirror changes successfully pulled"); + } + + + private void updateWorkingDir(@NotNull final File workingDir) throws VcsException, IOException { + String workingDirRevision = getWorkingDirRevision(mySettings, workingDir); + if (isInitialClone(workingDirRevision)) { + doUpdateWorkingDir(workingDir); + } else { + Map<String, Pair<String, String>> currentSubrepos = getSubrepositories(workingDir, workingDirRevision); + if (currentSubrepos.isEmpty()) { + doUpdateWorkingDir(workingDir); + } else { + Map<String, Pair<String, String>> toVersionSubrepos = getSubrepositories(workingDir, myToVersion); + Map<String, Pair<String, String>> subrepositoriesWithChangedUrls = getSubrepositoriesWithChangedUrls(currentSubrepos, toVersionSubrepos); + if (subrepositoriesWithChangedUrls.isEmpty()) { + doUpdateWorkingDir(workingDir); + } else { + logSubrepositoriesUrlsChanged(workingDirRevision, myToVersion, subrepositoriesWithChangedUrls); + FileUtil.delete(workingDir); + updateRepository(workingDir); + doUpdateWorkingDir(workingDir); + } + } + } + } + + + private void logSubrepositoriesUrlsChanged(@NotNull final String fromVersion, + @NotNull final String toVersion, + @NotNull final Map<String, Pair<String, String>> subrepositoriesWithChangedUrls) { + StringBuilder sb = new StringBuilder(); + sb.append("Subrepositories' URLs were changed between revisions ").append(fromVersion).append("..").append(toVersion).append(":\n"); + for (Map.Entry<String, Pair<String, String>> entry : subrepositoriesWithChangedUrls.entrySet()) { + String path = entry.getKey(); + String oldUrl = entry.getValue().first; + String newUrl = entry.getValue().second; + sb.append("path: \"").append(path).append("\", old URL: \"").append(oldUrl).append("\", new URL: \"").append(newUrl).append("\";\n"); + } + sb.append("do clean checkout."); + myLogger.warning(sb.toString()); + } + + + /*returns map: relative path -> (repository url, repository revision)*/ + private Map<String, Pair<String, String>> getSubrepositories(@NotNull final File workingDir, @NotNull final String revision) throws VcsException, IOException { + CatCommand cc = new CatCommand(mySettings, workingDir); + cc.setRevId(revision); + try { + File parentDir = cc.execute(Arrays.asList(".hgsub", ".hgsubstate"), false); + File hgsub = new File(parentDir, ".hgsub"); + File hgsubstate = new File(parentDir, ".hgsubstate"); + return readSubrepositories(hgsub, hgsubstate); + } catch (VcsException e) { + return Collections.emptyMap(); + } + } + + + private Map<String, Pair<String, String>> readSubrepositories(@NotNull final File hgsub, @NotNull final File hgsubstate) throws IOException { + if (hgsub.exists() && hgsubstate.exists()) { + Map<String, String> path2repo = readHgsub(hgsub); + Map<String, String> path2revision = readHgsubstate(hgsubstate); + Map<String, Pair<String, String>> result = new HashMap<String, Pair<String, String>>(); + for (Map.Entry<String, String> entry : path2repo.entrySet()) { + String path = entry.getKey(); + String repo = entry.getValue(); + String revision = path2revision.get(path); + if (revision != null) { + result.put(path, Pair.create(repo, revision)); + } else { + myLogger.warning("Cannot find revision for subrepository at path " + path + " skip it"); + } + } + return result; + } else { + return Collections.emptyMap(); + } + } + + + /*returns map: relative path -> repository url */ + private Map<String, String> readHgsub(@NotNull final File hgsub) throws IOException { + Map<String, String> result = new HashMap<String, String>(); + for (String line : FileUtil.readFile(hgsub)) { + String[] parts = line.split(" = "); + if (parts.length == 2) { + result.put(parts[0], parts[1]); + } else { + myLogger.warning("Cannot parse the line '" + line + "' from .hgsub, skip it"); + } + } + return result; + } + + + /*returns map: relative path -> revision */ + private Map<String, String> readHgsubstate(@NotNull final File hgsubstate) throws IOException { + Map<String, String> result = new HashMap<String, String>(); + for (String line : FileUtil.readFile(hgsubstate)) { + String[] parts = line.split(" "); + if (parts.length == 2) { + result.put(parts[1], parts[0]); + } else { + myLogger.warning("Cannot parse the line '" + line + "' from .hgsubstate, skip it"); + } + } + return result; + } + + + /*returns map repository path -> (old url, new url)*/ + private Map<String, Pair<String, String>> getSubrepositoriesWithChangedUrls(@NotNull final Map<String, Pair<String, String>> subrepos1, @NotNull final Map<String, Pair<String, String>> subrepos2) { + Map<String, Pair<String, String>> result = new HashMap<String, Pair<String, String>>(); + for (Map.Entry<String, Pair<String, String>> entry : subrepos1.entrySet()) { + String path = entry.getKey(); + String url1 = entry.getValue().first; + Pair<String, String> urlRevision = subrepos2.get(path); + if (urlRevision != null && !url1.equals(urlRevision.first)) + result.put(path, Pair.create(url1, urlRevision.first)); + } + return result; + } + + + private boolean isInitialClone(@NotNull final String workingDirRevision) { + return "000000000000".equals(workingDirRevision); + } + + + private String getWorkingDirRevision(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { + IdentifyCommand id = new IdentifyCommand(settings, workingDir); + id.setInLocalRepository(true); + return id.execute(); + } + + + private void doUpdateWorkingDir(@NotNull final File workingDir) throws VcsException { + myLogger.message("Updating folder " + workingDir.getAbsolutePath() + " to revision " + myToVersion); + UpdateCommand uc = new UpdateCommand(mySettings, workingDir); + ChangeSet cs = new ChangeSet(myToVersion); + uc.setToId(cs.getId()); + uc.execute(); + myLogger.message("Folder successfully updated"); + } + + + private String getDefaultPullUrl(Settings settings, boolean useLocalMirror) throws IOException { + if (useLocalMirror) { + File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepositoryUrl()); + return mirrorDir.getCanonicalPath(); + } else { + return settings.getRepositoryUrl(); + } + } + + + private void checkRuleIsValid(IncludeRule includeRule) throws VcsException { + if (includeRule.getTo() != null && includeRule.getTo().length() > 0) { + if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) { + throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); + } + } + } + + + public boolean isClonedFromLocalMirror(@NotNull final File workingDir) { + try { + File mirrorDir = myMirrorManager.getMirrorDir(mySettings.getRepositoryUrl()); + File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); + String config = FileUtil.readText(hgrc); + return config.contains("default = " + mirrorDir.getCanonicalPath()); + } catch (Exception e) { + return false; + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Constants.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,30 +1,30 @@ -/* - * Copyright 2000-2011 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.VcsRoot; - -public interface Constants { - String VCS_NAME = "mercurial"; - String REPOSITORY_PROP = "repositoryPath"; - String BRANCH_NAME_PROP = "branchName"; - String HG_COMMAND_PATH_PROP = "hgCommandPath"; - String HG_PATH_ENV = "TEAMCITY_HG_PATH"; - String SERVER_CLONE_PATH_PROP = "serverClonePath"; - String USERNAME = "username"; - String PASSWORD = VcsRoot.SECURE_PROPERTY_PREFIX + "password"; - String UNCOMPRESSED_TRANSFER = "uncompressedTransfer"; -} +/* + * Copyright 2000-2011 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.VcsRoot; + +public interface Constants { + String VCS_NAME = "mercurial"; + String REPOSITORY_PROP = "repositoryPath"; + String BRANCH_NAME_PROP = "branchName"; + String HG_COMMAND_PATH_PROP = "hgCommandPath"; + String HG_PATH_ENV = "TEAMCITY_HG_PATH"; + String SERVER_CLONE_PATH_PROP = "serverClonePath"; + String USERNAME = "username"; + String PASSWORD = VcsRoot.SECURE_PROPERTY_PREFIX + "password"; + String UNCOMPRESSED_TRANSFER = "uncompressedTransfer"; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathProvider.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,13 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public interface HgPathProvider { + + String getHgPath(@NotNull Settings settings); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersion.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,104 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class HgVersion implements Comparable<HgVersion> { + + private static final String PREFIX = "Mercurial Distributed SCM (version "; + + private final int myMajor; + private final int myMinor; + private final int myThird; + + + public HgVersion(int major, int minor, int third) { + myMajor = major; + myMinor = minor; + myThird = third; + } + + + public static HgVersion parse(@NotNull final String version) { + Parser p = new Parser(version); + if (!p.skipString(PREFIX)) + throw new IllegalArgumentException("Incorrect version format: " + version); + int major = p.readInt(); + p.skipString("."); + int minor = p.readInt(); + int third = p.skipString(".") ? p.readInt() : 0; + return new HgVersion(major, minor, third); + } + + + public boolean isEqualsOrGreaterThan(HgVersion other) { + return compareTo(other) >= 0; + } + + + @Override + public String toString() { + return myMajor + "." + myMinor + "." + myThird; + } + + @Override + public boolean equals(Object o) { + return (o instanceof HgVersion) && this.compareTo((HgVersion) o) == 0; + } + + @Override + public int hashCode() { + int result = myMajor; + result = 31 * result + myMinor; + result = 31 * result + myThird; + return result; + } + + public int compareTo(HgVersion other) { + int d = myMajor - other.myMajor; + if (d != 0) + return d; + + d = myMinor - other.myMinor; + if (d != 0) + return d; + + return myThird - other.myThird; + } + + + private static final class Parser { + + private final String myString; + private int myIndex = 0; + + Parser(@NotNull String string) { + myString = string; + } + + + boolean skipString(String str) { + if (myIndex == myString.length() || myIndex + str.length() > myString.length()) + return false; + String substr = myString.substring(myIndex, myIndex + str.length()); + if (substr.equals(str)) { + myIndex = myIndex + str.length(); + return true; + } else { + return false; + } + } + + + int readInt() { + int result = 0; + while (myIndex < myString.length() && Character.isDigit(myString.codePointAt(myIndex))) { + result = result * 10 + Character.digit(myString.codePointAt(myIndex), 10); + myIndex++; + } + return result; + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PathUtil.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,37 +1,37 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; - -public class PathUtil { - @NotNull - public static String normalizeSeparator(@NotNull String repPath) { - return repPath.replace('\\', '/'); - } - - @NotNull - public static File getCanonicalFile(@NotNull File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - return file.getAbsoluteFile(); - } - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +public class PathUtil { + @NotNull + public static String normalizeSeparator(@NotNull String repPath) { + return repPath.replace('\\', '/'); + } + + @NotNull + public static File getCanonicalFile(@NotNull File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + return file.getAbsoluteFile(); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PluginConfig.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/PluginConfig.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,10 +1,15 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + /** * @author dmitry.neverov */ public interface PluginConfig { - int getPullTimeout(); + @NotNull + File getCachesDir(); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -21,7 +21,7 @@ import java.io.File; -public class ArchiveCommand extends BaseCommand { +public class ArchiveCommand extends VcsRootCommand { private File myDestDir; private String myToId;
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,132 +1,113 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.openapi.util.SystemInfo; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.util.StringUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.Collections; -import java.util.Set; - -/** - * @author pavel - */ -public class BaseCommand { - private Settings mySettings; - private String myWorkDirectory; - - public BaseCommand(@NotNull final Settings settings, @NotNull File workingDir) { - mySettings = settings; - myWorkDirectory = workingDir.getAbsolutePath(); - } - - - public Settings getSettings() { - return mySettings; - } - - /** - * Sets new working directory, by default working directory is taken from the Settings#getLocalRepositoryDir - * @param workDirectory work dir - */ - public void setWorkDirectory(final String workDirectory) { - myWorkDirectory = workDirectory; - } - - public String getWorkDirectory() { - return myWorkDirectory; - } - - protected GeneralCommandLine createCommandLine() { - GeneralCommandLine cli = createCL(); - cli.setWorkDirectory(myWorkDirectory); - cli.setPassParentEnvs(true); - return cli; - } - - protected GeneralCommandLine createCL() { - GeneralCommandLine cl = new EscapingCommandLineDecorator(); - setupExecutable(cl); - return cl; - } - - /** - * Escape its parameters - */ - private static class EscapingCommandLineDecorator extends GeneralCommandLine { - @Override - public void addParameter(@NotNull String parameter) { - String escaped = escape(parameter); - super.addParameter(escaped); - } - - private String escape(String s) { - return StringUtil.escapeQuotesIfWindows(s); - } - } - - /** - * Since mercurial 1.7 on Windows the only file inside '<mercurial_install_dir>/bin' is 'hg.cmd' - * which run hg.exe placed in the parent dir. GeneralCommandLine will not find hg.cmd, in the - * case when $PATH contains <mercurial_install_dir>/bin and doesn't contain <mercurial_install_dir> - * and hg executable is set to 'hg'. To fix it - run hg using windows shell which expand - * hg to hg.cmd correctly. - */ - private void setupExecutable(GeneralCommandLine cli) { - if (SystemInfo.isWindows && getSettings().getHgCommandPath().equals("hg")) { - setupCmd(cli); - } else { - setupHg(cli); - } - } - - private void setupCmd(GeneralCommandLine cli) { - cli.setExePath("cmd"); - cli.addParameter("/c"); - cli.addParameter("hg"); - } - - private void setupHg(GeneralCommandLine cli) { - cli.setExePath(getSettings().getHgCommandPath()); - } - - protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { - return CommandUtil.runCommand(cli, getPrivateData()); - } - - protected ExecResult runCommand(@NotNull GeneralCommandLine cli, boolean logErrorsInDebug) throws VcsException { - return CommandUtil.runCommand(cli, CommandUtil.DEFAULT_COMMAND_TIMEOUT_SEC, getPrivateData(), logErrorsInDebug); - } - - protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException { - return CommandUtil.runCommand(cli, executionTimeout, getPrivateData()); - } - - protected void failIfNotEmptyStdErr(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException { - if (!StringUtil.isEmpty(res.getStderr())) { - CommandUtil.commandFailed(cli.getCommandLineString(), res); - } - } - - public Set<String> getPrivateData() { - return Collections.singleton(mySettings.getPassword()); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.util.SystemInfo; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.util.StringUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Collections; + +/** + * @author pavel + */ +public class BaseCommand { + + private final String myHgPath; + private final File myWorkDirectory; + + public BaseCommand(@NotNull final String hgPath, @NotNull File workingDir) { + myHgPath = hgPath; + myWorkDirectory = workingDir; + } + + + public File getWorkDirectory() { + return myWorkDirectory; + } + + protected GeneralCommandLine createCommandLine() { + GeneralCommandLine cli = createCL(); + cli.setWorkDirectory(myWorkDirectory.getAbsolutePath()); + cli.setPassParentEnvs(true); + return cli; + } + + protected GeneralCommandLine createCL() { + GeneralCommandLine cl = new EscapingCommandLineDecorator(); + setupExecutable(cl); + return cl; + } + + /** + * Escape its parameters + */ + private static class EscapingCommandLineDecorator extends GeneralCommandLine { + @Override + public void addParameter(@NotNull String parameter) { + String escaped = escape(parameter); + super.addParameter(escaped); + } + + private String escape(String s) { + return StringUtil.escapeQuotesIfWindows(s); + } + } + + /** + * Since mercurial 1.7 on Windows the only file inside '<mercurial_install_dir>/bin' is 'hg.cmd' + * which run hg.exe placed in the parent dir. GeneralCommandLine will not find hg.cmd, in the + * case when $PATH contains <mercurial_install_dir>/bin and doesn't contain <mercurial_install_dir> + * and hg executable is set to 'hg'. To fix it - run hg using windows shell which expand + * hg to hg.cmd correctly. + * @param cli command line in which to setup hg executable + */ + private void setupExecutable(GeneralCommandLine cli) { + if (SystemInfo.isWindows && myHgPath.equals("hg")) { + setupCmd(cli); + } else { + setupHg(cli); + } + } + + private void setupCmd(GeneralCommandLine cli) { + cli.setExePath("cmd"); + cli.addParameter("/c"); + cli.addParameter("hg"); + } + + private void setupHg(GeneralCommandLine cli) { + cli.setExePath(myHgPath); + } + + protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { + return CommandUtil.runCommand(cli, Collections.<String>emptySet()); + } + + protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException { + return CommandUtil.runCommand(cli, executionTimeout, Collections.<String>emptySet()); + } + + protected void failIfNotEmptyStdErr(@NotNull GeneralCommandLine cli, @NotNull ExecResult res) throws VcsException { + if (!StringUtil.isEmpty(res.getStderr())) { + CommandUtil.commandFailed(cli.getCommandLineString(), res); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,61 +1,61 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * @author Pavel.Sher - * Date: 26.10.2008 - */ -public class BranchesCommand extends BaseCommand { - - public BranchesCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - /** - * Returns map of branch name to latest changeset in that branch - * @return see above - * @throws jetbrains.buildServer.vcs.VcsException if error occurs - */ - public Map<String, ChangeSet> execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("branches"); - ExecResult res = runCommand(cli); - String stdout = res.getStdout(); - Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); - Pattern branchPattern = Pattern.compile("(.*)[\\s]+([0-9]+:[A-Za-z0-9]+).*"); - for (String line: stdout.split("[\r\n]+")) { - Matcher matcher = branchPattern.matcher(line); - if (matcher.matches()) { - String branchName = matcher.group(1).trim(); - String changeId = matcher.group(2).trim(); - result.put(branchName, new ChangeSet(changeId)); - } - } - return result; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Pavel.Sher + * Date: 26.10.2008 + */ +public class BranchesCommand extends VcsRootCommand { + + public BranchesCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + /** + * Returns map of branch name to latest changeset in that branch + * @return see above + * @throws jetbrains.buildServer.vcs.VcsException if error occurs + */ + public Map<String, ChangeSet> execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("branches"); + ExecResult res = runCommand(cli); + String stdout = res.getStdout(); + Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); + Pattern branchPattern = Pattern.compile("(.*)[\\s]+([0-9]+:[A-Za-z0-9]+).*"); + for (String line: stdout.split("[\r\n]+")) { + Matcher matcher = branchPattern.matcher(line); + if (matcher.matches()) { + String branchName = matcher.group(1).trim(); + String changeId = matcher.group(2).trim(); + result.put(branchName, new ChangeSet(changeId)); + } + } + return result; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,88 +1,87 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -public class CatCommand extends BaseCommand { - private String myRevId; - private final static int MAX_CMD_LEN = 900; - private boolean myLogErrorsInDebug = false; - - public CatCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setRevId(final String revId) { - myRevId = revId; - } - - public void setLogErrorsInDebug(boolean doLogErrorsInDebug) { - myLogErrorsInDebug = doLogErrorsInDebug; - } - - public File execute(List<String> relPaths) throws VcsException { - File tempDir; - try { - tempDir = FileUtil.createTempDirectory("mercurial", "catresult"); - } catch (IOException e) { - throw new VcsException("Unable to create temporary directory"); - } - for (String path: relPaths) { - final File parentFile = new File(tempDir, path).getParentFile(); - if (!parentFile.isDirectory() && !parentFile.mkdirs()) { - throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath()); - } - } - - Queue<String> paths = new LinkedList<String>(relPaths); - while (!paths.isEmpty()) { - GeneralCommandLine cli = createCommandLine(tempDir); - int cmdSize = cli.getCommandLineString().length(); - - do { - String path = paths.poll(); - cli.addParameter(path); - cmdSize += path.length(); - } while (cmdSize < MAX_CMD_LEN && !paths.isEmpty()); - - runCommand(cli, myLogErrorsInDebug); - } - - return tempDir; - } - - private GeneralCommandLine createCommandLine(final File tempDir) { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("cat"); - cli.addParameter("-o"); - cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p"); - if (myRevId != null) { - cli.addParameter("-r"); - cli.addParameter(myRevId); - } - return cli; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class CatCommand extends VcsRootCommand { + private String myRevId; + private final static int MAX_CMD_LEN = 900; + + public CatCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setRevId(final String revId) { + myRevId = revId; + } + + public File execute(List<String> relPaths) throws VcsException { + return execute(relPaths, true); + } + + public File execute(List<String> relPaths, boolean checkFailure) throws VcsException { + File tempDir; + try { + tempDir = FileUtil.createTempDirectory("mercurial", "catresult"); + } catch (IOException e) { + throw new VcsException("Unable to create temporary directory"); + } + for (String path: relPaths) { + final File parentFile = new File(tempDir, path).getParentFile(); + if (!parentFile.isDirectory() && !parentFile.mkdirs()) { + throw new VcsException("Failed to create directory: " + parentFile.getAbsolutePath()); + } + } + + Queue<String> paths = new LinkedList<String>(relPaths); + while (!paths.isEmpty()) { + GeneralCommandLine cli = createCommandLine(tempDir); + int cmdSize = cli.getCommandLineString().length(); + + do { + String path = paths.poll(); + cli.addParameter(path); + cmdSize += path.length(); + } while (cmdSize < MAX_CMD_LEN && !paths.isEmpty()); + + runCommand(cli, checkFailure); + } + + return tempDir; + } + + private GeneralCommandLine createCommandLine(final File tempDir) { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("cat"); + cli.addParameter("-o"); + cli.addParameter(tempDir.getAbsolutePath() + File.separator + "%p"); + if (myRevId != null) { + cli.addParameter("-r"); + cli.addParameter(myRevId); + } + return cli; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,115 +1,113 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Represents Mercurial change set - */ -public class ChangeSet extends ChangeSetRevision { - @NotNull private String myUser; - @NotNull private Date myTimestamp; - private String myDescription; - private List<ChangeSetRevision> myParents = new ArrayList<ChangeSetRevision>(); - private List<ModifiedFile> myModifiedFiles = new ArrayList<ModifiedFile>(); - - - public ChangeSet(final int revNumber, @NotNull final String id) { - super(revNumber, id); - } - - /** - * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) - * @param fullVersion full changeset version as reported by hg log command - */ - public ChangeSet(@NotNull final String fullVersion) { - super(fullVersion); - } - - public void setUser(@NotNull final String user) { - myUser = user; - } - - public void setTimestamp(@NotNull final Date timestamp) { - myTimestamp = timestamp; - } - - public void setDescription(final String description) { - myDescription = description; - } - - public void addParent(@NotNull ChangeSetRevision rev) { - myParents.add(rev); - } - - /** - * Returns user who made changeset - * @return user who made changeset - */ - @NotNull - public String getUser() { - return myUser; - } - - /** - * Returns changeset timestamp - * @return changeset timestamp - */ - @NotNull - public Date getTimestamp() { - return myTimestamp; - } - - /** - * Returns changeset summary specified by user - * @return changeset summary - */ - public String getDescription() { - return myDescription; - } - - /** - * Returns parrents of this change set - * @return see above - */ - @NotNull - public List<ChangeSetRevision> getParents() { - return myParents; - } - - /** - * Check if changeset is initial changeset (has no parents) - * @return true if changeset is initial changeset - */ - public boolean isInitial() { - return getParents().isEmpty(); - } - - public void setModifiedFiles(@NotNull final List<ModifiedFile> files) { - myModifiedFiles = files; - } - - @NotNull - public List<ModifiedFile> getModifiedFiles() { - return myModifiedFiles; - } - -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Represents Mercurial change set + */ +public class ChangeSet extends ChangeSetRevision { + @NotNull private String myUser; + @NotNull private Date myTimestamp; + private String myDescription; + private List<ChangeSetRevision> myParents = new ArrayList<ChangeSetRevision>(); + private List<ModifiedFile> myModifiedFiles = new ArrayList<ModifiedFile>(); + + public ChangeSet(final int revNumber, @NotNull final String id) { + super(revNumber, id); + } + + /** + * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) + * @param fullVersion full changeset version as reported by hg log command + */ + public ChangeSet(@NotNull final String fullVersion) { + super(fullVersion); + } + + public void setUser(@NotNull final String user) { + myUser = user; + } + + public void setTimestamp(@NotNull final Date timestamp) { + myTimestamp = timestamp; + } + + public void setDescription(final String description) { + myDescription = description; + } + + public void addParent(@NotNull ChangeSetRevision rev) { + myParents.add(rev); + } + + /** + * Returns user who made changeset + * @return user who made changeset + */ + @NotNull + public String getUser() { + return myUser; + } + + /** + * Returns changeset timestamp + * @return changeset timestamp + */ + @NotNull + public Date getTimestamp() { + return myTimestamp; + } + + /** + * Returns changeset summary specified by user + * @return changeset summary + */ + public String getDescription() { + return myDescription; + } + + /** + * Returns parrents of this change set + * @return see above + */ + @NotNull + public List<ChangeSetRevision> getParents() { + return myParents; + } + + /** + * Check if changeset is initial changeset (has no parents) + * @return true if changeset is initial changeset + */ + public boolean isInitial() { + return getParents().isEmpty(); + } + + public void setModifiedFiles(@NotNull final List<ModifiedFile> files) { + myModifiedFiles = files; + } + + @NotNull + public List<ModifiedFile> getModifiedFiles() { + return myModifiedFiles; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSetRevision.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSetRevision.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,99 +1,99 @@ -/* - * Copyright 2000-2011 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; - -/** - * @author Pavel.Sher - */ -public class ChangeSetRevision { - private final int myRevNumber; - @NotNull - private final String myId; - - public ChangeSetRevision(final int revNumber, @NotNull final String id) { - myRevNumber = revNumber; - myId = id; - } - - /** - * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) - * @param fullVersion full changeset version as reported by hg log command - */ - public ChangeSetRevision(@NotNull final String fullVersion) { - try { - int colon = fullVersion.indexOf(":"); - if (colon != -1) { - myRevNumber = Integer.parseInt(fullVersion.substring(0, colon)); - myId = fullVersion.substring(colon+1); - } else { - myRevNumber = -1; - myId = fullVersion; - } - } catch (Throwable e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Returns changeset revision id - * @return changeset revision id - */ - @NotNull - public String getId() { - return myId; - } - - /** - * Returns changeset revision number - * @return changeset revision number - */ - public int getRevNumber() { - return myRevNumber; - } - - /** - * Returns full changeset version as reported by hg log command: revnum:revid - * @return full changeset version as reported by hg log - */ - @NotNull - public String getFullVersion() { - return myRevNumber + ":" + myId; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final ChangeSetRevision that = (ChangeSetRevision) o; - - return myRevNumber == that.myRevNumber && myId.equals(that.myId); - } - - @Override - public int hashCode() { - int result = myRevNumber; - result = 31 * result + myId.hashCode(); - return result; - } - - @Override - public String toString() { - return "change:" + myId; - } -} +/* + * Copyright 2000-2011 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; + +/** + * @author Pavel.Sher + */ +public class ChangeSetRevision { + private final int myRevNumber; + @NotNull + private final String myId; + + public ChangeSetRevision(final int revNumber, @NotNull final String id) { + myRevNumber = revNumber; + myId = id; + } + + /** + * Constructor for version in the form revnum:changeset_id or just changeset_id (in this case rev number is set to -1) + * @param fullVersion full changeset version as reported by hg log command + */ + public ChangeSetRevision(@NotNull final String fullVersion) { + try { + int colon = fullVersion.indexOf(":"); + if (colon != -1) { + myRevNumber = Integer.parseInt(fullVersion.substring(0, colon)); + myId = fullVersion.substring(colon+1); + } else { + myRevNumber = -1; + myId = fullVersion; + } + } catch (Throwable e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Returns changeset revision id + * @return changeset revision id + */ + @NotNull + public String getId() { + return myId; + } + + /** + * Returns changeset revision number + * @return changeset revision number + */ + public int getRevNumber() { + return myRevNumber; + } + + /** + * Returns full changeset version as reported by hg log command: revnum:revid + * @return full changeset version as reported by hg log + */ + @NotNull + public String getFullVersion() { + return myRevNumber + ":" + myId; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ChangeSetRevision that = (ChangeSetRevision) o; + + return myRevNumber == that.myRevNumber && myId.equals(that.myId); + } + + @Override + public int hashCode() { + int result = myRevNumber; + result = 31 * result + myId.hashCode(); + return result; + } + + @Override + public String toString() { + return "change:" + myId; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangedFilesCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangedFilesCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,76 +1,76 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * @author Pavel.Sher - */ -public class ChangedFilesCommand extends BaseCommand { - private String myRevId; - - public ChangedFilesCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setRevId(@NotNull final String revId) { - myRevId = revId; - } - - public List<ModifiedFile> execute() throws VcsException { - File styleFile; - try { - styleFile = getStyleFile(); - } catch (IOException e) { - throw new VcsException("Unable to create style file: " + e.toString(), e); - } - try { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("log"); - cli.addParameter("-r"); - cli.addParameter(myRevId + ":" + myRevId); - cli.addParameter("--style=" + styleFile.getAbsolutePath()); - - ExecResult res = runCommand(cli); - return parseFiles(res.getStdout()); - } finally { - FileUtil.delete(styleFile); - } - } - - private File getStyleFile() throws IOException { - File styleFile = FileUtil.createTempFile("hg", "style"); - FileUtil.writeFile(styleFile, - "changeset = \"{file_mods}{file_adds}{file_dels}\"\n" + - "file_add = \"A {file_add}\\n\"\n" + - "file_del = \"R {file_del}\\n\"\n" + - "file_mod = \"M {file_mod}\\n\""); - return styleFile; - } - - private List<ModifiedFile> parseFiles(final String stdout) { - return StatusCommand.parseFiles(stdout); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * @author Pavel.Sher + */ +public class ChangedFilesCommand extends VcsRootCommand { + private String myRevId; + + public ChangedFilesCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setRevId(@NotNull final String revId) { + myRevId = revId; + } + + public List<ModifiedFile> execute() throws VcsException { + File styleFile; + try { + styleFile = getStyleFile(); + } catch (IOException e) { + throw new VcsException("Unable to create style file: " + e.toString(), e); + } + try { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("log"); + cli.addParameter("-r"); + cli.addParameter(myRevId + ":" + myRevId); + cli.addParameter("--style=" + styleFile.getAbsolutePath()); + + ExecResult res = runCommand(cli); + return parseFiles(res.getStdout()); + } finally { + FileUtil.delete(styleFile); + } + } + + private File getStyleFile() throws IOException { + File styleFile = FileUtil.createTempFile("hg", "style"); + FileUtil.writeFile(styleFile, + "changeset = \"{file_mods}{file_adds}{file_dels}\"\n" + + "file_add = \"A {file_add}\\n\"\n" + + "file_del = \"R {file_del}\\n\"\n" + + "file_mod = \"M {file_mod}\\n\""); + return styleFile; + } + + private List<ModifiedFile> parseFiles(final String stdout) { + return StatusCommand.parseFiles(stdout); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,80 +1,80 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -public class CloneCommand extends BaseCommand{ - private String myToId; - private boolean myUpdateWorkingDir = true; - private String myRepository; - private File myWorkingDir; - private boolean myUsePullProtocol = true; - - public CloneCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - myWorkingDir = workingDir; - myRepository = getSettings().getRepositoryUrl(); - } - - /** - * Sets repository to clone, by default uses repository from the specified settings - * @param repo repository path - */ - public void setRepository(@NotNull String repo) { - myRepository = repo; - } - - public void setToId(final String toId) { - myToId = toId; - } - - public void setUpdateWorkingDir(final boolean updateWorkingDir) { - myUpdateWorkingDir = updateWorkingDir; - } - - public void setUsePullProtocol(boolean usePullProtocol) { - myUsePullProtocol = usePullProtocol; - } - - public void execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - File parent = myWorkingDir.getParentFile(); - cli.setWorkDirectory(parent.getAbsolutePath()); - cli.addParameter("clone"); - if (myToId != null) { - cli.addParameter("-r"); - cli.addParameter(myToId); - } - if (myUsePullProtocol) - cli.addParameter("--pull"); - if (!myUpdateWorkingDir) { - cli.addParameter("-U"); - } - if (getSettings().isUncompressedTransfer()) { - cli.addParameter("--uncompressed"); - } - cli.addParameter(myRepository); - cli.addParameter(myWorkingDir.getName()); - - ExecResult res = runCommand(cli, 24*3600); // some repositories are quite large, we set timeout to 24 hours - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class CloneCommand extends VcsRootCommand { + private String myToId; + private boolean myUpdateWorkingDir = true; + private String myRepository; + private File myWorkingDir; + private boolean myUsePullProtocol = true; + + public CloneCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + myWorkingDir = workingDir; + myRepository = getSettings().getRepositoryUrl(); + } + + /** + * Sets repository to clone, by default uses repository from the specified settings + * @param repo repository path + */ + public void setRepository(@NotNull String repo) { + myRepository = repo; + } + + public void setToId(final String toId) { + myToId = toId; + } + + public void setUpdateWorkingDir(final boolean updateWorkingDir) { + myUpdateWorkingDir = updateWorkingDir; + } + + public void setUsePullProtocol(boolean usePullProtocol) { + myUsePullProtocol = usePullProtocol; + } + + public void execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + File parent = myWorkingDir.getParentFile(); + cli.setWorkDirectory(parent.getAbsolutePath()); + cli.addParameter("clone"); + if (myToId != null) { + cli.addParameter("-r"); + cli.addParameter(myToId); + } + if (myUsePullProtocol) + cli.addParameter("--pull"); + if (!myUpdateWorkingDir) { + cli.addParameter("-U"); + } + if (getSettings().isUncompressedTransfer()) { + cli.addParameter("--uncompressed"); + } + cli.addParameter(myRepository); + cli.addParameter(myWorkingDir.getName()); + + ExecResult res = runCommand(cli, 24*3600); // some repositories are quite large, we set timeout to 24 hours + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,141 +1,136 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.SimpleCommandLineProcessRunner; -import jetbrains.buildServer.log.Loggers; -import jetbrains.buildServer.util.StringUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.Set; - -public class CommandUtil { - public static final int DEFAULT_COMMAND_TIMEOUT_SEC = 3600; - - public static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res) throws VcsException { - checkCommandFailed(cmdName, res, false); - } - - private static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res, boolean logErrorsInDebug) throws VcsException { - if (logErrorsInDebug) { - if (res.getExitCode() != 0 || res.getException() != null) - Loggers.VCS.debug(createCommandLogMessage(cmdName, res)); - } else { - if (res.getExitCode() != 0 || res.getException() != null) - commandFailed(cmdName, res); - if (res.getStderr().length() > 0) { - Loggers.VCS.warn("Error output produced by: " + cmdName); - Loggers.VCS.warn(res.getStderr()); - } - } - } - - public static void commandFailed(final String cmdName, final ExecResult res) throws VcsException { - final String message = createCommandLogMessage(cmdName, res); - Loggers.VCS.warn(message); - if (hasImportantException(res)) { - Loggers.VCS.error("Error during executing '" + cmdName + "'", res.getException()); - } - throw new VcsException(message); - } - - private static String createCommandLogMessage(final String cmdName, final ExecResult res) { - String stderr = res.getStderr(); - String stdout = res.getStdout(); - String exceptionMessage = getExceptionMessage(res); - return "'" + cmdName + "' command failed.\n" + - (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") + - (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") + - (exceptionMessage != null ? "exception: " + exceptionMessage : ""); - } - - @Nullable - private static String getExceptionMessage(ExecResult result) { - Throwable exception = result.getException(); - String message = null; - if (exception != null) { - message = exception.getMessage(); - if (message == null) { - message = exception.getClass().getName(); - } - } - return message; - } - - private static boolean hasImportantException(ExecResult result) { - Throwable exception = result.getException(); - if (exception != null) { - return exception instanceof NullPointerException; - } else { - return false; - } - } - - public static ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { - return runCommand(cli, DEFAULT_COMMAND_TIMEOUT_SEC, Collections.<String>emptySet()); - } - - public static ExecResult runCommand(@NotNull GeneralCommandLine cli, @NotNull Set<String> privateData) throws VcsException { - return runCommand(cli, DEFAULT_COMMAND_TIMEOUT_SEC, privateData); - } - - public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData) throws VcsException { - return runCommand(cli, executionTimeout, privateData, false); - } - - public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData, boolean logErrorsInDebug) throws VcsException { - final String cmdStr = removePrivateData(cli.getCommandLineString(), privateData); - Loggers.VCS.debug("Run command: " + cmdStr); - final long start = System.currentTimeMillis(); - ExecResult res = SimpleCommandLineProcessRunner.runCommand(cli, null, new SimpleCommandLineProcessRunner.RunCommandEventsAdapter() { - @Override - public Integer getOutputIdleSecondsTimeout() { - return executionTimeout; - } - @Override - public void onProcessFinished(Process ps) { - long duration = System.currentTimeMillis() - start; - Loggers.VCS.debug("Command " + cmdStr + " took " + duration + "ms"); - } - }); - - removePrivateData(privateData, res); - - CommandUtil.checkCommandFailed(cmdStr, res, logErrorsInDebug); - Loggers.VCS.debug("Command " + cmdStr + " output:\n" + res.getStdout()); - return res; - } - - private static void removePrivateData(final Set<String> privateData, final ExecResult res) { - res.setStdout(removePrivateData(res.getStdout(), privateData)); - res.setStderr(removePrivateData(res.getStderr(), privateData)); - } - - public static String removePrivateData(final String str, final Set<String> privateData) { - String result = str; - for (String data: privateData) { - if (data == null || data.length() == 0) continue; - result = result.replace(data, "******"); - } - - return result; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.SimpleCommandLineProcessRunner; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.StringUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Set; + +public class CommandUtil { + private static final int DEFAULT_COMMAND_TIMEOUT_SEC = 3600; + + public static void checkCommandFailed(@NotNull String cmdName, @NotNull ExecResult res) throws VcsException { + if (res.getExitCode() != 0 || res.getException() != null) + commandFailed(cmdName, res); + if (res.getStderr().length() > 0) { + Loggers.VCS.warn("Error output produced by: " + cmdName); + Loggers.VCS.warn(res.getStderr()); + } + } + + public static void commandFailed(final String cmdName, final ExecResult res) throws VcsException { + final String message = createCommandLogMessage(cmdName, res); + Loggers.VCS.warn(message); + if (hasImportantException(res)) + Loggers.VCS.error("Error during executing '" + cmdName + "'", res.getException()); + throw new VcsException(message); + } + + private static String createCommandLogMessage(final String cmdName, final ExecResult res) { + String stderr = res.getStderr(); + String stdout = res.getStdout(); + String exceptionMessage = getExceptionMessage(res); + return "'" + cmdName + "' command failed.\n" + + (!StringUtil.isEmpty(stdout) ? "stdout: " + stdout + "\n" : "") + + (!StringUtil.isEmpty(stderr) ? "stderr: " + stderr + "\n" : "") + + (exceptionMessage != null ? "exception: " + exceptionMessage : ""); + } + + @Nullable + private static String getExceptionMessage(ExecResult result) { + Throwable exception = result.getException(); + String message = null; + if (exception != null) { + message = exception.getMessage(); + if (message == null) { + message = exception.getClass().getName(); + } + } + return message; + } + + private static boolean hasImportantException(ExecResult result) { + Throwable exception = result.getException(); + if (exception != null) { + return exception instanceof NullPointerException; + } else { + return false; + } + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { + return runCommand(cli, DEFAULT_COMMAND_TIMEOUT_SEC, Collections.<String>emptySet()); + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli, @NotNull Set<String> privateData) throws VcsException { + return runCommand(cli, DEFAULT_COMMAND_TIMEOUT_SEC, privateData); + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData) throws VcsException { + return runCommand(cli, executionTimeout, privateData, true); + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli, @NotNull Set<String> privateData, final boolean checkFailure) throws VcsException { + return runCommand(cli, DEFAULT_COMMAND_TIMEOUT_SEC, privateData, checkFailure); + } + + public static ExecResult runCommand(@NotNull GeneralCommandLine cli, final int executionTimeout, @NotNull Set<String> privateData, final boolean checkFailure) throws VcsException { + final String cmdStr = removePrivateData(cli.getCommandLineString(), privateData); + Loggers.VCS.debug("Run command: " + cmdStr); + final long start = System.currentTimeMillis(); + ExecResult res = SimpleCommandLineProcessRunner.runCommand(cli, null, new SimpleCommandLineProcessRunner.RunCommandEventsAdapter() { + @Override + public Integer getOutputIdleSecondsTimeout() { + return executionTimeout; + } + @Override + public void onProcessFinished(Process ps) { + long duration = System.currentTimeMillis() - start; + Loggers.VCS.debug("Command " + cmdStr + " took " + duration + "ms"); + } + }); + + removePrivateData(privateData, res); + + if (checkFailure) + CommandUtil.checkCommandFailed(cmdStr, res); + Loggers.VCS.debug("Command " + cmdStr + " output:\n" + res.getStdout()); + return res; + } + + private static void removePrivateData(final Set<String> privateData, final ExecResult res) { + res.setStdout(removePrivateData(res.getStdout(), privateData)); + res.setStderr(removePrivateData(res.getStderr(), privateData)); + } + + public static String removePrivateData(final String str, final Set<String> privateData) { + String result = str; + for (String data: privateData) { + if (data == null || data.length() == 0) continue; + result = result.replace(data, "******"); + } + + return result; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,62 +1,71 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -/** - * @author Pavel.Sher - * Date: 16.07.2008 - */ -public class IdentifyCommand extends BaseCommand { - - private boolean myInLocalRepository = false; - private ChangeSet myChangeSet; - - public IdentifyCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setInLocalRepository(boolean inLocalRepository) { - myInLocalRepository = inLocalRepository; - } - - public void setChangeSet(ChangeSet changeSet) { - myChangeSet = changeSet; - } - - public String execute() throws VcsException { - GeneralCommandLine cli = createCL(); - cli.addParameter("identify"); - if (myInLocalRepository) { - cli.setWorkDirectory(this.getWorkDirectory()); - } else { - cli.addParameter(getSettings().getRepositoryUrl()); - } - if (myChangeSet != null) { - cli.addParameter("--rev"); - cli.addParameter(myChangeSet.getId()); - } - ExecResult res = runCommand(cli); - failIfNotEmptyStdErr(cli, res); - return res.getStdout(); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author Pavel.Sher + * Date: 16.07.2008 + */ +public class IdentifyCommand extends VcsRootCommand { + + private boolean myInLocalRepository = false; + private ChangeSet myChangeSet; + private Integer myRevisionNumber; + + public IdentifyCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setInLocalRepository(boolean inLocalRepository) { + myInLocalRepository = inLocalRepository; + } + + public void setChangeSet(ChangeSet changeSet) { + myChangeSet = changeSet; + } + + public void setRevisionNumber(int revisionNumber) { + myRevisionNumber = revisionNumber; + } + + public String execute() throws VcsException { + GeneralCommandLine cli = createCL(); + cli.addParameter("identify"); + if (myInLocalRepository) { + cli.setWorkDirectory(this.getWorkDirectory().getAbsolutePath()); + } else { + cli.addParameter(getSettings().getRepositoryUrl()); + } + if (myChangeSet != null) { + cli.addParameter("--rev"); + cli.addParameter(myChangeSet.getId()); + } else if (myRevisionNumber != null) { + cli.addParameter("--rev"); + cli.addParameter(myRevisionNumber.toString()); + } + ExecResult res = runCommand(cli); + failIfNotEmptyStdErr(cli, res); + String output = res.getStdout().trim(); + return output.contains(" ") ? output.substring(0, output.indexOf(" ")) : output; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Init.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Init.java Fri Dec 02 15:35:00 2011 +0300 @@ -10,7 +10,7 @@ /** * @author dmitry.neverov */ -public class Init extends BaseCommand { +public class Init extends VcsRootCommand { private final String myDefaultPullUrl; @@ -20,7 +20,7 @@ } public void execute() throws VcsException { - new File(getWorkDirectory()).mkdirs(); + getWorkDirectory().mkdirs(); GeneralCommandLine cli = createCommandLine(); cli.addParameter("init"); runCommand(cli);
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,196 +1,232 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.openapi.util.JDOMUtil; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; - -public class LogCommand extends BaseCommand { - - private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z"; - - private String myFromId; - private String myToId; - private Integer myLimit = null; - private String myBranchName; - private final File myTemplate; - - public LogCommand(@NotNull Settings settings, @NotNull File workingDir, @NotNull final File template) { - super(settings, workingDir); - myTemplate = template; - myBranchName = settings.getBranchName(); - } - - public void setFromRevId(String id) { - myFromId = id; - } - - public void setToRevId(String id) { - myToId = id; - } - - public void setLimit(final int limit) { - myLimit = limit; - } - - public void setBranchName(String branchName) { - myBranchName = branchName; - } - - public List<ChangeSet> execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("log"); - cli.addParameter("--style=" + myTemplate.getAbsolutePath()); - if (myBranchName != null) { - cli.addParameter("-b"); - cli.addParameter(getSettings().getBranchName()); - } - cli.addParameter("-r"); - String from = myFromId; - if (from == null) from = "0"; - String to = myToId; - if (to == null) to = "tip"; - cli.addParameter(from + ":" + to); - if (myLimit != null) { - cli.addParameter("--limit"); - cli.addParameter(myLimit.toString()); - } - ExecResult res = runCommand(cli); - try { - return parseChangeSetsXml(res.getStdout()); - } catch (Exception e) { - throw new VcsException("Error while parsing log output:\n" + res.getStdout(), e); - } - } - - - private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws JDOMException, IOException, ParseException { - if ("".equals(xml)) - return Collections.emptyList(); - Document doc = JDOMUtil.loadDocument(xml); - Element log = doc.getRootElement(); - return parseLog(log); - } - - - private List<ChangeSet> parseLog(@NotNull final Element logElement) throws ParseException { - List<ChangeSet> result = new ArrayList<ChangeSet>(); - for (Object o : logElement.getChildren("logentry")) { - Element entry = (Element) o; - result.add(parseLogEntry(entry)); - } - return result; - } - - - - private ChangeSet parseLogEntry(@NotNull final Element logEntry) throws ParseException { - ChangeSet cset = new ChangeSet(getRevision(logEntry), getId(logEntry)); - addParents(cset, logEntry); - cset.setUser(getAuthor(logEntry)); - cset.setDescription(getDescription(logEntry)); - cset.setTimestamp(getDate(logEntry)); - cset.setModifiedFiles(getModifiedFiles(logEntry)); - return cset; - } - - - private int getRevision(@NotNull final Element logEntry) { - return Integer.parseInt(logEntry.getAttribute("revision").getValue()); - } - - - private String getId(@NotNull final Element logEntry) { - return logEntry.getAttribute("shortnode").getValue(); - } - - - private void addParents(@NotNull final ChangeSet cset, @NotNull final Element logEntry) { - List parents = logEntry.getChildren("parent"); - for (Object p : parents) { - Element parent = (Element) p; - ChangeSetRevision parentCset = getParent(parent); - cset.addParent(parentCset); - } - } - - - private ChangeSetRevision getParent(@NotNull final Element parent) { - return new ChangeSetRevision(getRevision(parent), getId(parent)); - } - - - private String getAuthor(@NotNull final Element logEntry) { - Element author = logEntry.getChild("author"); - return author.getAttribute("original").getValue(); - } - - - private String getDescription(@NotNull final Element logEntry) { - Element msg = logEntry.getChild("msg"); - return msg.getText(); - } - - - private Date getDate(@NotNull final Element logEntry) throws ParseException { - Element date = logEntry.getChild("date"); - return new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH).parse(date.getText()); - } - - - private List<ModifiedFile> getModifiedFiles(@NotNull final Element logEntry) { - List<ModifiedFile> result = new ArrayList<ModifiedFile>(); - Element paths = logEntry.getChild("paths"); - for (Object o : paths.getChildren("path")) { - Element path = (Element) o; - result.add(getModifiedFile(path)); - } - return result; - } - - - private ModifiedFile getModifiedFile(@NotNull final Element path) { - String filePath = path.getText(); - ModifiedFile.Status status = getStatus(path); - return new ModifiedFile(status, filePath); - } - - - private ModifiedFile.Status getStatus(@NotNull final Element path) { - String action = path.getAttribute("action").getValue(); - if (action.equals("A")) { - return ModifiedFile.Status.ADDED; - } else if (action.equals("M")) { - return ModifiedFile.Status.MODIFIED; - } else if (action.equals("R")) { - return ModifiedFile.Status.REMOVED; - } else { - return ModifiedFile.Status.UNKNOWN; - } - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.util.JDOMUtil; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +public class LogCommand extends VcsRootCommand { + + private final static String ZERO_PARENT_ID = "0000000000000000000000000000000000000000"; + private static final String DATE_FORMAT = "EEE MMM d HH:mm:ss yyyy Z"; + + private String myFromId; + private String myToId; + private Integer myLimit = null; + private String myBranchName; + private boolean myCalculateParents = true; + private String myRevsets; + private final File myTemplate; + + public LogCommand(@NotNull Settings settings, @NotNull File workingDir, @NotNull final File template) { + super(settings, workingDir); + myTemplate = template; + myBranchName = settings.getBranchName(); + } + + public void setFromRevId(String id) { + myFromId = id; + } + + public void setToRevId(String id) { + myToId = id; + } + + public void setLimit(final int limit) { + myLimit = limit; + } + + public void showCommitsFromAllBranches() { + myBranchName = null; + } + + public void setCalculateParents(boolean doCalculate) { + myCalculateParents = doCalculate; + } + + public void setRevsets(String revsets) { + myRevsets = revsets; + } + + public List<ChangeSet> execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("log"); + cli.addParameter("-v"); + cli.addParameter("--style=" + myTemplate.getAbsolutePath()); + if (myBranchName != null) { + cli.addParameter("-b"); + cli.addParameter(getSettings().getBranchName()); + } + 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()); + } + + ExecResult res = runCommand(cli); + try { + List<ChangeSet> changes = parseChangeSetsXml(res.getStdout()); + if (myCalculateParents) + assignTrivialParents(changes); + return changes; + } catch (Exception e) { + throw new VcsException("Error while parsing log output:\n" + res.getStdout(), e); + } + } + + + private List<ChangeSet> parseChangeSetsXml(@NotNull final String xml) throws JDOMException, IOException, ParseException { + if ("".equals(xml)) + return Collections.emptyList(); + Document doc = JDOMUtil.loadDocument(xml); + Element log = doc.getRootElement(); + return parseLog(log); + } + + + private List<ChangeSet> parseLog(@NotNull final Element logElement) throws ParseException { + List<ChangeSet> result = new ArrayList<ChangeSet>(); + for (Object o : logElement.getChildren("logentry")) { + Element entry = (Element) o; + result.add(parseLogEntry(entry)); + } + return result; + } + + + private ChangeSet parseLogEntry(@NotNull final Element logEntry) throws ParseException { + ChangeSet cset = new ChangeSet(getRevision(logEntry), getId(logEntry)); + addParents(cset, logEntry); + cset.setUser(getAuthor(logEntry)); + cset.setDescription(getDescription(logEntry)); + cset.setTimestamp(getDate(logEntry)); + cset.setModifiedFiles(getModifiedFiles(logEntry)); + return cset; + } + + + private int getRevision(@NotNull final Element logEntry) { + return Integer.parseInt(logEntry.getAttribute("revision").getValue()); + } + + + private String getId(@NotNull final Element logEntry) { + return logEntry.getAttribute("shortnode").getValue(); + } + + + private void addParents(@NotNull final ChangeSet cset, @NotNull final Element logEntry) { + List parents = logEntry.getChildren("parent"); + for (Object p : parents) { + Element parent = (Element) p; + ChangeSetRevision parentCset = getParent(parent); + cset.addParent(parentCset); + } + } + + + private ChangeSetRevision getParent(@NotNull final Element parent) { + return new ChangeSetRevision(getRevision(parent), getId(parent)); + } + + + private String getAuthor(@NotNull final Element logEntry) { + Element author = logEntry.getChild("author"); + return author.getAttribute("original").getValue(); + } + + + private String getDescription(@NotNull final Element logEntry) { + Element msg = logEntry.getChild("msg"); + return msg.getText(); + } + + + private Date getDate(@NotNull final Element logEntry) throws ParseException { + Element date = logEntry.getChild("date"); + return new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH).parse(date.getText()); + } + + + private List<ModifiedFile> getModifiedFiles(@NotNull final Element logEntry) { + List<ModifiedFile> result = new ArrayList<ModifiedFile>(); + Element paths = logEntry.getChild("paths"); + for (Object o : paths.getChildren("path")) { + Element path = (Element) o; + result.add(getModifiedFile(path)); + } + return result; + } + + + private ModifiedFile getModifiedFile(@NotNull final Element path) { + String filePath = path.getText(); + ModifiedFile.Status status = getStatus(path); + return new ModifiedFile(status, filePath); + } + + + private ModifiedFile.Status getStatus(@NotNull final Element path) { + String action = path.getAttribute("action").getValue(); + if (action.equals("A")) { + return ModifiedFile.Status.ADDED; + } else if (action.equals("M")) { + return ModifiedFile.Status.MODIFIED; + } else if (action.equals("R")) { + return ModifiedFile.Status.REMOVED; + } else { + return ModifiedFile.Status.UNKNOWN; + } + } + + private void assignTrivialParents(final @NotNull List<ChangeSet> csets) throws VcsException { + for (ChangeSet cset : csets) { + if (cset.getParents().isEmpty()) { + int parentRevNumber = cset.getRevNumber() - 1; + String parentId = getIdOf(parentRevNumber); + cset.addParent(new ChangeSetRevision(parentRevNumber, parentId)); + } + } + } + + private String getIdOf(int revNumber) throws VcsException { + if (revNumber < 0) + return ZERO_PARENT_ID; + IdentifyCommand identify = new IdentifyCommand(getSettings(), getWorkDirectory()); + identify.setInLocalRepository(true); + identify.setRevisionNumber(revNumber); + return identify.execute(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,25 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Analog of git merge-base. It returns a last common ancestor between two revisions. + * + * @author dmitry.neverov + */ +public interface MergeBaseCommand { + + /** + * Returns hash of least common ancestor between two revisions or null + * if common ancestor is not found + * @param revision1 first revision + * @param revision2 second revision + * @return see above + * @throws VcsException if some commands fail + */ + @Nullable + String execute(@NotNull String revision1, @NotNull String revision2) throws VcsException; + +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,86 +1,86 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import org.jetbrains.annotations.NotNull; - -/** - * Represents repository modified file - */ -public class ModifiedFile { - /** - * Type of modification - */ - public static enum Status { - ADDED("added"), - MODIFIED("modified"), - REMOVED("removed"), - UNKNOWN("unknown"); - private String myName; - - Status(@NotNull final String name) { - myName = name; - } - - @NotNull - public String getName() { - return myName; - } - } - - @NotNull private Status myStatus; - @NotNull private String myPath; - - public ModifiedFile(@NotNull final Status status, @NotNull final String path) { - myStatus = status; - myPath = path; - } - - /** - * Returns type of modification - * @return type of modification - */ - @NotNull - public Status getStatus() { - return myStatus; - } - - /** - * Returns file path - * @return file path - */ - @NotNull - public String getPath() { - return myPath; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final ModifiedFile that = (ModifiedFile) o; - - return myPath.equals(that.myPath) && myStatus == that.myStatus; - } - - @Override - public int hashCode() { - int result = myStatus.hashCode(); - result = 31 * result + myPath.hashCode(); - return result; - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents repository modified file + */ +public class ModifiedFile { + /** + * Type of modification + */ + public static enum Status { + ADDED("added"), + MODIFIED("modified"), + REMOVED("removed"), + UNKNOWN("unknown"); + private String myName; + + Status(@NotNull final String name) { + myName = name; + } + + @NotNull + public String getName() { + return myName; + } + } + + @NotNull private Status myStatus; + @NotNull private String myPath; + + public ModifiedFile(@NotNull final Status status, @NotNull final String path) { + myStatus = status; + myPath = path; + } + + /** + * Returns type of modification + * @return type of modification + */ + @NotNull + public Status getStatus() { + return myStatus; + } + + /** + * Returns file path + * @return file path + */ + @NotNull + public String getPath() { + return myPath; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ModifiedFile that = (ModifiedFile) o; + + return myPath.equals(that.myPath) && myStatus == that.myStatus; + } + + @Override + public int hashCode() { + int result = myStatus.hashCode(); + result = 31 * result + myPath.hashCode(); + return result; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,40 +1,40 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -/** - * @author Pavel.Sher - * Date: 14.07.2008 - */ -public class PullCommand extends BaseCommand { - - public PullCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void execute(int timeout) throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("pull"); - cli.addParameter(getSettings().getRepositoryUrl()); - runCommand(cli, timeout); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author Pavel.Sher + * Date: 14.07.2008 + */ +public class PullCommand extends VcsRootCommand { + + public PullCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void execute(int timeout) throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("pull"); + cli.addParameter(getSettings().getRepositoryUrl()); + runCommand(cli, timeout); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,49 +1,49 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -/** - * @author pavel - */ -public class PushCommand extends BaseCommand { - private boolean myForced; - - public PushCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setForce(boolean force) { - myForced = force; - } - - public void execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("push"); - if (myForced) { - cli.addParameter("-f"); - } - cli.addParameter(getSettings().getRepositoryUrl()); - ExecResult res = runCommand(cli); - failIfNotEmptyStdErr(cli, res); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author pavel + */ +public class PushCommand extends VcsRootCommand { + private boolean myForced; + + public PushCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setForce(boolean force) { + myForced = force; + } + + public void execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("push"); + if (myForced) { + cli.addParameter("-f"); + } + cli.addParameter(getSettings().getRepositoryUrl()); + ExecResult res = runCommand(cli); + failIfNotEmptyStdErr(cli, res); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,216 +1,226 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.PathUtil; -import jetbrains.buildServer.log.Loggers; -import jetbrains.buildServer.util.StringUtil; -import jetbrains.buildServer.vcs.VcsRoot; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.IOException; -import java.net.*; -import java.util.HashSet; -import java.util.Set; - -/** - * Represents Mercurial repository settings - */ -public class Settings { - private String myRepository; - private String myHgCommandPath; - private File myCustomWorkingDir; - private String myUsername; - private String myPassword; - private String myBranchName; - private boolean myUncompressedTransfer = false; - private static final String DEFAULT_BRANCH_NAME = "default"; - private String myCustomClonePath; - - public Settings(@NotNull VcsRoot vcsRoot) { - myRepository = vcsRoot.getProperty(Constants.REPOSITORY_PROP); - myHgCommandPath = vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP); - myBranchName = vcsRoot.getProperty(Constants.BRANCH_NAME_PROP); - myCustomClonePath = vcsRoot.getProperty(Constants.SERVER_CLONE_PATH_PROP); - myUsername = vcsRoot.getProperty(Constants.USERNAME); - myPassword = vcsRoot.getProperty(Constants.PASSWORD); - myUncompressedTransfer = "true".equals(vcsRoot.getProperty(Constants.UNCOMPRESSED_TRANSFER)); - } - - public String getCustomClonePath() { - return myCustomClonePath; - } - - public String getRepository() { - return myRepository; - } - - /** - * Returns name of the branch to use (returns 'default' if no branch specified) - * @return see above - */ - @NotNull - public String getBranchName() { - return StringUtil.isEmpty(myBranchName) ? DEFAULT_BRANCH_NAME : myBranchName; - } - - /** - * Returns true if current branch is default branch - * @return see above - */ - public boolean isDefaultBranch() { - return getBranchName().equals(DEFAULT_BRANCH_NAME); - } - - public boolean isUncompressedTransfer() { - return myUncompressedTransfer; - } - - /** - * Returns path to hg command - * @return path to hg command - */ - @NotNull - public String getHgCommandPath() { - return myHgCommandPath; - } - - public String getUsername() { - return myUsername; - } - - public String getPassword() { - return myPassword; - } - - private final static Set<String> AUTH_PROTOS = new HashSet<String>(); - static { - AUTH_PROTOS.add("http"); - AUTH_PROTOS.add("https"); - AUTH_PROTOS.add("ssh"); - } - - /** - * Returns URL to use for push command - * @return URL to use for push command - */ - public String getRepositoryUrl() { - if (isRequireCredentials()) { - if (containsCredentials(myRepository)) return myRepository; - try { - return createURLWithCredentials(myRepository); - } catch (MalformedURLException e) { - Loggers.VCS.warn("Error while parsing url " + myRepository, e); - } - return myRepository; - } else { - return myRepository; - } - } - - private boolean containsCredentials(final String repository) { - try { - URL url = new URL(null, repository, new FakeStreamHandler()); - String userInfo = url.getUserInfo(); - return userInfo != null && userInfo.contains(":"); - } catch (MalformedURLException e) { - return false; - } - } - - private String createURLWithCredentials(final String originalUrl) throws MalformedURLException { - String userInfo = createUserInfo(); - if (!"".equals(userInfo)) { - URL url = new URL(null, originalUrl, new FakeStreamHandler()); - return url.getProtocol() + "://" - + userInfo + "@" - + url.getHost() - + (url.getPort() != -1 ? ":" + url.getPort() : "") - + url.getFile() - + (url.getRef() != null ? url.getRef() : ""); - } else { - return originalUrl; - } - } - - private boolean isRequireCredentials() { - for (String scheme : AUTH_PROTOS) { - if (myRepository.startsWith(scheme + ":")) { - return true; - } - } - return false; - } - - private String createUserInfo() { - String userInfo = ""; - if (!StringUtil.isEmpty(myUsername)) { - userInfo += myUsername; - if (!StringUtil.isEmpty(myPassword)) { - userInfo += ":" + myPassword; - } - } - return getEscapedUserInfo(userInfo); - } - - private static String getEscapedUserInfo(String userInfo) { - try { - URI uri = new URI("http", userInfo, "somewhere.com", 80, "", "", ""); - String escapedURI = uri.toASCIIString(); - int from = "http://".length(); - int to = escapedURI.indexOf("somewhere.com") - 1; - String escapedUserInfo = escapedURI.substring(from, to); - escapedUserInfo = escapedUserInfo.replaceAll("&", "%26"); - return escapedUserInfo; - } catch (URISyntaxException e) { - assert false; - } - return userInfo; - } - - /** - * Set custom working dir for vcs root. This option make sence only for server-side checkout - * @param customWorkingDir custom working dir - */ - public void setCustomWorkingDir(@NotNull final File customWorkingDir) { - myCustomWorkingDir = PathUtil.getCanonicalFile(customWorkingDir); - } - - /** - * Returns custom working dir for root or null if default working dir should be used. - * This options make sence only with server-side checkout. - * @return see above - */ - @Nullable - public File getCustomWorkingDir() { - return myCustomWorkingDir; - } - - public static boolean isValidRepository(File dir) { - // need better way to check that repository copy is ok - return dir.isDirectory() && new File(dir, ".hg").isDirectory(); - } - - private class FakeStreamHandler extends URLStreamHandler { - @Override - protected URLConnection openConnection(URL u) throws IOException { - throw new UnsupportedOperationException(); - } - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.PathUtil; +import jetbrains.buildServer.log.Loggers; +import jetbrains.buildServer.util.StringUtil; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.net.*; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents Mercurial repository settings + */ +public class Settings { + + private final HgPathProvider myHgPathProvider; + private String myRepository; + private String myHgCommandPath; + private File myCustomWorkingDir; + private String myUsername; + private String myPassword; + private String myBranchName; + private boolean myUncompressedTransfer = false; + private static final String DEFAULT_BRANCH_NAME = "default"; + private String myCustomClonePath; + + public Settings(@NotNull final HgPathProvider hgPathProvider, @NotNull final VcsRoot vcsRoot) { + myHgPathProvider = hgPathProvider; + myRepository = vcsRoot.getProperty(Constants.REPOSITORY_PROP); + myHgCommandPath = vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP); + myBranchName = vcsRoot.getProperty(Constants.BRANCH_NAME_PROP); + myCustomClonePath = vcsRoot.getProperty(Constants.SERVER_CLONE_PATH_PROP); + myUsername = vcsRoot.getProperty(Constants.USERNAME); + myPassword = vcsRoot.getProperty(Constants.PASSWORD); + myUncompressedTransfer = "true".equals(vcsRoot.getProperty(Constants.UNCOMPRESSED_TRANSFER)); + } + + public String getCustomClonePath() { + return myCustomClonePath; + } + + public String getRepository() { + return myRepository; + } + + /** + * Returns name of the branch to use (returns 'default' if no branch specified) + * @return see above + */ + @NotNull + public String getBranchName() { + return StringUtil.isEmpty(myBranchName) ? DEFAULT_BRANCH_NAME : myBranchName; + } + + /** + * Returns true if current branch is default branch + * @return see above + */ + public boolean isDefaultBranch() { + return getBranchName().equals(DEFAULT_BRANCH_NAME); + } + + public boolean isUncompressedTransfer() { + return myUncompressedTransfer; + } + + /** + * @return path to hg command taking into account server-wide/agent-wide settings + */ + @NotNull + public String getHgCommandPath() { + return myHgPathProvider.getHgPath(this); + } + + /** + * @return path to hg command as it is set in VCS root settings + */ + public String getHgPath() { + return myHgCommandPath; + } + + public String getUsername() { + return myUsername; + } + + public String getPassword() { + return myPassword; + } + + private final static Set<String> AUTH_PROTOS = new HashSet<String>(); + static { + AUTH_PROTOS.add("http"); + AUTH_PROTOS.add("https"); + AUTH_PROTOS.add("ssh"); + } + + /** + * Returns URL to use for push command + * @return URL to use for push command + */ + public String getRepositoryUrl() { + if (isRequireCredentials()) { + if (containsCredentials(myRepository)) return myRepository; + try { + return createURLWithCredentials(myRepository); + } catch (MalformedURLException e) { + Loggers.VCS.warn("Error while parsing url " + myRepository, e); + } + return myRepository; + } else { + return myRepository; + } + } + + private boolean containsCredentials(final String repository) { + try { + URL url = new URL(null, repository, new FakeStreamHandler()); + String userInfo = url.getUserInfo(); + return userInfo != null && userInfo.contains(":"); + } catch (MalformedURLException e) { + return false; + } + } + + private String createURLWithCredentials(final String originalUrl) throws MalformedURLException { + String userInfo = createUserInfo(); + if (!"".equals(userInfo)) { + URL url = new URL(null, originalUrl, new FakeStreamHandler()); + return url.getProtocol() + "://" + + userInfo + "@" + + url.getHost() + + (url.getPort() != -1 ? ":" + url.getPort() : "") + + url.getFile() + + (url.getRef() != null ? url.getRef() : ""); + } else { + return originalUrl; + } + } + + private boolean isRequireCredentials() { + for (String scheme : AUTH_PROTOS) { + if (myRepository.startsWith(scheme + ":")) { + return true; + } + } + return false; + } + + private String createUserInfo() { + String userInfo = ""; + if (!StringUtil.isEmpty(myUsername)) { + userInfo += myUsername; + if (!StringUtil.isEmpty(myPassword)) { + userInfo += ":" + myPassword; + } + } + return getEscapedUserInfo(userInfo); + } + + private static String getEscapedUserInfo(String userInfo) { + try { + URI uri = new URI("http", userInfo, "somewhere.com", 80, "", "", ""); + String escapedURI = uri.toASCIIString(); + int from = "http://".length(); + int to = escapedURI.indexOf("somewhere.com") - 1; + String escapedUserInfo = escapedURI.substring(from, to); + escapedUserInfo = escapedUserInfo.replaceAll("&", "%26"); + return escapedUserInfo; + } catch (URISyntaxException e) { + assert false; + } + return userInfo; + } + + /** + * Set custom working dir for vcs root. This option make sence only for server-side checkout + * @param customWorkingDir custom working dir + */ + public void setCustomWorkingDir(@NotNull final File customWorkingDir) { + myCustomWorkingDir = PathUtil.getCanonicalFile(customWorkingDir); + } + + /** + * Returns custom working dir for root or null if default working dir should be used. + * This options make sence only with server-side checkout. + * @return see above + */ + @Nullable + public File getCustomWorkingDir() { + return myCustomWorkingDir; + } + + public static boolean isValidRepository(File dir) { + // need better way to check that repository copy is ok + return dir.isDirectory() && new File(dir, ".hg").isDirectory(); + } + + private class FakeStreamHandler extends URLStreamHandler { + @Override + protected URLConnection openConnection(URL u) throws IOException { + throw new UnsupportedOperationException(); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,78 +1,78 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class StatusCommand extends BaseCommand { - private String myFromId; - private String myToId; - - public StatusCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setFromRevId(final String fromId) { - myFromId = fromId; - } - - public void setToRevId(final String toId) { - myToId = toId; - } - - public List<ModifiedFile> execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("status"); - cli.addParameter("--rev"); - String from = myFromId; - if (from == null) from = "0"; - String to = myToId; - if (to == null) to = "0"; - cli.addParameter(from + ":" + to); - ExecResult res = runCommand(cli); - return parseFiles(res.getStdout()); - } - - public static List<ModifiedFile> parseFiles(final String stdout) { - List<ModifiedFile> result = new ArrayList<ModifiedFile>(); - String[] lines = stdout.split("\n"); - for (String line: lines) { - if (line.length() == 0) continue; - char modifier = line.charAt(0); - String path = line.substring(2); - ModifiedFile.Status status = toStatus(modifier); - if (status == ModifiedFile.Status.UNKNOWN) continue; - result.add(new ModifiedFile(status, path)); - } - return result; - } - - public static ModifiedFile.Status toStatus(final char modifier) { - switch (modifier) { - case 'A': return ModifiedFile.Status.ADDED; - case 'M': return ModifiedFile.Status.MODIFIED; - case 'R': return ModifiedFile.Status.REMOVED; - default: return ModifiedFile.Status.UNKNOWN; - } - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class StatusCommand extends VcsRootCommand { + private String myFromId; + private String myToId; + + public StatusCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setFromRevId(final String fromId) { + myFromId = fromId; + } + + public void setToRevId(final String toId) { + myToId = toId; + } + + public List<ModifiedFile> execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("status"); + cli.addParameter("--rev"); + String from = myFromId; + if (from == null) from = "0"; + String to = myToId; + if (to == null) to = "0"; + cli.addParameter(from + ":" + to); + ExecResult res = runCommand(cli); + return parseFiles(res.getStdout()); + } + + public static List<ModifiedFile> parseFiles(final String stdout) { + List<ModifiedFile> result = new ArrayList<ModifiedFile>(); + String[] lines = stdout.split("\n"); + for (String line: lines) { + if (line.length() == 0) continue; + char modifier = line.charAt(0); + String path = line.substring(2); + ModifiedFile.Status status = toStatus(modifier); + if (status == ModifiedFile.Status.UNKNOWN) continue; + result.add(new ModifiedFile(status, path)); + } + return result; + } + + public static ModifiedFile.Status toStatus(final char modifier) { + switch (modifier) { + case 'A': return ModifiedFile.Status.ADDED; + case 'M': return ModifiedFile.Status.MODIFIED; + case 'R': return ModifiedFile.Status.REMOVED; + default: return ModifiedFile.Status.UNKNOWN; + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,48 +1,48 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -public class TagCommand extends BaseCommand { - private String myTag; - private String myRevId; - - public TagCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setTag(@NotNull final String tag) { - myTag = tag; - } - - public void setRevId(@NotNull final String revId) { - myRevId = revId; - } - - public void execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("tag"); - cli.addParameter("-r"); - cli.addParameter(myRevId); - cli.addParameter(myTag); - runCommand(cli); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class TagCommand extends VcsRootCommand { + private String myTag; + private String myRevId; + + public TagCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setTag(@NotNull final String tag) { + myTag = tag; + } + + public void setRevId(@NotNull final String revId) { + myRevId = revId; + } + + public void execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("tag"); + cli.addParameter("-r"); + cli.addParameter(myRevId); + cli.addParameter(myTag); + runCommand(cli); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,50 +1,50 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -public class UpdateCommand extends BaseCommand { - - private static final int UPDATE_TIMEOUT_SECONDS = 8 * 3600;//8 hours - - private String myToId; - - public UpdateCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setToId(final String toId) { - myToId = toId; - } - - public void execute() throws VcsException { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("update"); - cli.addParameter("-C"); - cli.addParameter("-r"); - if (myToId != null) { - cli.addParameter(myToId); - } else { - cli.addParameter(getSettings().getBranchName()); - } - runCommand(cli, UPDATE_TIMEOUT_SECONDS); - } -} +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +public class UpdateCommand extends VcsRootCommand { + + private static final int UPDATE_TIMEOUT_SECONDS = 8 * 3600;//8 hours + + private String myToId; + + public UpdateCommand(@NotNull Settings settings, @NotNull File workingDir) { + super(settings, workingDir); + } + + public void setToId(final String toId) { + myToId = toId; + } + + public void execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("update"); + cli.addParameter("-C"); + cli.addParameter("-r"); + if (myToId != null) { + cli.addParameter(myToId); + } else { + cli.addParameter(getSettings().getBranchName()); + } + runCommand(cli, UPDATE_TIMEOUT_SECONDS); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,49 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Collections; +import java.util.Set; + +/** + * @author dmitry.neverov + */ +public class VcsRootCommand extends BaseCommand { + + private final Settings mySettings; + + + public VcsRootCommand(@NotNull final Settings settings, @NotNull final File workDir) { + super(settings.getHgCommandPath(), workDir); + mySettings = settings; + } + + + public Settings getSettings() { + return mySettings; + } + + + public Set<String> getPrivateData() { + return Collections.singleton(mySettings.getPassword()); + } + + + protected ExecResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { + return CommandUtil.runCommand(cli, getPrivateData()); + } + + + protected ExecResult runCommand(@NotNull GeneralCommandLine cli, int executionTimeout) throws VcsException { + return CommandUtil.runCommand(cli, executionTimeout, getPrivateData()); + } + + + protected ExecResult runCommand(@NotNull GeneralCommandLine cli, boolean checkFailure) throws VcsException { + return CommandUtil.runCommand(cli, getPrivateData(), checkFailure); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,34 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.execution.configurations.GeneralCommandLine; +import jetbrains.buildServer.ExecResult; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class VersionCommand extends BaseCommand { + + public VersionCommand(@NotNull final Settings settings, @NotNull File workingDir) { + super(settings.getHgCommandPath(), workingDir); + } + + + public VersionCommand(@NotNull final String hgPath, @NotNull File workingDir) { + super(hgPath, workingDir); + } + + + public HgVersion execute() throws VcsException { + GeneralCommandLine cli = createCommandLine(); + cli.addParameter("version"); + cli.addParameter("--quiet"); + ExecResult result = runCommand(cli); + return HgVersion.parse(result.getStdout()); + } + +}
--- a/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Fri Dec 02 15:35:00 2011 +0300 @@ -1,7 +1,9 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> - -<beans default-autowire="constructor"> - <bean id="mercurialServer" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport" /> - <bean id="config" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigImpl" /> -</beans> +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> + +<beans default-autowire="constructor"> + <bean id="mercurialServer" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport" /> + <bean id="config" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigImpl" /> + <bean id="commandFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.CommandFactory" /> + <bean id="hgPathProvider" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgPathProvider"/> +</beans>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesCommand.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,17 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author dmitry.neverov + */ +public interface CollectChangesCommand { + + @NotNull + public List<ChangeSet> execute(@NotNull String fromCommit, @NotNull String toCommit) throws VcsException; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesNoRevsets.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,83 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.util.graph.DAG; +import jetbrains.buildServer.util.graph.DAGIterator; +import jetbrains.buildServer.util.graph.DAGs; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; + +/** + * @author dmitry.neverov + */ +public class CollectChangesNoRevsets implements CollectChangesCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final File myTemplate; + + public CollectChangesNoRevsets(@NotNull final Settings settings, + @NotNull final File workingDir, + @NotNull final File template) { + mySettings = settings; + myWorkingDir = workingDir; + myTemplate = template; + } + + + @NotNull + public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + List<ChangeSet> csets = getRevisionsReachableFrom(toCommit); + Map<String, ChangeSet> csetsMap = getChangesetMap(csets); + if (csetsMap.containsKey(fromCommit)) { + DAG<String> dag = DAGs.createFromEdges(getEdges(csets)); + DAGIterator<String> iter = dag.iterator(toCommit); + iter.markUninteresting(fromCommit); + List<ChangeSet> result = new ArrayList<ChangeSet>(); + while (iter.hasNext()) { + String commit = iter.next(); + ChangeSet cset = csetsMap.get(commit); + if (cset == null) + throw new IllegalStateException("Cannot find cset for id " + commit + ", csets map: " + csetsMap); + result.add(cset); + } + Collections.reverse(result); + return result; + } else { + return Collections.emptyList(); + } + } + + + private Map<String, ChangeSet> getChangesetMap(@NotNull final List<ChangeSet> csets) { + Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); + for (ChangeSet cset : csets) { + result.put(cset.getId(), cset); + } + return result; + } + + + private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { + LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); + log.setFromRevId(new ChangeSetRevision(revision).getId()); + log.showCommitsFromAllBranches(); + log.setToRevId("0"); + return log.execute(); + } + + + private List<Pair<String, String>> getEdges(List<ChangeSet> csets) { + List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); + for (ChangeSet cset : csets) { + for (ChangeSetRevision parent : cset.getParents()) { + result.add(Pair.create(cset.getId(), parent.getId())); + } + } + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesWithRevsets.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,34 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * @author dmitry.neverov + */ +public class CollectChangesWithRevsets implements CollectChangesCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final File myTemplate; + + public CollectChangesWithRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final File template) { + mySettings = settings; + myWorkingDir = workingDir; + myTemplate = template; + } + + @NotNull + public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); + log.showCommitsFromAllBranches(); + log.setRevsets("ancestors(" + toCommit + ") - ancestors(" + fromCommit + ")"); + return log.execute(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactory.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,70 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.MergeBaseCommand; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommand; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +/** + * @author dmitry.neverov + */ +public final class CommandFactory { + + //hg version which supports revsets + private final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0); + private final static String LOG_TEMPLATE_NAME = "log.template"; + + private final File myDefaultWorkingDir; + private final File myLogTemplate; + + + public CommandFactory(@NotNull final ServerPluginConfig config) throws IOException { + myDefaultWorkingDir = config.getCachesDir(); + myLogTemplate = createLogTemplate(config.getPluginDataDir()); + } + + + @NotNull + public MergeBaseCommand createMergeBase(@NotNull Settings settings, @NotNull File workingDir) throws VcsException { + HgVersion hgVersion = getHgVersion(settings); + if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) + return new MergeBaseWithRevsets(settings, workingDir, this); + else + return new MergeBaseNoRevsets(settings, workingDir, this); + } + + + @NotNull + public LogCommand createLog(@NotNull final Settings settings, @NotNull final File workingDir) { + return new LogCommand(settings, workingDir, myLogTemplate); + } + + @NotNull + public CollectChangesCommand getCollectChangesCommand(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { + HgVersion hgVersion = getHgVersion(settings); + if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) { + return new CollectChangesWithRevsets(settings, workingDir, myLogTemplate); + } else { + return new CollectChangesNoRevsets(settings, workingDir, myLogTemplate); + } + } + + private File createLogTemplate(@NotNull final File templateFileDir) throws IOException { + File template = new File(templateFileDir, LOG_TEMPLATE_NAME); + if (!template.exists()) { + FileUtil.copyResource(CommandFactory.class, "/buildServerResources/log.template", template); + } + return template; + } + + private HgVersion getHgVersion(@NotNull final Settings settings) throws VcsException { + VersionCommand versionCommand = new VersionCommand(settings, myDefaultWorkingDir); + return versionCommand.execute(); + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Fri Dec 02 15:35:00 2011 +0300 @@ -55,28 +55,30 @@ * <p>Working copy of repository is created in the $TEAMCITY_DATA_PATH/system/caches/hg_<hash code> folder. * <p>Personal builds (remote runs) are not yet supported, they require corresponding functionality from the IDE. */ -public class MercurialVcsSupport extends ServerVcsSupport implements LabelingSupport, VcsFileContentProvider, BranchSupport { - - private final String LOG_TEMPLATE_NAME = "log.template"; +public class MercurialVcsSupport extends ServerVcsSupport implements LabelingSupport, VcsFileContentProvider, BranchSupport, + CollectChangesBetweenRoots { private ConcurrentMap<String, Lock> myWorkDirLocks= new ConcurrentHashMap<String, Lock>(); private VcsManager myVcsManager; private File myDefaultWorkFolderParent; private MirrorManager myMirrorManager; private final ServerPluginConfig myConfig; - private File myLogTemplate; + private final HgPathProvider myHgPathProvider; + private final CommandFactory myCommandFactory; private final FileFilter myIgnoreDotHgFilter = new IgnoreDotHgFilter(); private final FileFilter myAcceptAllFilter = new AcceptAllFilter(); public MercurialVcsSupport(@NotNull final VcsManager vcsManager, - @NotNull final ServerPaths paths, @NotNull final SBuildServer server, @NotNull final EventDispatcher<BuildServerListener> dispatcher, - @NotNull final ServerPluginConfig config) throws IOException { - myLogTemplate = createLogTemplate(paths.getPluginDataDirectory()); + @NotNull final ServerPluginConfig config, + @NotNull final HgPathProvider hgPathProvider, + @NotNull final CommandFactory commandFactory) { myVcsManager = vcsManager; - myDefaultWorkFolderParent = new File(paths.getCachesDir(), "mercurial"); + myConfig = config; + myDefaultWorkFolderParent = myConfig.getCachesDir(); myMirrorManager = new MirrorManager(myDefaultWorkFolderParent); - myConfig = config; + myHgPathProvider = hgPathProvider; + myCommandFactory = commandFactory; dispatcher.addListener(new BuildServerAdapter() { @Override public void cleanupFinished() { @@ -98,6 +100,15 @@ }); } }); + logUsedHg(); + } + + private void logUsedHg() { + String hgPath = myConfig.getHgPath(); + if (hgPath != null) + Loggers.VCS.info("Use server-wide hg path " + hgPath + ", path in the VCS root settings will be ignored"); + else + Loggers.VCS.info("Server-wide hg path is not set, will use path from the VCS root settings"); } private void deleteWithLocking(Collection<File> filesForDelete) { @@ -111,21 +122,6 @@ } } - private Collection<ModifiedFile> computeModifiedFilesForMergeCommit(final Settings settings, final ChangeSet cur) throws VcsException { - File workingDir = getWorkingDir(settings); - ChangedFilesCommand cfc = new ChangedFilesCommand(settings, workingDir); - cfc.setRevId(cur.getId()); - return cfc.execute(); - } - - private File createLogTemplate(@NotNull final File templateFileDir) throws IOException { - File template = new File(templateFileDir, LOG_TEMPLATE_NAME); - if (!template.exists()) { - FileUtil.copyResource(MercurialVcsSupport.class, "/buildServerResources/log.template", template); - } - return template; - } - private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, CheckoutRules rules) { List<VcsChange> files = new ArrayList<VcsChange>(); for (ModifiedFile mf: modifiedFiles) { @@ -194,35 +190,6 @@ return new byte[0]; } - /** - * Returns file's content or empty string if it doesn't exist. - * @param path path of the file of interest - * @param settings root settings - * @param cset repository cset (should be present in the repository) - * @return see above - */ - @NotNull - private String getFileContent(@NotNull final String path, @NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { - File dir = getWorkingDir(settings); - CatCommand cat = new CatCommand(settings, dir); - cat.setRevId(cset.getId()); - cat.setLogErrorsInDebug(true); - File parentDir = null; - try { - parentDir = cat.execute(Collections.singletonList(path)); - File f = new File(parentDir, path); - if (f.isFile()) - return FileUtil.readText(f); - else - return ""; - } catch (Exception e) { - return ""; - } finally { - if (parentDir != null) - deleteTmpDir(parentDir); - } - } - @NotNull public String getName() { return Constants.VCS_NAME; @@ -420,6 +387,35 @@ return !isEmptyOrSpaces(hgsub); } + /** + * Returns file's content or empty string if it doesn't exist. + * @param path path of the file of interest + * @param settings root settings + * @param cset repository cset (should be present in the repository) + * @return see above + */ + @NotNull + private String getFileContent(@NotNull final String path, @NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { + File dir = getWorkingDir(settings); + CatCommand cat = new CatCommand(settings, dir); + cat.setRevId(cset.getId()); + File parentDir = null; + try { + parentDir = cat.execute(Collections.singletonList(path), false); + File f = new File(parentDir, path); + if (f.isFile()) + return FileUtil.readText(f); + else + return ""; + } catch (Exception e) { + return ""; + } finally { + if (parentDir != null) + deleteTmpDir(parentDir); + } + } + + private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { buildPatchFromDirectory(repRoot, builder, repRoot, checkoutRules, filter); } @@ -494,6 +490,7 @@ /** * Check if changeSet is present in local repository. * @param settings root settings + * @param workDir where to run a command * @param cset change set of interest * @return true if changeSet is present in local repository */ @@ -525,7 +522,16 @@ } @NotNull - public Map<String, String> getBranchesRevisions(@NotNull VcsRoot root) throws VcsException { + public RepositoryState getCurrentState(@NotNull VcsRoot root) throws VcsException { + RepositoryState state = new RepositoryStateImpl(); + for (Map.Entry<String, String> entry : getBranchesRevisions(root).entrySet()) { + state.setBranchRevision(entry.getKey(), entry.getValue()); + } + return state; + } + + @NotNull + private Map<String, String> getBranchesRevisions(@NotNull VcsRoot root) throws VcsException { Settings settings = createSettings(root); syncRepository(settings); File workingDir = getWorkingDir(settings); @@ -551,12 +557,15 @@ VcsRoot branchRoot = createBranchRoot(root, branchName); String baseVersion = getCurrentVersion(root); String branchVersion = getCurrentVersion(branchRoot); - String branchPoint = getBranchPoint(settings, baseVersion, branchVersion); + String mergeBase = getMergeBase(settings, baseVersion, branchVersion); + + if (mergeBase == null) + return null; - LogCommand lc = new LogCommand(settings, getWorkingDir(settings), myLogTemplate); - lc.setFromRevId(new ChangeSetRevision(branchPoint).getId()); + LogCommand lc = myCommandFactory.createLog(settings, getWorkingDir(settings)); + lc.setFromRevId(new ChangeSetRevision(mergeBase).getId()); lc.setToRevId(new ChangeSetRevision(branchVersion).getId()); - lc.setBranchName(null);//do not limit output to particular branch, return all commits + lc.showCommitsFromAllBranches(); List<ChangeSet> changeSets = lc.execute(); if (changeSets.size() > 1) {//when branch points to the commit in original branch we get 1 cset String branchId = changeSets.get(1).getId(); @@ -578,75 +587,88 @@ public List<ModificationData> collectChanges(@NotNull VcsRoot fromRoot, @NotNull String fromRootRevision, @NotNull VcsRoot toRoot, @Nullable String toRootRevision, @NotNull CheckoutRules checkoutRules) throws VcsException { - //we get all branches while clone, if vcs roots are related it is doesn't matter in which one search for branch point - Settings settings = createSettings(fromRoot); + Settings settings = createSettings(toRoot); syncRepository(settings); - String branchPoint = getBranchPoint(settings, fromRootRevision, toRootRevision); - return ((CollectChangesByCheckoutRules) getCollectChangesPolicy()).collectChanges(toRoot, branchPoint, toRootRevision, checkoutRules); + String toRevision = toRootRevision != null ? toRootRevision : getCurrentVersion(toRoot); + String mergeBase = getMergeBase(settings, fromRootRevision, toRevision); + if (mergeBase == null) + return Collections.emptyList(); + return collectChanges(toRoot, mergeBase, toRootRevision, checkoutRules); } - private String getBranchPoint(@NotNull Settings settings, String branchOneRev, String branchTwoRev) throws VcsException { - if (branchOneRev.equals(branchTwoRev)) - return branchOneRev; - File workingDir = getWorkingDir(settings); - LogCommand lc = new LogCommand(settings, workingDir, myLogTemplate); - lc.setFromRevId(new ChangeSetRevision(branchOneRev).getId()); - lc.setToRevId(new ChangeSetRevision(branchTwoRev).getId()); - lc.setLimit(1); - List<ChangeSet> changeSets = lc.execute(); - ChangeSet cs = changeSets.get(0); - if (cs.isInitial()) { - return cs.getId(); - } else { - return cs.getParents().get(0).getId(); - } + @Nullable + private String getMergeBase(@NotNull Settings settings, @NotNull String revision1, @NotNull String revision2) throws VcsException { + String result = myCommandFactory.createMergeBase(settings, getWorkingDir(settings)).execute(revision1, revision2); + if (result == null) + result = getMinusNthCommit(settings, 10); + return result; } + + @Nullable + private String getMinusNthCommit(@NotNull Settings settings, int n) throws VcsException { + LogCommand log = myCommandFactory.createLog(settings, getWorkingDir(settings)); + log.setToRevId(settings.getBranchName()); + if (n > 0) + log.setLimit(n); + List<ChangeSet> changeSets = log.execute(); + if (changeSets.isEmpty()) + return null; + return changeSets.get(0).getId(); + } + + @NotNull public CollectChangesPolicy getCollectChangesPolicy() { - return new CollectChangesByCheckoutRules() { - @NotNull - public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException { - Settings settings = createSettings(root); - syncRepository(settings); + return this; + } - // first obtain changes between specified versions - List<ModificationData> result = new ArrayList<ModificationData>(); - if (currentVersion == null) - return result; + public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException { + Settings settings = createSettings(root); + syncRepository(settings); + List<ModificationData> result = new ArrayList<ModificationData>(); + for (ChangeSet cset : getChangesets(settings, fromVersion, currentVersion)) { + result.add(createModificationData(cset, root, checkoutRules)); + } + return result; + } - File workingDir = getWorkingDir(settings); - LogCommand lc = new LogCommand(settings, workingDir, myLogTemplate); - String fromId = new ChangeSetRevision(fromVersion).getId(); - lc.setFromRevId(fromId); - lc.setToRevId(new ChangeSetRevision(currentVersion).getId()); - List<ChangeSet> changeSets = lc.execute(); - if (changeSets.isEmpty()) { - return result; - } - ChangeSet prev = new ChangeSet(fromVersion); - for (ChangeSet cur : changeSets) { - if (cur.getId().equals(fromId)) - continue; // skip already reported changeset + private ModificationData createModificationData(@NotNull final ChangeSet cset, @NotNull final VcsRoot root, @NotNull final CheckoutRules checkoutRules) { + List<ChangeSetRevision> parents = cset.getParents(); + if (parents.isEmpty()) + throw new IllegalStateException("Commit " + cset.getId() + " has no parents"); + List<VcsChange> files = toVcsChanges(cset.getModifiedFiles(), parents.get(0).getFullVersion(), cset.getFullVersion(), checkoutRules); + final ModificationData result = new ModificationData(cset.getTimestamp(), files, cset.getDescription(), cset.getUser(), root, cset.getFullVersion(), cset.getId()); + for (ChangeSetRevision parent : parents) { + result.addParentRevision(parent.getFullVersion()); + } + if (result.getParentRevisions().size() > 1) + result.setCanBeIgnored(false); + return result; + } + - boolean merge = cur.getParents().size() > 1; - List<ModifiedFile> modifiedFiles = cur.getModifiedFiles(); - List<VcsChange> files = toVcsChanges(modifiedFiles, prev.getFullVersion(), cur.getFullVersion(), checkoutRules); - if (files.isEmpty() && !merge) - continue; - ModificationData md = new ModificationData(cur.getTimestamp(), files, cur.getDescription(), cur.getUser(), root, cur.getFullVersion(), cur.getId()); - if (merge) - md.setCanBeIgnored(false); - result.add(md); - prev = cur; - } + @NotNull + private List<ChangeSet> getChangesets(@NotNull final Settings settings, @NotNull final String fromVersion, @Nullable final String toVersion) throws VcsException { + if (toVersion == null) + return Collections.emptyList(); + String fromCommit = new ChangeSetRevision(fromVersion).getId(); + String toCommit = new ChangeSetRevision(toVersion).getId(); + File workingDir = getWorkingDir(settings); + CollectChangesCommand log = myCommandFactory.getCollectChangesCommand(settings, workingDir); + List<ChangeSet> changesets = log.execute(fromCommit, toCommit); + Iterator<ChangeSet> iter = changesets.iterator(); + while (iter.hasNext()) { + ChangeSet cset = iter.next(); + if (cset.getId().equals(fromCommit)) + iter.remove();//skip already reported changes + } + return changesets; + } - return result; - } - }; - } + @NotNull public BuildPatchPolicy getBuildPatchPolicy() { @@ -761,7 +783,7 @@ } private Settings createSettings(final VcsRoot root) throws VcsException { - Settings settings = new Settings(root); + Settings settings = new Settings(myHgPathProvider, root); String customClonePath = settings.getCustomClonePath(); if (!StringUtil.isEmptyOrSpaces(customClonePath) && !myDefaultWorkFolderParent.equals(new File(customClonePath).getAbsoluteFile())) { File parentDir = new File(customClonePath); @@ -812,6 +834,11 @@ } + @Override + public boolean isDAGBasedVcs() { + return true; + } + private static class IgnoreDotHgFilter implements FileFilter { public boolean accept(final File file) { return !(file.isDirectory() && ".hg".equals(file.getName()));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseNoRevsets.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,64 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.util.graph.DAG; +import jetbrains.buildServer.util.graph.DAGs; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.*; + +/** + * Implementation of merge-base for hg versions which don't have revsets + * @author dmitry.neverov + */ +public final class MergeBaseNoRevsets implements MergeBaseCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final CommandFactory myCommandFactory; + + public MergeBaseNoRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final CommandFactory commandFactory) { + mySettings = settings; + myWorkingDir = workingDir; + myCommandFactory = commandFactory; + } + + + @Nullable + public String execute(@NotNull final String revision1, @NotNull final String revision2) { + if (revision1.equals(revision2)) + return revision1; + try { + List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>(); + fillEdges(edges, getRevisionsReachableFrom(revision1)); + fillEdges(edges, getRevisionsReachableFrom(revision2)); + DAG<String> dag = DAGs.createFromEdges(edges); + List<String> commonAncestors = dag.getCommonAncestors(new ChangeSetRevision(revision1).getId(), new ChangeSetRevision(revision2).getId()); + return commonAncestors.isEmpty() ? null : commonAncestors.get(0); + } catch (VcsException e) { + return null; + } + } + + + private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { + LogCommand log = myCommandFactory.createLog(mySettings, myWorkingDir); + log.setFromRevId(new ChangeSetRevision(revision).getId()); + log.showCommitsFromAllBranches(); + log.setToRevId("0"); + return log.execute(); + } + + + private void fillEdges(List<Pair<String, String>> edges, List<ChangeSet> csets) { + for (ChangeSet cset : csets) { + for (ChangeSetRevision parent : cset.getParents()) { + edges.add(Pair.create(cset.getId(), parent.getId())); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseWithRevsets.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,38 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.List; + +/** + * Implementation of merge-base using hg revsets + * @author dmitry.neverov + */ +public final class MergeBaseWithRevsets implements MergeBaseCommand { + + private final Settings mySettings; + private final File myWorkingDir; + private final CommandFactory myCommandFactory; + + public MergeBaseWithRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final CommandFactory commandFactory) { + mySettings = settings; + myWorkingDir = workingDir; + myCommandFactory = commandFactory; + } + + public String execute(@NotNull final String revision1, @NotNull final String revision2) throws VcsException { + try { + LogCommand log = myCommandFactory.createLog(mySettings, myWorkingDir); + log.setRevsets("ancestor(" + new ChangeSetRevision(revision1).getId() + ", " + new ChangeSetRevision(revision2).getId() + ")"); + log.showCommitsFromAllBranches(); + log.setCalculateParents(false); + List<ChangeSet> csets = log.execute(); + return csets.isEmpty() ? null : csets.get(0).getId(); + } catch (VcsException e) { + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProvider.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,39 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class ServerHgPathProvider implements HgPathProvider { + + private final ServerPluginConfig myConfig; + + + public ServerHgPathProvider(@NotNull final ServerPluginConfig config) { + myConfig = config; + } + + + public String getHgPath(@NotNull final Settings settings) { + String serverWideHgPath = myConfig.getHgPath(); + if (serverWideHgPath != null) { + return serverWideHgPath; + } else { + String pathFromRoot = settings.getHgPath(); + if (pathFromRoot.equals(unresolvedAgentHgPath())) { + //try to use hg from the PATH: + return "hg"; + } else { + return pathFromRoot; + } + } + } + + + private String unresolvedAgentHgPath() { + //Use hard-coded value here in order to not add dependency on agent part of plugin: + return "%teamcity.hg.agent.path%"; + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfig.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfig.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,10 +1,22 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; + /** * @author dmitry.neverov */ public interface ServerPluginConfig extends PluginConfig { + @Nullable + String getHgPath(); + public boolean isUsePullProtocol(); + @NotNull + public File getPluginDataDir(); + + int getPullTimeout(); }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigImpl.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigImpl.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,6 +1,11 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import jetbrains.buildServer.serverSide.ServerPaths; import jetbrains.buildServer.serverSide.TeamCityProperties; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; /** * @author dmitry.neverov @@ -8,12 +13,35 @@ public class ServerPluginConfigImpl implements ServerPluginConfig { private static final String PULL_TIMEOUT_SECONDS = "teamcity.hg.pull.timeout.seconds"; - private final int DEFAULT_PULL_TIMEOUT_SECONDS = 3600; + public static final int DEFAULT_PULL_TIMEOUT_SECONDS = 3600; + + private final File myCachesDir; + private final File myPluginDataDir; + + public ServerPluginConfigImpl(@NotNull final ServerPaths paths) { + myCachesDir = new File(paths.getCachesDir(), "mercurial"); + myPluginDataDir = paths.getPluginDataDirectory(); + } public boolean isUsePullProtocol() { return TeamCityProperties.getBooleanOrTrue("teamcity.hg.use.pull.protocol"); } + @Nullable + public String getHgPath() { + return TeamCityProperties.getPropertyOrNull("teamcity.hg.server.path"); + } + + @NotNull + public File getCachesDir() { + return myCachesDir; + } + + @NotNull + public File getPluginDataDir() { + return myPluginDataDir; + } + public int getPullTimeout() { int timeout = TeamCityProperties.getInteger(PULL_TIMEOUT_SECONDS, DEFAULT_PULL_TIMEOUT_SECONDS); return timeout > 0 ? timeout : DEFAULT_PULL_TIMEOUT_SECONDS;
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,225 +1,240 @@ -/* - * Copyright 2000-2011 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.util.FileUtil; -import jetbrains.buildServer.vcs.CheckoutRules; -import jetbrains.buildServer.vcs.IncludeRule; -import jetbrains.buildServer.vcs.VcsException; -import jetbrains.buildServer.vcs.VcsRoot; -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @author Pavel.Sher - * Date: 30.07.2008 - */ -@Test -public class AgentSideCheckoutTest extends BaseMercurialTestCase { - private MercurialAgentSideVcsSupport myVcsSupport; - private File myWorkDir; - private File myMirrorsRootDir; - private Mockery myContext; - private BuildProgressLogger myLogger; - private int myBuildCounter = 0; - - @Override - @BeforeMethod - protected void setUp() throws Exception { - super.setUp(); - - myContext = new Mockery(); - - myMirrorsRootDir = myTempFiles.createTempDir(); - - final BuildAgentConfiguration agentConfig = myContext.mock(BuildAgentConfiguration.class); - myContext.checking(new Expectations() {{ - allowing(agentConfig).getCacheDirectory("mercurial"); will(returnValue(myMirrorsRootDir)); - }}); - - myVcsSupport = new MercurialAgentSideVcsSupport(agentConfig); - - myLogger = myContext.mock(BuildProgressLogger.class); - myContext.checking(new Expectations() {{ - allowing(myLogger).message(with(any(String.class))); - }}); - - myWorkDir = myTempFiles.createTempDir(); - - } - - public void checkout_on_agent() throws IOException, VcsException { - testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule(".", ".", null)); - } - - public void checkout_on_agent_include_rule_with_mapping() throws IOException, VcsException { - testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule("+:.", "subdir", null)); - } - - private void testUpdate(final VcsRoot vcsRoot, String version, String expected, final IncludeRule includeRule) throws VcsException, IOException { - File workDir = doUpdate(vcsRoot, version, includeRule); - - checkWorkingDir(expected, workDir); - } - - private void checkWorkingDir(final String expected, final File workDir) throws IOException { - FileUtil.delete(new File(workDir, ".hg")); - checkDirectoriesAreEqual(new File(getTestDataPath(), expected), workDir); - } - - private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule) throws VcsException { - return doUpdate(vcsRoot, version, includeRule, false); - } - - private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule, boolean useLocalMirrors) throws VcsException { - File actualWorkDir = new File(myWorkDir, includeRule.getTo()); - final Map<String, String> sharedConfigParameters = new HashMap<String, String>(); - sharedConfigParameters.put("teamcity.hg.use.local.mirrors", String.valueOf(useLocalMirrors)); - final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++); - myContext.checking(new Expectations() {{ - allowing(build).getBuildLogger(); will(returnValue(myLogger)); - allowing(build).getSharedConfigParameters(); will(returnValue(sharedConfigParameters)); - }}); - myVcsSupport.getUpdater(vcsRoot, new CheckoutRules(""), version, myWorkDir, build, false).process(includeRule, actualWorkDir); - - File hgDir = new File(actualWorkDir, ".hg"); - assertTrue(hgDir.isDirectory()); - return actualWorkDir; - } - - public void checkout_on_agent_from_branch() throws IOException, VcsException { - testUpdate(createVcsRoot(simpleRepo(), "test_branch"), "7:376dcf05cd2a", "patch3/after", new IncludeRule(".", ".", null)); - } - - public void update_on_agent() throws IOException, VcsException { - VcsRoot vcsRoot = createVcsRoot(simpleRepo()); - doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", ".", null)); - File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null)); - - checkWorkingDir("patch1/after", workDir); - } - - public void update_on_agent_with_include_rule() throws IOException, VcsException { - VcsRoot vcsRoot = createVcsRoot(simpleRepo()); - doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null)); - File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", "subdir", null)); - - checkWorkingDir("patch1/after", workDir); - } - - public void update_on_agent_from_branch() throws IOException, VcsException { - VcsRoot vcsRoot = createVcsRoot(simpleRepo(), "test_branch"); - doUpdate(vcsRoot, "7:376dcf05cd2a", new IncludeRule(".", ".", null)); - File workDir = doUpdate(vcsRoot, "8:04c3ae4c6312", new IncludeRule(".", ".", null)); - - checkWorkingDir("patch4/after", workDir); - } - - public void by_default_local_mirror_not_created() throws IOException, VcsException { - List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); - assertTrue(mirrors.isEmpty()); - VcsRoot root = createVcsRoot(simpleRepo()); - doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); - mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); - //though some dirs are created - they are empty => there were no clones into local mirrors - for (File mirror : mirrors) { - assertTrue(FileUtil.getSubDirectories(mirror).isEmpty()); - } - } - - public void local_mirror_is_created() throws IOException, VcsException { - List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); - assertTrue(mirrors.isEmpty()); - VcsRoot root = createVcsRoot(simpleRepo()); - doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); - mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); - assertEquals(1, mirrors.size()); - File mirror = mirrors.get(0); - File dotHg = new File(mirror, ".hg"); - assertTrue(dotHg.exists()); - File hgrc = new File(dotHg, "hgrc"); - String hgrcContent = FileUtil.readText(hgrc); - assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP))); - } - - public void new_repository_is_cloned_from_local_mirror() throws IOException, VcsException { - VcsRoot root = createVcsRoot(simpleRepo()); - File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); - File mirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); - File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); - String hgrcContent = FileUtil.readText(hgrc); - assertTrue(hgrcContent.contains("default = " + mirrorDir.getCanonicalPath())); - } - - public void repository_cloned_from_remote_start_cloning_from_local_mirror() throws IOException, VcsException { - VcsRoot root = createVcsRoot(simpleRepo()); - //clone from remote repository - File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); - String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc")); - - File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); - File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); - String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc")); - assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed - assertTrue(hgrcContent2.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror - } - - public void repository_cloned_from_local_mirror_start_cloning_from_remote() throws IOException, VcsException { - VcsRoot root = createVcsRoot(simpleRepo()); - //clone from remote repository - File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); - String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc")); - File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); - assertTrue(hgrcContent.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror - - File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); - String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc")); - assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed - assertTrue(hgrcContent2.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP)));//now it clones from remote - } - - /** - * TW-15984 - */ - public void should_be_able_to_clone_into_non_empty_dir() throws IOException, VcsException { - VcsRoot vcsRoot = createVcsRoot(simpleRepo()); - doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null)); - doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null)); - } - - public void cloned_repo_should_contains_default_parameter_in_hgrc() throws VcsException, IOException { - VcsRoot root = createVcsRoot(simpleRepo()); - File workingDir = doUpdate(root, "4:b06a290a363b", new IncludeRule(".", ".", null)); - File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); - String hgrcContent = FileUtil.readText(hgrc); - assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP))); - } - - protected String getTestDataPath() { - return "mercurial-tests/testData"; - } -} +/* + * Copyright 2000-2011 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.util.FileUtil; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.IncludeRule; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Pavel.Sher + * Date: 30.07.2008 + */ +@Test +public class AgentSideCheckoutTest extends BaseMercurialTestCase { + + final static String HG_PATH_REFERENCE = "%" + HgDetector.AGENT_HG_PATH_PROPERTY + "%"; + private MercurialAgentSideVcsSupport myVcsSupport; + private File myWorkDir; + private File myMirrorsRootDir; + private Mockery myContext; + private BuildProgressLogger myLogger; + private int myBuildCounter = 0; + + @Override + @BeforeMethod + protected void setUp() throws Exception { + super.setUp(); + + myContext = new Mockery(); + + myMirrorsRootDir = myTempFiles.createTempDir(); + + final BuildAgentConfiguration agentConfig = myContext.mock(BuildAgentConfiguration.class); + myContext.checking(new Expectations() {{ + allowing(agentConfig).getCacheDirectory("mercurial"); will(returnValue(myMirrorsRootDir)); + allowing(agentConfig).getTempDirectory(); will(returnValue(myTempFiles.createTempDir())); + allowing(agentConfig).getParametersResolver(); will(returnValue(new HgPathResolver())); + }}); + + myVcsSupport = new MercurialAgentSideVcsSupport(new AgentPluginConfigImpl(agentConfig), new AgentHgPathProvider(agentConfig)); + + myLogger = myContext.mock(BuildProgressLogger.class); + myContext.checking(new Expectations() {{ + allowing(myLogger).message(with(any(String.class))); + }}); + + myWorkDir = myTempFiles.createTempDir(); + + } + + public void should_work_when_path_to_hg_is_property() throws Exception { + VcsRootImpl root = new VcsRootBuilder() + .repository(LocalRepositoryUtil.prepareRepository(simpleRepo()).getAbsolutePath()) + .hgPath(HG_PATH_REFERENCE).build(); + testUpdate(root, "4:b06a290a363b", "cleanPatch1/after", new IncludeRule(".", ".", null)); + } + + + public void checkout_on_agent() throws IOException, VcsException { + testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule(".", ".", null)); + } + + public void checkout_on_agent_include_rule_with_mapping() throws IOException, VcsException { + testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule("+:.", "subdir", null)); + } + + private void testUpdate(final VcsRoot vcsRoot, String version, String expected, final IncludeRule includeRule) throws VcsException, IOException { + File workDir = doUpdate(vcsRoot, version, includeRule); + + checkWorkingDir(expected, workDir); + } + + private void checkWorkingDir(final String expected, final File workDir) throws IOException { + FileUtil.delete(new File(workDir, ".hg")); + checkDirectoriesAreEqual(new File(getTestDataPath(), expected), workDir); + } + + private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule) throws VcsException { + return doUpdate(vcsRoot, version, includeRule, false); + } + + private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule, boolean useLocalMirrors) throws VcsException { + File actualWorkDir = new File(myWorkDir, includeRule.getTo()); + final Map<String, String> sharedConfigParameters = new HashMap<String, String>(); + sharedConfigParameters.put("teamcity.hg.use.local.mirrors", String.valueOf(useLocalMirrors)); + final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++); + myContext.checking(new Expectations() {{ + allowing(build).getBuildLogger(); will(returnValue(myLogger)); + allowing(build).getSharedConfigParameters(); will(returnValue(sharedConfigParameters)); + }}); + myVcsSupport.getUpdater(vcsRoot, new CheckoutRules(""), version, myWorkDir, build, false).process(includeRule, actualWorkDir); + + File hgDir = new File(actualWorkDir, ".hg"); + assertTrue(hgDir.isDirectory()); + return actualWorkDir; + } + + public void checkout_on_agent_from_branch() throws IOException, VcsException { + testUpdate(createVcsRoot(simpleRepo(), "test_branch"), "7:376dcf05cd2a", "patch3/after", new IncludeRule(".", ".", null)); + } + + public void update_on_agent() throws IOException, VcsException { + VcsRoot vcsRoot = createVcsRoot(simpleRepo()); + doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", ".", null)); + File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null)); + + checkWorkingDir("patch1/after", workDir); + } + + public void update_on_agent_with_include_rule() throws IOException, VcsException { + VcsRoot vcsRoot = createVcsRoot(simpleRepo()); + doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null)); + File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", "subdir", null)); + + checkWorkingDir("patch1/after", workDir); + } + + public void update_on_agent_from_branch() throws IOException, VcsException { + VcsRoot vcsRoot = createVcsRoot(simpleRepo(), "test_branch"); + doUpdate(vcsRoot, "7:376dcf05cd2a", new IncludeRule(".", ".", null)); + File workDir = doUpdate(vcsRoot, "8:04c3ae4c6312", new IncludeRule(".", ".", null)); + + checkWorkingDir("patch4/after", workDir); + } + + public void by_default_local_mirror_not_created() throws IOException, VcsException { + List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); + assertTrue(mirrors.isEmpty()); + VcsRoot root = createVcsRoot(simpleRepo()); + doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); + mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); + //though some dirs are created - they are empty => there were no clones into local mirrors + for (File mirror : mirrors) { + assertTrue(FileUtil.getSubDirectories(mirror).isEmpty()); + } + } + + public void local_mirror_is_created() throws IOException, VcsException { + List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); + assertTrue(mirrors.isEmpty()); + VcsRoot root = createVcsRoot(simpleRepo()); + doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); + mirrors = FileUtil.getSubDirectories(myMirrorsRootDir); + assertEquals(1, mirrors.size()); + File mirror = mirrors.get(0); + File dotHg = new File(mirror, ".hg"); + assertTrue(dotHg.exists()); + File hgrc = new File(dotHg, "hgrc"); + String hgrcContent = FileUtil.readText(hgrc); + assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP))); + } + + public void new_repository_is_cloned_from_local_mirror() throws IOException, VcsException { + VcsRoot root = createVcsRoot(simpleRepo()); + File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); + File mirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); + File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); + String hgrcContent = FileUtil.readText(hgrc); + assertTrue(hgrcContent.contains("default = " + mirrorDir.getCanonicalPath())); + } + + public void repository_cloned_from_remote_start_cloning_from_local_mirror() throws IOException, VcsException { + VcsRoot root = createVcsRoot(simpleRepo()); + //clone from remote repository + File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); + String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc")); + + File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); + File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); + String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc")); + assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed + assertTrue(hgrcContent2.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror + } + + public void repository_cloned_from_local_mirror_start_cloning_from_remote() throws IOException, VcsException { + VcsRoot root = createVcsRoot(simpleRepo()); + //clone from remote repository + File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); + String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc")); + File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); + assertTrue(hgrcContent.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror + + File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); + String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc")); + assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed + assertTrue(hgrcContent2.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP)));//now it clones from remote + } + + /** + * TW-15984 + */ + public void should_be_able_to_clone_into_non_empty_dir() throws IOException, VcsException { + VcsRoot vcsRoot = createVcsRoot(simpleRepo()); + doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null)); + doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null)); + } + + public void cloned_repo_should_contains_default_parameter_in_hgrc() throws VcsException, IOException { + VcsRoot root = createVcsRoot(simpleRepo()); + File workingDir = doUpdate(root, "4:b06a290a363b", new IncludeRule(".", ".", null)); + File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); + String hgrcContent = FileUtil.readText(hgrc); + assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP))); + } + + protected String getTestDataPath() { + return "mercurial-tests/testData"; + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,105 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.agent.AgentRunningBuild; +import jetbrains.buildServer.agent.BuildAgentConfiguration; +import jetbrains.buildServer.agent.BuildProgressLogger; +import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2; +import jetbrains.buildServer.log.Log4jFactory; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.IncludeRule; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jetbrains.annotations.NotNull; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +/** + * @author dmitry.neverov + */ +@Test +public class AgentSideCheckoutWithSubreposTest { + + private TempFiles myTempFiles = new TempFiles(); + private File myOriginalRepositoriesParentDir; + private File myWorkDir; + private Mockery myContext; + private BuildProgressLogger myLogger; + private UpdateByIncludeRules2 myVcsSupport; + private int myBuildCounter = 0; + private File myR1Dir; + + static { + Logger.setFactory(new Log4jFactory()); + } + + @BeforeMethod + public void setUp() throws Exception { + myOriginalRepositoriesParentDir = myTempFiles.createTempDir(); + myWorkDir = new File(myOriginalRepositoriesParentDir, "agentWorkDir"); + 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())); + }}); + + myVcsSupport = new MercurialAgentSideVcsSupport(new AgentPluginConfigImpl(agentConfig), 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))); + }}); + + myR1Dir = copy(new File("mercurial-tests/testData/subrepos/r1")); + copy(new File("mercurial-tests/testData/subrepos/r2")); + copy(new File("mercurial-tests/testData/subrepos/r3")); + } + + @AfterMethod + public void tearDown() { + myTempFiles.cleanup(); + } + + + public void subrepository_url_changed() throws Exception { + VcsRootImpl root = new VcsRootBuilder() + .repository(myR1Dir.getAbsolutePath()) + .build(); + doUpdate(root, "34017377d9c3"); + doUpdate(root, "d350e7209906"); + } + + + private void doUpdate(final VcsRoot vcsRoot, final String toVersion) 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(Collections.emptyMap())); + }}); + myVcsSupport.getUpdater(vcsRoot, CheckoutRules.DEFAULT, toVersion, myWorkDir, build, false).process(IncludeRule.createDefaultInstance(), myWorkDir); + } + + + private File copy(@NotNull File originalRepositoryDir) throws IOException { + String dirName = originalRepositoryDir.getName(); + File copyDir = new File(myOriginalRepositoriesParentDir, dirName); + FileUtil.copyDir(originalRepositoryDir, copyDir); + if (new File(copyDir, "hg").isDirectory()) { + FileUtil.rename(new File(copyDir, "hg"), new File(copyDir, ".hg")); + } + return copyDir; + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/BaseMercurialTestCase.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,74 +1,64 @@ -/* - * Copyright 2000-2011 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.MockSupport; -import jetbrains.buildServer.TempFiles; -import jetbrains.buildServer.vcs.impl.VcsRootImpl; -import jetbrains.buildServer.vcs.patches.PatchTestCase; -import org.jetbrains.annotations.NotNull; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; - -import java.io.File; -import java.io.IOException; - -/** - * @author Pavel.Sher - * Date: 31.07.2008 - */ -public abstract class BaseMercurialTestCase extends PatchTestCase { - protected TempFiles myTempFiles; - protected MockSupport myMockSupport; - - @Override - @BeforeMethod - protected void setUp() throws Exception { - super.setUp(); - - myMockSupport = new MockSupport(); - myMockSupport.setUpMocks(); - myTempFiles = new TempFiles(); - } - - @AfterMethod - protected void tearDown() throws Exception { - myMockSupport.tearDownMocks(); - myTempFiles.cleanup(); - } - - protected VcsRootImpl createVcsRoot(@NotNull String repPath) throws IOException { - VcsRootImpl vcsRoot = new VcsRootImpl(1, Constants.VCS_NAME); - vcsRoot.addProperty(Constants.HG_COMMAND_PATH_PROP, new File(Util.getHgPath()).getAbsolutePath()); - File repository = LocalRepositoryUtil.prepareRepository(repPath); - vcsRoot.addProperty(Constants.REPOSITORY_PROP, repository.getAbsolutePath()); - return vcsRoot; - } - - protected VcsRootImpl createVcsRoot(@NotNull String repPath, @NotNull String branchName) throws IOException { - VcsRootImpl vcsRoot = createVcsRoot(repPath); - vcsRoot.addProperty(Constants.BRANCH_NAME_PROP, branchName); - return vcsRoot; - } - - protected void cleanRepositoryAfterTest(@NotNull String repPath) { - LocalRepositoryUtil.forgetRepository(repPath); - } - - protected String simpleRepo() { - return new File("mercurial-tests/testData/rep1").getAbsolutePath(); - } -} +/* + * Copyright 2000-2011 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.TempFiles; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import jetbrains.buildServer.vcs.patches.PatchTestCase; +import org.jetbrains.annotations.NotNull; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import java.io.File; +import java.io.IOException; + +/** + * @author Pavel.Sher + * Date: 31.07.2008 + */ +public abstract class BaseMercurialTestCase extends PatchTestCase { + protected TempFiles myTempFiles; + + @Override + @BeforeMethod + protected void setUp() throws Exception { + super.setUp(); + myTempFiles = new TempFiles(); + } + + @AfterMethod + protected void tearDown() throws Exception { + myTempFiles.cleanup(); + } + + protected VcsRootImpl createVcsRoot(@NotNull String repPath) throws IOException { + File repository = LocalRepositoryUtil.prepareRepository(repPath); + return new VcsRootBuilder().repository(repository.getAbsolutePath()).build(); + } + + protected VcsRootImpl createVcsRoot(@NotNull String repPath, @NotNull String branchName) throws IOException { + File repository = LocalRepositoryUtil.prepareRepository(repPath); + return new VcsRootBuilder().repository(repository.getAbsolutePath()).branch(branchName).build(); + } + + protected void cleanRepositoryAfterTest(@NotNull String repPath) { + LocalRepositoryUtil.forgetRepository(repPath); + } + + protected String simpleRepo() { + return new File("mercurial-tests/testData/rep1").getAbsolutePath(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/DagFeaturesTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,92 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSetRevision; +import jetbrains.buildServer.log.Log4jFactory; +import jetbrains.buildServer.vcs.CheckoutRules; +import jetbrains.buildServer.vcs.ModificationData; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jetbrains.annotations.NotNull; +import org.jmock.Mockery; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.List; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +/** + * @author dmitry.neverov + */ +@Test +public class DagFeaturesTest { + + static { + Logger.setFactory(new Log4jFactory()); + } + + private TempFiles myTempFiles = new TempFiles(); + private MercurialVcsSupport myHg; + private String myRepository; + + @BeforeMethod + public void setUp() throws Exception { + ServerPluginConfig config = new ServerPluginConfigBuilder() + .cachesDir(myTempFiles.createTempDir()) + .pluginDataDir(myTempFiles.createTempDir()) + .build(); + myHg = Util.createMercurialServerSupport(new Mockery(), config); + + File original = new File("mercurial-tests/testData/rep2"); + File copy = new File(myTempFiles.createTempDir(), "rep2"); + LocalRepositoryUtil.copyRepository(original, copy); + myRepository = copy.getAbsolutePath(); + } + + public void tearDown() { + myTempFiles.cleanup(); + } + + + //TW-17882 + public void should_detect_changes_from_named_branches() throws Exception { + VcsRootImpl root = new VcsRootBuilder().repository(myRepository).build(); + + List<ModificationData> changes = myHg.collectChanges(root, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT); + assertEquals(4, changes.size()); + for (ModificationData change : changes) { + assertFalse(change.getParentRevisions().isEmpty()); + checkVersionsHaveNumbers(change.getParentRevisions()); + } + + changes = myHg.collectChanges(root, "12:1e620196c4b6", "18:df04faa7575a", CheckoutRules.DEFAULT); + assertEquals(6, changes.size()); + for (ModificationData change : changes) { + assertFalse(change.getParentRevisions().isEmpty()); + checkVersionsHaveNumbers(change.getParentRevisions()); + } + } + + + //TW-17882 + public void should_report_changes_only_from_merged_named_branches() throws Exception { + VcsRootImpl root = new VcsRootBuilder().repository(myRepository).build(); + List<ModificationData> changes = myHg.collectChanges(root, "1e620196c4b6", "505c5b9d01e6", CheckoutRules.DEFAULT); + assertEquals(2, changes.size()); + for (ModificationData change : changes) { + checkVersionsHaveNumbers(change.getParentRevisions()); + } + } + + + private void checkVersionsHaveNumbers(@NotNull List<String> versions) { + for (String version : versions) { + ChangeSetRevision rev = new ChangeSetRevision(version); + assertTrue(rev.getRevNumber() != -1); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathResolver.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,64 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.parameters.NullValueResolver; +import jetbrains.buildServer.parameters.ProcessingResult; +import jetbrains.buildServer.parameters.ReferencesResolverUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +/** +* @author dmitry.neverov +*/ +class HgPathResolver extends NullValueResolver { + @NotNull + public ProcessingResult resolve(@NotNull String value) { + if (ReferencesResolverUtil.containsReference(value)) { + if (value.equals(AgentSideCheckoutTest.HG_PATH_REFERENCE)) { + try { + return new ResolvedPath(Util.getHgPath()); + } catch (IOException e) { + return new Unresolved(value); + } + } else { + throw new IllegalArgumentException("Value resolver is asked to resolve " + value); + } + } else { + return new ResolvedPath(value); + } + } + + private static class ResolvedPath implements ProcessingResult { + private final String myPath; + ResolvedPath(final @NotNull String path) { + myPath = path; + } + public boolean isModified() { + return true; + } + @NotNull + public String getResult() { + return myPath; + } + public boolean isFullyResolved() { + return true; + } + } + + private static class Unresolved implements ProcessingResult { + private final String myUnresolvedValue; + Unresolved(@NotNull final String value) { + myUnresolvedValue = value; + } + public boolean isModified() { + return false; + } + @NotNull + public String getResult() { + return myUnresolvedValue; + } + public boolean isFullyResolved() { + return false; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersionTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,24 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; +import org.testng.annotations.Test; + +/** + * @author dmitry.neverov + */ +@Test +public class HgVersionTest extends TestCase { + + public void test_parse() { + checkParseCorrectly("Mercurial Distributed SCM (version 1.7.1+11-cc4e13c92dfa)", "1.7.1"); + checkParseCorrectly("Mercurial Distributed SCM (version 1.7)", "1.7.0"); + checkParseCorrectly("Mercurial Distributed SCM (version 1.5.2)", "1.5.2"); + } + + + private void checkParseCorrectly(@NotNull String versionToParse, @NotNull String expected) { + assertEquals(expected, HgVersion.parse(versionToParse).toString()); + } + +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/LocalRepositoryUtil.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,57 +1,61 @@ -/* - * Copyright 2000-2011 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.TempFiles; -import jetbrains.buildServer.util.FileUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Pavel.Sher - * Date: 14.07.2008 - */ -public class LocalRepositoryUtil { - private final static TempFiles myTempFiles = new TempFiles(); - private final static Map<String, File> myRepositories = new HashMap<String, File>(); - static { - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - public void run() { - myTempFiles.cleanup(); - } - })); - } - - public static File prepareRepository(@NotNull String repPath) throws IOException { - File repository = myRepositories.get(repPath); - if (repository != null) return repository; - final File tempDir = myTempFiles.createTempDir(); - FileUtil.copyDir(new File(repPath), tempDir); - if (new File(tempDir, "hg").isDirectory()) { - FileUtil.rename(new File(tempDir, "hg"), new File(tempDir, ".hg")); - } - myRepositories.put(repPath, tempDir); - return tempDir; - } - - public static void forgetRepository(@NotNull String repPath) { - myRepositories.remove(repPath); - } -} +/* + * Copyright 2000-2011 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.TempFiles; +import jetbrains.buildServer.util.FileUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Pavel.Sher + * Date: 14.07.2008 + */ +public class LocalRepositoryUtil { + private final static TempFiles myTempFiles = new TempFiles(); + private final static Map<String, File> myRepositories = new HashMap<String, File>(); + static { + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + myTempFiles.cleanup(); + } + })); + } + + public static File prepareRepository(@NotNull String repPath) throws IOException { + File repository = myRepositories.get(repPath); + if (repository != null) return repository; + final File tempDir = myTempFiles.createTempDir(); + copyRepository(new File(repPath), tempDir); + myRepositories.put(repPath, tempDir); + return tempDir; + } + + public static void forgetRepository(@NotNull String repPath) { + myRepositories.remove(repPath); + } + + + public static void copyRepository(File src, File dst) throws IOException { + FileUtil.copyDir(src, dst); + if (new File(dst, "hg").isDirectory()) + FileUtil.rename(new File(dst, "hg"), new File(dst, ".hg")); + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -19,16 +19,12 @@ import jetbrains.buildServer.ExecResult; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.serverSide.BuildServerListener; -import jetbrains.buildServer.serverSide.SBuildServer; -import jetbrains.buildServer.serverSide.ServerPaths; -import jetbrains.buildServer.util.EventDispatcher; import jetbrains.buildServer.vcs.*; import jetbrains.buildServer.vcs.impl.VcsRootImpl; import jetbrains.buildServer.vcs.patches.PatchBuilderImpl; import junit.framework.Assert; import org.jetbrains.annotations.NotNull; -import org.jmock.Mock; +import org.jmock.Mockery; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -37,33 +33,26 @@ import java.io.FilenameFilter; import java.io.IOException; import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import static com.intellij.openapi.util.io.FileUtil.copyDir; import static com.intellij.openapi.util.io.FileUtil.moveDirWithContent; @Test public class MercurialVcsSupportTest extends BaseMercurialTestCase { + private MercurialVcsSupport myVcs; - private ServerPaths myServerPaths; + private String myRep2Path = new File("mercurial-tests/testData/rep2").getAbsolutePath(); + private ServerPluginConfig myPluginConfig; @BeforeMethod protected void setUp() throws Exception { super.setUp(); - - Mock vcsManagerMock = new Mock(VcsManager.class); - vcsManagerMock.stubs().method("registerVcsSupport"); - Mock serverMock = new Mock(SBuildServer.class); - ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - serverMock.stubs().method("getExecutor").will(myMockSupport.returnValue(executor)); - - EventDispatcher<BuildServerListener> dispatcher = EventDispatcher.create(BuildServerListener.class); - - File systemDir = myTempFiles.createTempDir(); - myServerPaths = new ServerPaths(systemDir.getAbsolutePath(), systemDir.getAbsolutePath(), systemDir.getAbsolutePath()); - assertTrue(new File(myServerPaths.getCachesDir()).mkdirs()); - myVcs = new MercurialVcsSupport((VcsManager)vcsManagerMock.proxy(), myServerPaths, (SBuildServer)serverMock.proxy(), dispatcher, createPluginConfig()); + Mockery context = new Mockery(); + myPluginConfig = new ServerPluginConfigBuilder() + .cachesDir(myTempFiles.createTempDir()) + .pluginDataDir(myTempFiles.createTempDir()) + .build(); + myVcs = Util.createMercurialServerSupport(context, myPluginConfig); } protected String getTestDataPath() { @@ -82,7 +71,7 @@ } private List<ModificationData> collectChanges(@NotNull VcsRoot vcsRoot, @NotNull String from, @NotNull String to, @NotNull CheckoutRules rules) throws VcsException { - return ((CollectChangesByCheckoutRules) myVcs.getCollectChangesPolicy()).collectChanges(vcsRoot, from, to, rules); + return myVcs.collectChanges(vcsRoot, from, to, rules); } public void test_collect_changes_between_two_same_roots() throws Exception { @@ -92,6 +81,13 @@ do_check_for_collect_changes(changes); } + public void test_collect_changes_from_non_existing_revision() throws Exception { + VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); + VcsRootImpl sameVcsRoot = createVcsRoot(simpleRepo()); + List<ModificationData> changes = myVcs.collectChanges(vcsRoot, "0:9875b412a789", sameVcsRoot, "3:9522278aa38d", new CheckoutRules("")); + assertFalse(changes.isEmpty());//should return some changes from the toRoot + } + public void test_collect_changes() throws Exception { VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); List<ModificationData> changes = collectChanges(vcsRoot, "0:9875b412a788", "3:9522278aa38d", new CheckoutRules("")); @@ -143,7 +139,7 @@ ByteArrayOutputStream output = buildPatch(vcsRoot, null, "4:b06a290a363b", new CheckoutRules("")); checkPatchResult(output.toByteArray()); - File clonedReposParentDir = new File(myServerPaths.getCachesDir(), "mercurial"); + File clonedReposParentDir = myPluginConfig.getCachesDir(); assertTrue(clonedReposParentDir.isDirectory()); assertTrue(1 == clonedReposParentDir.list(new FilenameFilter() { public boolean accept(final File dir, final String name) { @@ -189,8 +185,8 @@ } public void test_clean_patch_with_subrepositories() throws Exception { - File r1 = new File(myServerPaths.getCachesDir() + File.separator + "mercurial", "r1"); - File r3 = new File(myServerPaths.getCachesDir() + File.separator + "mercurial", "r3"); + File r1 = new File(myPluginConfig.getCachesDir(), "r1"); + File r3 = new File(myPluginConfig.getCachesDir(), "r3"); copyDir(new File("mercurial-tests/testData/subrepos/r1"), r1); copyDir(new File("mercurial-tests/testData/subrepos/r3"), r3); moveDirWithContent(new File(r1, "hg"), new File(r1, ".hg")); @@ -344,15 +340,15 @@ VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); String repPath = vcsRoot.getProperty(Constants.REPOSITORY_PROP); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#test_branch"); - Settings settings = new Settings(vcsRoot); + Settings settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); assertEquals("test_branch", settings.getBranchName()); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#"); - settings = new Settings(vcsRoot); + settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); assertEquals("default", settings.getBranchName()); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath); - settings = new Settings(vcsRoot); + settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); assertEquals("default", settings.getBranchName()); } @@ -383,6 +379,13 @@ assertEquals("10:fc524efc2bc4", changes.get(1).getVersion()); } + public void collectChanges_should_return_all_changes_from_branch() throws Exception { + VcsRootImpl defaultBranchRoot = createVcsRoot(myRep2Path, "default"); + VcsRootImpl personalBranchRoot = createVcsRoot(myRep2Path, "personal-branch"); + List<ModificationData> modifications = myVcs.collectChanges(defaultBranchRoot, "16:505c5b9d01e6", personalBranchRoot, "17:9ec402c74298", CheckoutRules.DEFAULT); + assertEquals(3, modifications.size()); + } + public void test_collect_changes_merge() throws Exception { VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo()); @@ -412,10 +415,10 @@ VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo()); List<ModificationData> changes = collectChanges(vcsRoot, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT); - assertEquals(changes.size(), 2); + assertEquals(changes.size(), 4); - assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(0)); - assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(1)); + assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(2)); + assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(3)); } //TW-17530 @@ -443,7 +446,7 @@ VcsRootImpl root = new VcsRootImpl(1, Constants.VCS_NAME); root.addAllProperties(myVcs.getDefaultVcsProperties()); root.addProperty(Constants.REPOSITORY_PROP, "http://host.com/path"); - Settings settings = new Settings(root); + Settings settings = new Settings(new ServerHgPathProvider(myPluginConfig), root); assertFalse(settings.isUncompressedTransfer()); } @@ -501,16 +504,5 @@ public void test_collect_changes_using_checkout_rules() { assertTrue(myVcs.getCollectChangesPolicy() instanceof CollectChangesByCheckoutRules); } - - private ServerPluginConfig createPluginConfig() { - return new ServerPluginConfig() { - public boolean isUsePullProtocol() { - return true; - } - public int getPullTimeout() { - return CommandUtil.DEFAULT_COMMAND_TIMEOUT_SEC; - } - }; - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProviderTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,54 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertEquals; + +/** + * @author dmitry.neverov + */ +@Test +public class ServerHgPathProviderTest { + + private String myServerWideHgPath; + private String myVcsRootHgPath; + + + @BeforeMethod + public void setUp() { + myServerWideHgPath = null; + myVcsRootHgPath = "/vcs/root/hg/path"; + } + + + public void server_should_use_settings_from_vcs_root_if_server_wide_path_is_not_set() throws Exception { + myServerWideHgPath = null; + HgPathProvider provider = createHgPathProvider(); + Settings settings = createSettings(provider); + assertEquals(myVcsRootHgPath, provider.getHgPath(settings)); + } + + + public void server_should_use_server_wide_path_if_it_is_set() throws Exception { + myServerWideHgPath = "/server-wide/hg/path"; + HgPathProvider provider = createHgPathProvider(); + Settings settings = createSettings(provider); + assertEquals(myServerWideHgPath, provider.getHgPath(settings)); + } + + + private ServerHgPathProvider createHgPathProvider() { + ServerPluginConfig config = new ServerPluginConfigBuilder().hgPath(myServerWideHgPath).build(); + return new ServerHgPathProvider(config); + } + + + private Settings createSettings(HgPathProvider hgPathProvider) throws Exception { + VcsRootImpl root = new VcsRootBuilder().hgPath(myVcsRootHgPath).build(); + return new Settings(hgPathProvider, root); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerPluginConfigBuilder.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,70 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class ServerPluginConfigBuilder { + + private boolean myUsePullProtocol = true; + private String myHgPath; + private File myCachesDir; + private File myPluginDataDir; + + + @NotNull + public ServerPluginConfig build() { + return new ServerPluginConfig() { + + public boolean isUsePullProtocol() { + return myUsePullProtocol; + } + + public String getHgPath() { + return myHgPath; + } + + @NotNull + public File getCachesDir() { + if (myCachesDir == null) + throw new IllegalStateException("Caches dir is not set"); + return myCachesDir; + } + + @NotNull + public File getPluginDataDir() { + if (myPluginDataDir == null) + throw new IllegalStateException("Plugin data dir is not set"); + return myPluginDataDir; + } + + public int getPullTimeout() { + return ServerPluginConfigImpl.DEFAULT_PULL_TIMEOUT_SECONDS; + } + }; + } + + + public ServerPluginConfigBuilder userPullProtocol(boolean doUse) { + myUsePullProtocol = doUse; + return this; + } + + public ServerPluginConfigBuilder hgPath(String hgPath) { + myHgPath = hgPath; + return this; + } + + public ServerPluginConfigBuilder cachesDir(File cachesDir) { + myCachesDir = cachesDir; + return this; + } + + public ServerPluginConfigBuilder pluginDataDir(File pluginDataDir) { + myPluginDataDir = pluginDataDir; + return this; + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SettingsTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SettingsTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,136 +1,143 @@ -/* - * Copyright 2000-2011 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.TempFiles; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.vcs.impl.VcsRootImpl; -import junit.framework.TestCase; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -/** - * @author Pavel.Sher - */ -@Test -public class SettingsTest extends TestCase { - - private TempFiles myTempFiles = new TempFiles(); - private MirrorManager myMirrorManager; - - @Override - @BeforeMethod - public void setUp() throws Exception { - myMirrorManager = new MirrorManager(myTempFiles.createTempDir()); - } - - @Override - @AfterMethod - public void tearDown() throws Exception { - myTempFiles.cleanup(); - } - - public void test_url_without_credentials() { - VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); - } - - public void test_url_with_credentials() { - VcsRootImpl vcsRoot = createVcsRoot("http://user:pwd@host.com/path"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); - } - - public void test_url_with_username() { - VcsRootImpl vcsRoot = createVcsRoot("http://user@host.com/path"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); - } - - public void test_url_with_at_after_slash() { - VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path@"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://user:pwd@host.com/path@", settings.getRepositoryUrl()); - } - - public void test_url_with_at_in_username() { - VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path", "my.name@gmail.com", "1234"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://my.name%40gmail.com:1234@host.com/path", settings.getRepositoryUrl()); - } - - /** TW-13768 */ - public void test_underscore_in_host() { - VcsRootImpl vcsRoot = createVcsRoot("http://Klekovkin.SDK_GARANT:8000/", "my.name@gmail.com", "1234"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://my.name%40gmail.com:1234@Klekovkin.SDK_GARANT:8000/", settings.getRepositoryUrl()); - } - - /** TW-13768 */ - public void test_underscore_in_host_with_credentials_in_url() { - VcsRootImpl vcsRoot = createVcsRoot("http://me:mypass@Klekovkin.SDK_GARANT:8000/"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://me:mypass@Klekovkin.SDK_GARANT:8000/", settings.getRepositoryUrl()); - } - - public void test_windows_path() throws Exception { - VcsRootImpl vcsRoot = createVcsRoot("c:\\windows\\path"); - Settings settings = new Settings(vcsRoot); - assertEquals("c:\\windows\\path", settings.getRepositoryUrl()); - } - - public void test_file_scheme_has_no_credentials() { - VcsRootImpl vcsRoot = createVcsRoot("file:///path/to/repo", "my.name@gmail.com", "1234"); - Settings settings = new Settings(vcsRoot); - assertEquals("file:///path/to/repo", settings.getRepositoryUrl()); - } - - public void uncompressed_transfer() { - VcsRootImpl root = createVcsRoot("http://host.com/path"); - root.addProperty(Constants.UNCOMPRESSED_TRANSFER, "true"); - Settings settings = new Settings(root); - assertTrue(settings.isUncompressedTransfer()); - } - - //TW-18262 - public void ampersand_in_password() { - VcsRootImpl vcsRoot = createVcsRoot("http://some.org/path", "user", "m&n"); - Settings settings = new Settings(vcsRoot); - assertEquals("http://user:m%26n@some.org/path", settings.getRepositoryUrl()); - } - - //TW-18835 - public void test_ssh() { - VcsRootImpl vcsRoot = createVcsRoot("ssh://ourserver.com/mercurialrepo/", "user", "pwd"); - Settings settings = new Settings(vcsRoot); - assertEquals("ssh://user:pwd@ourserver.com/mercurialrepo/", settings.getRepositoryUrl()); - } - - private VcsRootImpl createVcsRoot(String url) { - return createVcsRoot(url, "user", "pwd"); - } - - private VcsRootImpl createVcsRoot(String url, String userName, String password) { - VcsRootImpl vcsRoot = new VcsRootImpl(1, Constants.VCS_NAME); - vcsRoot.addProperty(Constants.HG_COMMAND_PATH_PROP, "hg.exe"); - vcsRoot.addProperty(Constants.REPOSITORY_PROP, url); - vcsRoot.addProperty(Constants.USERNAME, userName); - vcsRoot.addProperty(Constants.PASSWORD, password); - return vcsRoot; - } -} +/* + * Copyright 2000-2011 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.TempFiles; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import junit.framework.TestCase; +import org.jetbrains.annotations.NotNull; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * @author Pavel.Sher + */ +@Test +public class SettingsTest extends TestCase { + + private TempFiles myTempFiles = new TempFiles(); + private MirrorManager myMirrorManager; + + @Override + @BeforeMethod + public void setUp() throws Exception { + myMirrorManager = new MirrorManager(myTempFiles.createTempDir()); + } + + @Override + @AfterMethod + public void tearDown() throws Exception { + myTempFiles.cleanup(); + } + + public void test_url_without_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); + } + + public void test_url_with_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("http://user:pwd@host.com/path"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); + } + + public void test_url_with_username() { + VcsRootImpl vcsRoot = createVcsRoot("http://user@host.com/path"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://user:pwd@host.com/path", settings.getRepositoryUrl()); + } + + public void test_url_with_at_after_slash() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path@"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://user:pwd@host.com/path@", settings.getRepositoryUrl()); + } + + public void test_url_with_at_in_username() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path", "my.name@gmail.com", "1234"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://my.name%40gmail.com:1234@host.com/path", settings.getRepositoryUrl()); + } + + /** TW-13768 */ + public void test_underscore_in_host() { + VcsRootImpl vcsRoot = createVcsRoot("http://Klekovkin.SDK_GARANT:8000/", "my.name@gmail.com", "1234"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://my.name%40gmail.com:1234@Klekovkin.SDK_GARANT:8000/", settings.getRepositoryUrl()); + } + + /** TW-13768 */ + public void test_underscore_in_host_with_credentials_in_url() { + VcsRootImpl vcsRoot = createVcsRoot("http://me:mypass@Klekovkin.SDK_GARANT:8000/"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://me:mypass@Klekovkin.SDK_GARANT:8000/", settings.getRepositoryUrl()); + } + + public void test_windows_path() throws Exception { + VcsRootImpl vcsRoot = createVcsRoot("c:\\windows\\path"); + Settings settings = createSettings(vcsRoot); + assertEquals("c:\\windows\\path", settings.getRepositoryUrl()); + } + + public void test_file_scheme_has_no_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("file:///path/to/repo", "my.name@gmail.com", "1234"); + Settings settings = createSettings(vcsRoot); + assertEquals("file:///path/to/repo", settings.getRepositoryUrl()); + } + + public void uncompressed_transfer() { + VcsRootImpl root = createVcsRoot("http://host.com/path"); + root.addProperty(Constants.UNCOMPRESSED_TRANSFER, "true"); + Settings settings = createSettings(root); + assertTrue(settings.isUncompressedTransfer()); + } + + //TW-18262 + public void ampersand_in_password() { + VcsRootImpl vcsRoot = createVcsRoot("http://some.org/path", "user", "m&n"); + Settings settings = createSettings(vcsRoot); + assertEquals("http://user:m%26n@some.org/path", settings.getRepositoryUrl()); + } + + //TW-18835 + public void test_ssh() { + VcsRootImpl vcsRoot = createVcsRoot("ssh://ourserver.com/mercurialrepo/", "user", "pwd"); + Settings settings = createSettings(vcsRoot); + assertEquals("ssh://user:pwd@ourserver.com/mercurialrepo/", settings.getRepositoryUrl()); + } + + private VcsRootImpl createVcsRoot(String url) { + return createVcsRoot(url, "user", "pwd"); + } + + private VcsRootImpl createVcsRoot(String url, String userName, String password) { + VcsRootImpl vcsRoot = new VcsRootImpl(1, Constants.VCS_NAME); + vcsRoot.addProperty(Constants.HG_COMMAND_PATH_PROP, "hg.exe"); + vcsRoot.addProperty(Constants.REPOSITORY_PROP, url); + vcsRoot.addProperty(Constants.USERNAME, userName); + vcsRoot.addProperty(Constants.PASSWORD, password); + return vcsRoot; + } + + private Settings createSettings(@NotNull final VcsRoot root) { + ServerPluginConfig config = new ServerPluginConfigBuilder().build(); + return new Settings(new ServerHgPathProvider(config), root); + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,6 +1,17 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import jetbrains.buildServer.serverSide.BuildServerListener; +import jetbrains.buildServer.serverSide.SBuildServer; +import jetbrains.buildServer.util.EventDispatcher; +import jetbrains.buildServer.vcs.VcsManager; +import org.jetbrains.annotations.NotNull; +import org.jmock.Expectations; +import org.jmock.Mockery; + +import java.io.File; import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; /** * @author dmitry.neverov @@ -14,8 +25,19 @@ if (providedHg != null) { return providedHg; } else { - return "mercurial-tests/testData/bin/hg.exe"; + return new File("mercurial-tests/testData/bin/hg.exe").getAbsolutePath(); } } + + public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, ServerPluginConfig config) throws IOException { + VcsManager vcsManager = context.mock(VcsManager.class); + final SBuildServer server = context.mock(SBuildServer.class); + final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + context.checking(new Expectations() {{ + allowing(server).getExecutor(); will(returnValue(executor)); + }}); + EventDispatcher<BuildServerListener> dispatcher = EventDispatcher.create(BuildServerListener.class); + return new MercurialVcsSupport(vcsManager, server, dispatcher, config, new ServerHgPathProvider(config), new CommandFactory(config)); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/VcsRootBuilder.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,65 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +/** + * @author dmitry.neverov + */ +public class VcsRootBuilder { + + private String myRepository; + private String myUsername; + private String myPassword; + private String myBranch; + private long myRootId = 1L; + private String myHgPath; + + public VcsRootImpl build() throws IOException { + VcsRootImpl vcsRoot = new VcsRootImpl(myRootId, Constants.VCS_NAME); + vcsRoot.addProperty(Constants.REPOSITORY_PROP, myRepository); + vcsRoot.addProperty(Constants.HG_COMMAND_PATH_PROP, myHgPath != null ? myHgPath : Util.getHgPath()); + vcsRoot.addProperty(Constants.USERNAME, myUsername); + vcsRoot.addProperty(Constants.PASSWORD, myPassword); + vcsRoot.addProperty(Constants.BRANCH_NAME_PROP, myBranch); + return vcsRoot; + } + + + public VcsRootBuilder repository(@NotNull String repository) { + myRepository = repository; + return this; + } + + + public VcsRootBuilder username(@NotNull String username) { + myUsername = username; + return this; + } + + + public VcsRootBuilder password(@NotNull String password) { + myPassword = password; + return this; + } + + + public VcsRootBuilder branch(@NotNull String branch) { + myBranch = branch; + return this; + } + + + public VcsRootBuilder rootId(long rootId) { + myRootId = rootId; + return this; + } + + + public VcsRootBuilder hgPath(String hgPath) { + myHgPath = hgPath; + return this; + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -2,9 +2,6 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.util.SystemInfo; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Util; -import jetbrains.buildServer.vcs.impl.VcsRootImpl; import junit.framework.TestCase; import org.testng.annotations.Test; @@ -18,13 +15,8 @@ public class BaseCommandTest extends TestCase { public void should_quote_command_line_arguments() throws IOException { - VcsRootImpl root = new VcsRootImpl(1, "rootForTest"); - root.addProperty(Constants.REPOSITORY_PROP, "http://some.org/repo.hg"); - root.addProperty(Constants.HG_COMMAND_PATH_PROP, Util.getHgPath()); File workingDir = new File("some dir"); - Settings settings = new Settings(root); - - BaseCommand command = new BaseCommand(settings, workingDir); + BaseCommand command = new BaseCommand("/path/to/hg", workingDir); GeneralCommandLine cl = command.createCommandLine(); cl.addParameter("param with spaces"); cl.addParameter("param with quote \" rm -rf /");
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,96 +1,94 @@ -/* - * Copyright 2000-2011 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.BaseTestCase; -import jetbrains.buildServer.TempFiles; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.LocalRepositoryUtil; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManager; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Util; -import jetbrains.buildServer.vcs.VcsException; -import jetbrains.buildServer.vcs.VcsRoot; -import jetbrains.buildServer.vcs.impl.VcsRootImpl; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class BaseCommandTestCase extends BaseTestCase { - private String myRepository; - private String myUsername; - private String myPassword; - private boolean myCloneRequired; - - public BaseCommandTestCase() { - } - - protected void setRepository(final String repository, boolean cloneRequired) { - myRepository = repository; - myCloneRequired = cloneRequired; - } - - protected void setUsername(final String username) { - myUsername = username; - } - - protected void setPassword(final String password) { - myPassword = password; - } - - protected <T> T runCommand(CommandExecutor<T> executor) throws IOException, VcsException { - Map<String, String> vcsRootProps = new HashMap<String, String>(); - - vcsRootProps.put(Constants.REPOSITORY_PROP, myRepository); - - if (myCloneRequired) { - File repository = LocalRepositoryUtil.prepareRepository(new File(myRepository).getAbsolutePath()); - vcsRootProps.put(Constants.REPOSITORY_PROP, repository.getAbsolutePath()); - } - - vcsRootProps.put(Constants.HG_COMMAND_PATH_PROP, Util.getHgPath()); - if (myUsername != null) { - vcsRootProps.put(Constants.USERNAME, myUsername); - } - if (myPassword != null) { - vcsRootProps.put(Constants.PASSWORD, myPassword); - } - - TempFiles tf = new TempFiles(); - File parentDir = tf.createTempDir(); - - MirrorManager mirrorManager = new MirrorManager(parentDir); - VcsRoot vcsRoot = new VcsRootImpl(1, vcsRootProps); - Settings settings = new Settings(vcsRoot); - final File workingDir = mirrorManager.getMirrorDir(settings.getRepositoryUrl()); - settings.setCustomWorkingDir(workingDir); - try { - if (myCloneRequired) { - new CloneCommand(settings, workingDir).execute(); - } - - return executor.execute(settings, workingDir); - } finally { - tf.cleanup(); - } - } - - public interface CommandExecutor<T> { - T execute(@NotNull Settings settings, File workingDir) throws VcsException; - } -} +/* + * Copyright 2000-2011 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.BaseTestCase; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.*; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class BaseCommandTestCase extends BaseTestCase { + private String myRepository; + private String myUsername; + private String myPassword; + private boolean myCloneRequired; + + public BaseCommandTestCase() { + } + + protected void setRepository(final String repository, boolean cloneRequired) { + myRepository = repository; + myCloneRequired = cloneRequired; + } + + protected void setUsername(final String username) { + myUsername = username; + } + + protected void setPassword(final String password) { + myPassword = password; + } + + protected <T> T runCommand(CommandExecutor<T> executor) throws IOException, VcsException { + Map<String, String> vcsRootProps = new HashMap<String, String>(); + + vcsRootProps.put(Constants.REPOSITORY_PROP, myRepository); + + if (myCloneRequired) { + File repository = LocalRepositoryUtil.prepareRepository(new File(myRepository).getAbsolutePath()); + vcsRootProps.put(Constants.REPOSITORY_PROP, repository.getAbsolutePath()); + } + + vcsRootProps.put(Constants.HG_COMMAND_PATH_PROP, Util.getHgPath()); + if (myUsername != null) { + vcsRootProps.put(Constants.USERNAME, myUsername); + } + if (myPassword != null) { + vcsRootProps.put(Constants.PASSWORD, myPassword); + } + + TempFiles tf = new TempFiles(); + File parentDir = tf.createTempDir(); + + MirrorManager mirrorManager = new MirrorManager(parentDir); + VcsRoot vcsRoot = new VcsRootImpl(1, vcsRootProps); + ServerPluginConfig config = new ServerPluginConfigBuilder().build(); + Settings settings = new Settings(new ServerHgPathProvider(config), vcsRoot); + final File workingDir = mirrorManager.getMirrorDir(settings.getRepositoryUrl()); + settings.setCustomWorkingDir(workingDir); + try { + if (myCloneRequired) { + new CloneCommand(settings, workingDir).execute(); + } + + return executor.execute(settings, workingDir); + } finally { + tf.cleanup(); + } + } + + public interface CommandExecutor<T> { + T execute(@NotNull Settings settings, File workingDir) throws VcsException; + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -2,9 +2,7 @@ import jetbrains.buildServer.BaseTestCase; import jetbrains.buildServer.TempFiles; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.LocalRepositoryUtil; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.Util; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.*; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.impl.VcsRootImpl; import org.testng.annotations.AfterMethod; @@ -44,7 +42,8 @@ root.addProperty(Constants.HG_COMMAND_PATH_PROP, Util.getHgPath()); File workingDir = myTempFiles.createTempDir(); - Settings settings = new Settings(root); + ServerPluginConfig config = new ServerPluginConfigBuilder().cachesDir(myTempFiles.createTempDir()).build(); + Settings settings = new Settings(new ServerHgPathProvider(config), root); settings.setCustomWorkingDir(workingDir); CloneCommand clone = new CloneCommand(settings, workingDir);
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,140 +1,184 @@ -/* - * Copyright 2000-2011 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.TempFiles; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -@Test -public class LogCommandTest extends BaseCommandTestCase { - - private TempFiles myTempFiles = new TempFiles(); - private File myTemplateFile; - - - @BeforeMethod - @Override - protected void setUp() throws Exception { - super.setUp(); - setRepository("mercurial-tests/testData/rep1", true); - myTemplateFile = myTempFiles.createTempFile(); - FileUtil.copyResource(MercurialVcsSupport.class, "/buildServerResources/log.template", myTemplateFile); - } - - @AfterMethod - public void tearDown() { - myTempFiles.cleanup(); - } - - - public void testOneChangeSet() throws Exception { - final String toId = "9875b412a788"; - List<ChangeSet> changes = runLog(null, toId); - assertEquals(1, changes.size()); - final ChangeSet changeSet = changes.get(0); - assertEquals(0, changeSet.getRevNumber()); - assertEquals(toId, changeSet.getId()); - assertEquals("pavel@localhost", changeSet.getUser()); - assertEquals("dir1 created", changeSet.getDescription()); - assertTrue(changeSet.getParents().isEmpty()); - } - - public void testMoreThanOneChangeSet() throws Exception { - final String fromId = "9875b412a788"; - final String toId = "7209b1f1d793"; - List<ChangeSet> changes = runLog(fromId, toId); - assertEquals(3, changes.size()); - ChangeSet changeSet1 = changes.get(0); - final ChangeSet changeSet2 = changes.get(1); - final ChangeSet changeSet3 = changes.get(2); - assertEquals("dir1 created", changeSet1.getDescription()); - assertEquals("new file added", changeSet2.getDescription()); - assertEquals("file4.txt added", changeSet3.getDescription()); - - changes = runLog(null, toId); - assertEquals(3, changes.size()); - changeSet1 = changes.get(2); - assertEquals("file4.txt added", changeSet1.getDescription()); - } - - public void changeset_parents() throws VcsException, IOException { - setRepository("mercurial-tests/testData/rep2", true); - List<ChangeSet> changes = runLog("6eeb8974fe67", "6eeb8974fe67"); - assertEquals(1, changes.size()); - ChangeSet cs = changes.get(0); - assertNotNull(cs.getParents()); - assertEquals(2, cs.getParents().size()); - assertTrue(cs.getParents().contains(new ChangeSetRevision("1:a3d15477d297"))); - assertTrue(cs.getParents().contains(new ChangeSetRevision("3:2538c02bafeb"))); - } - - public void parse_multiline_description() throws VcsException, IOException { - List<ChangeSet> changes = runLog("9babcf2d5705", "9c6a6b4aede0"); - assertEquals(1, changes.size()); - assertEquals("Multiline description\n" + - "description with new\n" + - "lines\n" + - "aaaa\n" + - "bbb", changes.get(0).getDescription()); - } - - public void log_result_should_contain_changed_files() throws Exception { - final String fromId = "7209b1f1d793"; - final String toId = "b06a290a363b"; - List<ChangeSet> csets = runLog(fromId, toId); - assertEquals(3, csets.size()); - - List<ModifiedFile> files = csets.get(0).getModifiedFiles(); - assertEquals(1, files.size()); - ModifiedFile file = files.get(0); - assertEquals(ModifiedFile.Status.ADDED, file.getStatus()); - assertEquals("dir1/file4.txt", file.getPath()); - - files = csets.get(1).getModifiedFiles(); - assertEquals(1, files.size()); - file = files.get(0); - assertEquals(ModifiedFile.Status.REMOVED, file.getStatus()); - assertEquals("dir1/file4.txt", file.getPath()); - - files = csets.get(2).getModifiedFiles(); - assertEquals(1, files.size()); - file = files.get(0); - assertEquals(ModifiedFile.Status.MODIFIED, file.getStatus()); - assertEquals("dir1/file3.txt", file.getPath()); - } - - - private List<ChangeSet> runLog(final String fromId, final String toId) throws IOException, VcsException { - return runCommand(new CommandExecutor<List<ChangeSet>>() { - public List<ChangeSet> execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { - LogCommand lc = new LogCommand(settings, workingDir, myTemplateFile); - lc.setFromRevId(fromId); - lc.setToRevId(toId); - return lc.execute(); - } - }); - } -} +/* + * Copyright 2000-2011 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.TempFiles; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Test +public class LogCommandTest extends BaseCommandTestCase { + + private TempFiles myTempFiles = new TempFiles(); + private File myTemplateFile; + + + @BeforeMethod + @Override + protected void setUp() throws Exception { + super.setUp(); + setRepository("mercurial-tests/testData/rep1", true); + myTemplateFile = myTempFiles.createTempFile(); + FileUtil.copyResource(MercurialVcsSupport.class, "/buildServerResources/log.template", myTemplateFile); + } + + + @AfterMethod + public void tearDown() { + myTempFiles.cleanup(); + } + + + public void testOneChangeSet() throws Exception { + final String toId = "9875b412a788"; + List<ChangeSet> changes = runLog(null, toId); + assertEquals(1, changes.size()); + final ChangeSet changeSet = changes.get(0); + assertEquals(0, changeSet.getRevNumber()); + assertEquals(toId, changeSet.getId()); + assertEquals("pavel@localhost", changeSet.getUser()); + assertEquals("dir1 created", changeSet.getDescription()); + } + + public void testMoreThanOneChangeSet() throws Exception { + final String fromId = "9875b412a788"; + final String toId = "7209b1f1d793"; + List<ChangeSet> changes = runLog(fromId, toId); + assertEquals(3, changes.size()); + ChangeSet changeSet1 = changes.get(0); + final ChangeSet changeSet2 = changes.get(1); + final ChangeSet changeSet3 = changes.get(2); + assertEquals("dir1 created", changeSet1.getDescription()); + assertEquals("new file added", changeSet2.getDescription()); + assertEquals("file4.txt added", changeSet3.getDescription()); + + changes = runLog(null, toId); + assertEquals(3, changes.size()); + changeSet1 = changes.get(2); + assertEquals("file4.txt added", changeSet1.getDescription()); + } + + public void changeset_parents() throws VcsException, IOException { + setRepository("mercurial-tests/testData/rep2", true); + List<ChangeSet> changes = runLog("6eeb8974fe67", "6eeb8974fe67"); + assertEquals(1, changes.size()); + ChangeSet cs = changes.get(0); + assertNotNull(cs.getParents()); + assertEquals(2, cs.getParents().size()); + assertTrue(cs.getParents().contains(new ChangeSetRevision("1:a3d15477d297"))); + assertTrue(cs.getParents().contains(new ChangeSetRevision("3:2538c02bafeb"))); + } + + public void parse_multiline_description() throws VcsException, IOException { + List<ChangeSet> changes = runLog("9babcf2d5705", "9c6a6b4aede0"); + assertEquals(1, changes.size()); + assertEquals("Multiline description\n" + + "description with new\n" + + "lines\n" + + "aaaa\n" + + "bbb", changes.get(0).getDescription()); + } + + + public void log_result_should_contain_changed_files() throws Exception { + final String fromId = "7209b1f1d793"; + final String toId = "b06a290a363b"; + List<ChangeSet> csets = runLog(fromId, toId); + assertEquals(3, csets.size()); + + List<ModifiedFile> files = csets.get(0).getModifiedFiles(); + assertEquals(1, files.size()); + ModifiedFile file = files.get(0); + assertEquals(ModifiedFile.Status.ADDED, file.getStatus()); + assertEquals("dir1/file4.txt", file.getPath()); + + files = csets.get(1).getModifiedFiles(); + assertEquals(1, files.size()); + file = files.get(0); + assertEquals(ModifiedFile.Status.REMOVED, file.getStatus()); + assertEquals("dir1/file4.txt", file.getPath()); + + files = csets.get(2).getModifiedFiles(); + assertEquals(1, files.size()); + file = files.get(0); + assertEquals(ModifiedFile.Status.MODIFIED, file.getStatus()); + assertEquals("dir1/file3.txt", file.getPath()); + } + + + public void log_results_should_have_parents() throws Exception { + setRepository("mercurial-tests/testData/rep2", true); + List<ChangeSet> csets = runLog("e0ad3ddde5aa", "df04faa7575a"); + for (ChangeSet cset : csets) { + assertFalse(cset.getParents().isEmpty()); + } + + Map<String, ChangeSet> csetMap = createChangeSetMap(csets); + + //see testData/README + checkParents(csetMap.get("e0ad3ddde5aa"), "0000000000000000000000000000000000000000"); + checkParents(csetMap.get("a3d15477d297"), "e0ad3ddde5aa"); + checkParents(csetMap.get("db8a04d262f3"), "e0ad3ddde5aa"); + checkParents(csetMap.get("2538c02bafeb"), "db8a04d262f3"); + checkParents(csetMap.get("6eeb8974fe67"), "a3d15477d297", "2538c02bafeb"); + checkParents(csetMap.get("b4937926e2e3"), "6eeb8974fe67"); + checkParents(csetMap.get("6066b677d026"), "b4937926e2e3"); + checkParents(csetMap.get("d6eaab231902"), "6eeb8974fe67"); + checkParents(csetMap.get("b6e2d176fe8e"), "6066b677d026", "d6eaab231902"); + } + + + private Map<String, ChangeSet> createChangeSetMap(@NotNull List<ChangeSet> csets) { + Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); + for (ChangeSet cset : csets) { + result.put(cset.getId(), cset); + } + return result; + } + + + private void checkParents(@NotNull final ChangeSet cset, String... parents) { + assertEquals(parents.length, cset.getParents().size()); + int i = 0; + for (ChangeSetRevision parent : cset.getParents()) { + assertEquals(parents[i], parent.getId()); + i++; + } + } + + + private List<ChangeSet> runLog(final String fromId, final String toId) throws IOException, VcsException { + return runCommand(new CommandExecutor<List<ChangeSet>>() { + public List<ChangeSet> execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { + LogCommand lc = new LogCommand(settings, workingDir, myTemplateFile); + lc.setFromRevId(fromId); + lc.setToRevId(toId); + return lc.execute(); + } + }); + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,48 +1,48 @@ -/* - * Copyright 2000-2011 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 org.testng.annotations.Test; - -import java.io.File; -import java.io.IOException; - -/** - * @author Pavel.Sher - */ -@Test -public class PushCommandTest extends BaseCommandTestCase { - public void hide_private_data() throws VcsException, IOException { - setRepository("http://some.host.com", false); - setUsername("user1"); - final String password = "pwd1"; - setPassword(password); - - try { - runCommand(new CommandExecutor<Boolean>() { - public Boolean execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { - PushCommand cmd = new PushCommand(settings, workingDir); - cmd.execute(); - return null; - } - }); - } catch (VcsException e) { - assertFalse(e.getMessage().contains(password)); - } - } -} +/* + * Copyright 2000-2011 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 org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; + +/** + * @author Pavel.Sher + */ +@Test +public class PushCommandTest extends BaseCommandTestCase { + public void hide_private_data() throws VcsException, IOException { + setRepository("http://some.host.com", false); + setUsername("user1"); + final String password = "pwd1"; + setPassword(password); + + try { + runCommand(new CommandExecutor<Boolean>() { + public Boolean execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { + PushCommand cmd = new PushCommand(settings, workingDir); + cmd.execute(); + return null; + } + }); + } catch (VcsException e) { + assertFalse(e.getMessage().contains(password)); + } + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -1,66 +1,66 @@ -/* - * Copyright 2000-2011 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 org.testng.annotations.Test; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -@Test -public class StatusCommandTest extends BaseCommandTestCase { - public void testAddedFile() throws IOException, VcsException { - setRepository("mercurial-tests/testData/rep1", true); - List<ModifiedFile> files = runStatus("9875b412a788", "1d446e82d356"); - assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.ADDED, md.getStatus()); - assertEquals("dir1/file3.txt", md.getPath().replace(File.separatorChar, '/')); - } - - public void testRemovedFile() throws IOException, VcsException { - setRepository("mercurial-tests/testData/rep1", true); - List<ModifiedFile> files = runStatus("7209b1f1d793", "9522278aa38d"); - assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.REMOVED, md.getStatus()); - assertEquals("dir1/file4.txt", md.getPath().replace(File.separatorChar, '/')); - } - - public void testModifiedFile() throws IOException, VcsException { - setRepository("mercurial-tests/testData/rep1", true); - List<ModifiedFile> files = runStatus("9522278aa38d", "b06a290a363b"); - assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.MODIFIED, md.getStatus()); - assertEquals("dir1/file3.txt", md.getPath().replace(File.separatorChar, '/')); - } - - private List<ModifiedFile> runStatus(final String fromId, final String toId) throws IOException, VcsException { - return runCommand(new CommandExecutor<List<ModifiedFile>>() { - public List<ModifiedFile> execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - StatusCommand st = new StatusCommand(settings, workingDir); - st.setFromRevId(fromId); - st.setToRevId(toId); - return st.execute(); - } - }); - } - -} +/* + * Copyright 2000-2011 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 org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +@Test +public class StatusCommandTest extends BaseCommandTestCase { + public void testAddedFile() throws IOException, VcsException { + setRepository("mercurial-tests/testData/rep1", true); + List<ModifiedFile> files = runStatus("9875b412a788", "1d446e82d356"); + assertEquals(1, files.size()); + ModifiedFile md = files.get(0); + assertEquals(ModifiedFile.Status.ADDED, md.getStatus()); + assertEquals("dir1/file3.txt", md.getPath().replace(File.separatorChar, '/')); + } + + public void testRemovedFile() throws IOException, VcsException { + setRepository("mercurial-tests/testData/rep1", true); + List<ModifiedFile> files = runStatus("7209b1f1d793", "9522278aa38d"); + assertEquals(1, files.size()); + ModifiedFile md = files.get(0); + assertEquals(ModifiedFile.Status.REMOVED, md.getStatus()); + assertEquals("dir1/file4.txt", md.getPath().replace(File.separatorChar, '/')); + } + + public void testModifiedFile() throws IOException, VcsException { + setRepository("mercurial-tests/testData/rep1", true); + List<ModifiedFile> files = runStatus("9522278aa38d", "b06a290a363b"); + assertEquals(1, files.size()); + ModifiedFile md = files.get(0); + assertEquals(ModifiedFile.Status.MODIFIED, md.getStatus()); + assertEquals("dir1/file3.txt", md.getPath().replace(File.separatorChar, '/')); + } + + private List<ModifiedFile> runStatus(final String fromId, final String toId) throws IOException, VcsException { + return runCommand(new CommandExecutor<List<ModifiedFile>>() { + public List<ModifiedFile> execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { + StatusCommand st = new StatusCommand(settings, workingDir); + st.setFromRevId(fromId); + st.setToRevId(toId); + return st.execute(); + } + }); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommandTest.java Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,25 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.*; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import junit.framework.TestCase; +import org.testng.annotations.Test; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +@Test +public class VersionCommandTest extends TestCase { + + public void test() throws Exception { + VcsRootImpl root = new VcsRootBuilder().repository("some/repository").build(); + ServerPluginConfig config = new ServerPluginConfigBuilder().build(); + Settings settings = new Settings(new ServerHgPathProvider(config), root); + VersionCommand versionCommand = new VersionCommand(settings, new File("..")); + HgVersion version = versionCommand.execute(); + assertNotNull(version); + } + +}
--- a/mercurial-tests/src/testng.xml Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/src/testng.xml Fri Dec 02 15:35:00 2011 +0300 @@ -1,17 +1,22 @@ -<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> -<suite name="Mercurial Suite"> - <test name="Mercurial Tests"> - <classes> - <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.BaseCommandTest"/> - <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.AgentSideCheckoutTest"/> - <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.SettingsTest"/> - <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerTest"/> - </classes> - </test> -</suite> +<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> +<suite name="Mercurial Suite"> + <test name="Mercurial Tests"> + <classes> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.BaseCommandTest"/> + <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.AgentSideCheckoutTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentSideCheckoutWithSubreposTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.SettingsTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersionTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommandTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgPathProviderTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.DagFeaturesTest"/> + </classes> + </test> +</suite>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/README Fri Dec 02 15:35:00 2011 +0300 @@ -0,0 +1,63 @@ +rep1 history: +@ 10:9c6a6b4aede0 Multiline description tip +| +| o 9:9babcf2d5705 name with space branch name with space +| | +| o 8:04c3ae4c6312 file modified test_branch +| | +| o 7:376dcf05cd2a new file added in the test_branch test_branch +|/ +o 6:b9deb9a1c6f4 files with spaces added +| +o 5:1d2cc6f3bc29 modified in subdir +| +o 4:b06a290a363b file modified +| +o 3:9522278aa38d file removed +| +o 2:7209b1f1d793 file4.txt added +| +o 1:1d446e82d356 new file added +| +o 0:9875b412a788 dir1 created + + +rep2 history: + +@ 18:df04faa7575a merge personal-branch tip +|\ +| o 17:9ec402c74298 another change to file.txt in personal-branch (personal-branch) +| | +o | 16:505c5b9d01e6 change file.txt back +| | +| o 15:96b78d73081d change file.txt in personal-branch (personal-branch) +| | +o | 14:78e67807f916 change file.txt +| | +| o 13:dec47d2d49bf create personal branch (personal-branch) +|/ +o 12:1e620196c4b6 merge with test branch +|\ +| o 11:48177654181c dir6 trunk +| | +o | 10:fc524efc2bc4 dir6 (test) +| | +o | 9:8c44244d6645 dir5 (test) +|/ +o 8:b6e2d176fe8e merge with conflict +|\ +| o 7:d6eaab231902 branch dir4 +| | +o | 6:6066b677d026 file41 +| | +o | 5:b4937926e2e3 dir4 +|/ +o 4:6eeb8974fe67 merge +|\ +| o 3:2538c02bafeb dir2 +| | +| o 2:db8a04d262f3 dir1 +| | +o | 1:a3d15477d297 dir3 +|/ +o 0:e0ad3ddde5aa file.txt
--- a/mercurial-tests/testData/rep2/hg/branchheads.cache Fri Dec 02 15:12:49 2011 +0300 +++ b/mercurial-tests/testData/rep2/hg/branchheads.cache Fri Dec 02 15:35:00 2011 +0300 @@ -1,3 +1,4 @@ -48177654181c50307bfb333f824126f54858cf53 11 -48177654181c50307bfb333f824126f54858cf53 default +df04faa7575acbe8e4cb112003e7db352a7589bf 18 +df04faa7575acbe8e4cb112003e7db352a7589bf default fc524efc2bc481e22365ab1452a41197060dbd9b test +9ec402c74298567d252e70bd4ef2be8235be62cc personal-branch