Mercurial > hg > mercurial
changeset 305:844986ea478d
Detect an update of subrepository URL and do clean checkout in this case.
Because hg itself cannot do update correctly
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Fri, 09 Sep 2011 12:05:23 +0400 |
parents | fa88221586c9 (current diff) e9cdb499350d (diff) |
children | 659287a241c2 |
files | |
diffstat | 52 files changed, 530 insertions(+), 182 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialAgentSideVcsSupport.java Fri Sep 09 12:05:23 2011 +0400 @@ -15,6 +15,7 @@ */ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import com.intellij.openapi.util.Pair; import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; @@ -32,7 +33,7 @@ import java.io.File; import java.io.IOException; -import java.util.Collections; +import java.util.*; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil.removePrivateData; @@ -48,30 +49,7 @@ } 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 BuildProgressLogger logger = build.getBuildLogger(); - final boolean useLocalMirrors = isUseLocalMirrors(build); - - return new IncludeRuleUpdater() { - public void process(@NotNull final IncludeRule includeRule, @NotNull final File workingDir) throws VcsException { - try { - checkRuleIsValid(includeRule); - Settings settings = new Settings(myHgPathProvider, vcsRoot); - if (useLocalMirrors) { - updateLocalMirror(vcsRoot, logger); - } - updateRepository(workingDir, settings, logger, useLocalMirrors); - 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(myMirrorManager, myHgPathProvider, vcsRoot, toVersion, build); } @NotNull @@ -85,95 +63,4 @@ public UpdatePolicy getUpdatePolicy() { return this; } - - private boolean isUseLocalMirrors(AgentRunningBuild build) { - String value = build.getSharedConfigParameters().get("teamcity.hg.use.local.mirrors"); - return "true".equals(value); - } - - 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, boolean useLocalMirrors) throws VcsException, IOException { - if (!Settings.isValidRepository(workingDir)) { - initRepository(workingDir, settings, logger, useLocalMirrors); - } else { - ensureUseRightRepository(workingDir, settings, logger, useLocalMirrors); - } - String defaultPullUrl = getDefaultPullUrl(settings, useLocalMirrors); - logger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new PullCommand(settings, workingDir).execute(); - 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) throws VcsException, IOException { - Settings settings = new Settings(myHgPathProvider, 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(); - 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 Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,292 @@ +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 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; + + + public MercurialIncludeRuleUpdater(@NotNull final MirrorManager mirrorManager, + @NotNull final HgPathProvider hgPathProvider, + @NotNull final VcsRoot root, + @NotNull final String toVersion, + @NotNull final AgentRunningBuild build) { + myMirrorManager = mirrorManager; + myHgPathProvider = hgPathProvider; + myRoot = root; + mySettings = new Settings(myHgPathProvider, myRoot); + myToVersion = toVersion; + myLogger = build.getBuildLogger(); + myUseLocalMirrors = isUseLocalMirrors(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 boolean isUseLocalMirrors(AgentRunningBuild build) { + String value = build.getSharedConfigParameters().get("teamcity.hg.use.local.mirrors"); + return "true".equals(value); + } + + + 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(); + 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(); + 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 { + myLogger.warning("URLs of subrepositories were changed, do clean checkout"); + FileUtil.delete(workingDir); + updateRepository(workingDir); + doUpdateWorkingDir(workingDir); + } + } + } + } + + + /*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/command/CatCommand.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Sep 09 12:05:23 2011 +0400 @@ -39,6 +39,10 @@ } 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"); @@ -63,7 +67,7 @@ cmdSize += path.length(); } while (cmdSize < MAX_CMD_LEN && !paths.isEmpty()); - runCommand(cli); + runCommand(cli, checkFailure); } return tempDir;
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandUtil.java Fri Sep 09 12:05:23 2011 +0400 @@ -86,6 +86,14 @@ } 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(); @@ -103,7 +111,8 @@ removePrivateData(privateData, res); - CommandUtil.checkCommandFailed(cmdStr, res); + if (checkFailure) + CommandUtil.checkCommandFailed(cmdStr, res); Loggers.VCS.debug("Command " + cmdStr + " output:\n" + res.getStdout()); return res; }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Fri Sep 09 12:05:23 2011 +0400 @@ -65,6 +65,7 @@ } ExecResult res = runCommand(cli); failIfNotEmptyStdErr(cli, res); - return res.getStdout(); + String output = res.getStdout().trim(); + return output.contains(" ") ? output.substring(0, output.indexOf(" ")) : output; } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Fri Sep 09 12:05:23 2011 +0400 @@ -228,11 +228,6 @@ IdentifyCommand identify = new IdentifyCommand(getSettings(), getWorkDirectory()); identify.setInLocalRepository(true); identify.setRevisionNumber(revNumber); - String output = identify.execute().trim(); - if (output.contains(" ")) { - return output.substring(0, output.indexOf(" ")); - } else { - return output; - } + return identify.execute(); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Fri Sep 09 12:05:23 2011 +0400 @@ -41,4 +41,9 @@ 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); + } }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Fri Sep 09 12:05:23 2011 +0400 @@ -449,6 +449,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 */
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Fri Sep 09 12:05:23 2011 +0400 @@ -18,16 +18,12 @@ import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; -import jetbrains.buildServer.parameters.ProcessingResult; -import jetbrains.buildServer.parameters.ReferencesResolverUtil; -import jetbrains.buildServer.parameters.ValueResolver; 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.BeforeMethod; @@ -46,7 +42,7 @@ @Test public class AgentSideCheckoutTest extends BaseMercurialTestCase { - private final static String HG_PATH_REFERENCE = "%" + HgDetector.AGENT_HG_PATH_PROPERTY + "%"; + final static String HG_PATH_REFERENCE = "%" + HgDetector.AGENT_HG_PATH_PROPERTY + "%"; private MercurialAgentSideVcsSupport myVcsSupport; private File myWorkDir; private File myMirrorsRootDir; @@ -66,6 +62,7 @@ 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())); }}); @@ -240,56 +237,4 @@ } - private static class HgPathResolver implements ValueResolver { - @NotNull - public ProcessingResult resolve(@NotNull String value) { - if (ReferencesResolverUtil.containsReference(value)) { - if (value.equals(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/AgentSideCheckoutWithSubreposTest.java Fri Sep 09 12:05:23 2011 +0400 @@ -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(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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathResolver.java Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,64 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.parameters.ProcessingResult; +import jetbrains.buildServer.parameters.ReferencesResolverUtil; +import jetbrains.buildServer.parameters.ValueResolver; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +/** +* @author dmitry.neverov +*/ +class HgPathResolver implements ValueResolver { + @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; + } + } +}
--- a/mercurial-tests/src/testng.xml Thu Sep 08 13:36:01 2011 +0400 +++ b/mercurial-tests/src/testng.xml Fri Sep 09 12:05:23 2011 +0400 @@ -10,6 +10,7 @@ <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"/>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/README Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,11 @@ +r1 history: +3:d350e7209906 Add different subrepository in the same path <- subrepository r2 = ../r3 (9e4a2fef1a1c) +2:4d7b3db8779f Remove subrepository <- subrepository removed +1:34017377d9c3 Add subrepository <- subrepository r2 = ../r2 (916933c1dd8e) +0:e4eced2b7381 Initial commit + +r2 history: +0:916933c1dd8e Initial commit + +r3 history: +0:9e4a2fef1a1c Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/branchheads.cache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,2 @@ +4d7b3db8779f75e0ca452fdd9a057a5c69665aa3 2 +4d7b3db8779f75e0ca452fdd9a057a5c69665aa3 default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/last-message.txt Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +Add different subrepository in the same path \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/requires Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/store/fncache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,3 @@ +data/a.i +data/.hgsub.i +data/.hgsubstate.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/tags.cache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,2 @@ +1 34017377d9c3d7bbcf665f845cce1e41c30bf4e9 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/undo.branch Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r1/hg/undo.desc Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,2 @@ +3 +commit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/last-message.txt Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/requires Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/store/fncache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +data/b.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r2/hg/undo.branch Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/last-message.txt Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +Initial commit \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/requires Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,3 @@ +revlogv1 +store +fncache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/store/fncache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,1 @@ +data/c.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/r3/hg/tags.cache Fri Sep 09 12:05:23 2011 +0400 @@ -0,0 +1,2 @@ +0 9e4a2fef1a1c04623a0d89edb4f3ba290cf2666e +