Mercurial > hg > mercurial
changeset 433:2617dcc70c15
Merge branch Faradi-7.0.x
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Tue, 15 May 2012 10:33:21 +0400 |
parents | 9a2b6a7a3381 (diff) 4a76645fe087 (current diff) |
children | a40ae1cfb67c |
files | mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java |
diffstat | 62 files changed, 1353 insertions(+), 671 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-agent/src/META-INF/build-agent-plugin-mercurial.xml Tue May 15 10:33:21 2012 +0400 @@ -7,4 +7,5 @@ <bean id="hgDetector" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgDetector" /> <bean id="pluginConfig" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentPluginConfigImpl"/> <bean id="mirrorManager" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerImpl" /> + <bean id="mirrorCleaner" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentMirrorCleaner" /> </beans>
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentHgPathProvider.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentHgPathProvider.java Tue May 15 10:33:21 2012 +0400 @@ -1,7 +1,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.agent.BuildAgentConfiguration; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.parameters.ProcessingResult; import jetbrains.buildServer.parameters.ValueResolver; import org.jetbrains.annotations.NotNull; @@ -19,8 +19,8 @@ } - public String getHgPath(@NotNull final Settings settings) { - String pathFromRoot = settings.getHgPath(); + public String getHgPath(@NotNull final HgVcsRoot root) { + String pathFromRoot = root.getHgPath(); return resolve(pathFromRoot); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleaner.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,61 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.agent.DirectoryCleanersProvider; +import jetbrains.buildServer.agent.DirectoryCleanersProviderContext; +import jetbrains.buildServer.agent.DirectoryCleanersRegistry; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.VcsRoot; +import jetbrains.buildServer.vcs.VcsRootEntry; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Date; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author dmitry.neverov + */ +public class AgentMirrorCleaner implements DirectoryCleanersProvider { + + private final static Logger ourLog = Logger.getInstance(AgentMirrorCleaner.class.getName()); + private final MirrorManager myMirrorManager; + + public AgentMirrorCleaner(@NotNull final MirrorManager mirrorManager) { + myMirrorManager = mirrorManager; + } + + @NotNull + public String getCleanerName() { + return "Mercurial mirrors clean"; + } + + public void registerDirectoryCleaners(@NotNull DirectoryCleanersProviderContext context, + @NotNull DirectoryCleanersRegistry registry) { + Set<String> repositoriesUsedInBuild = getRunningBuildRepositories(context); + for (Map.Entry<String, File> entry : myMirrorManager.getMappings().entrySet()) { + String repository = entry.getKey(); + File mirror = entry.getValue(); + if (!repositoriesUsedInBuild.contains(repository)) { + ourLog.debug("Register cleaner for mirror " + mirror.getAbsolutePath()); + registry.addCleaner(mirror, new Date(myMirrorManager.getLastUsedTime(mirror))); + } + } + } + + private Set<String> getRunningBuildRepositories(@NotNull DirectoryCleanersProviderContext context) { + Set<String> repositories = new HashSet<String>(); + for (VcsRootEntry entry : context.getRunningBuild().getVcsRootEntries()) { + VcsRoot root = entry.getVcsRoot(); + HgVcsRoot hgRoot = new HgVcsRoot(root); + AuthSettings auth = hgRoot.getAuthSettings(); + ourLog.debug("Repository " + auth.getRepositoryUrlWithHiddenPassword(hgRoot.getRepository()) + + " is used in the build, its mirror won't be cleaned"); + repositories.add(hgRoot.getRepository()); + } + return repositories; + } +}
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Tue May 15 10:33:21 2012 +0400 @@ -4,7 +4,8 @@ import jetbrains.buildServer.agent.BuildProgressLogger; import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.vcs.IncludeRule; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.VcsRoot; @@ -23,7 +24,7 @@ private final AgentPluginConfig myConfig; private final MirrorManager myMirrorManager; - private final Settings mySettings; + private final HgVcsRoot myRoot; private final AuthSettings myAuthSettings; private final String myHgPath; private final String myToVersion; @@ -39,9 +40,9 @@ @NotNull final AgentRunningBuild build) { myConfig = pluginConfig; myMirrorManager = mirrorManager; - mySettings = new Settings(hgPathProvider, root); - myAuthSettings = mySettings.getAuthSettings(); - myHgPath = mySettings.getHgCommandPath(); + myRoot = new HgVcsRoot(root); + myAuthSettings = myRoot.getAuthSettings(); + myHgPath = hgPathProvider.getHgPath(myRoot); myToVersion = toVersion; myLogger = build.getBuildLogger(); myUseLocalMirrors = myConfig.isUseLocalMirrors(build); @@ -53,9 +54,9 @@ try { checkRuleIsValid(rule); if (myUseLocalMirrors) - updateLocalMirror(mySettings.getRepository(), myToVersion); + updateLocalMirror(myRoot.getRepository(), myToVersion); updateRepository(workingDir); - updateWorkingDir(workingDir, myToVersion, mySettings.getRepository()); + updateWorkingDir(workingDir, myToVersion, myRoot.getRepository()); } catch (Exception e) { throwVcsException(e); } @@ -75,7 +76,7 @@ mirrorRepo.doClone().fromRepository(repositoryUrl) .setUpdateWorkingDir(false) .setUsePullProtocol(false) - .useUncompressedTransfer(mySettings.isUncompressedTransfer()) + .useUncompressedTransfer(myRoot.isUncompressedTransfer()) .call(); myLogger.message("Clone successfully finished"); } else { @@ -94,7 +95,7 @@ private void updateRepository(@NotNull File workingDir) throws VcsException, IOException { - String repositoryUrl = getDefaultPullUrl(mySettings, myUseLocalMirrors); + String repositoryUrl = getDefaultPullUrl(myRoot, myUseLocalMirrors); HgRepo repo = new HgRepo(workingDir, myHgPath, myAuthSettings); myLogger.message("Update repository " + workingDir.getAbsolutePath()); if (repo.isEmpty()) {//can do clone only in empty dir @@ -102,21 +103,25 @@ repo.doClone().fromRepository(repositoryUrl) .setUsePullProtocol(false) .setUpdateWorkingDir(false) - .useUncompressedTransfer(!myUseLocalMirrors && mySettings.isUncompressedTransfer()) + .useUncompressedTransfer(!myUseLocalMirrors && myRoot.isUncompressedTransfer()) .call(); - repo.setDefaultPath(mySettings.getRepository()); + repo.setDefaultPath(myRoot.getRepository()); myLogger.message("Repository successfully cloned"); } else { if (!repo.isValidRepository()) repo.init().call(); - repo.setDefaultPath(mySettings.getRepository()); + repo.setDefaultPath(myRoot.getRepository()); if (repo.containsRevision(myToVersion)) { myLogger.message("Repository already contains revision " + myToVersion); } else { myLogger.message("Start pulling changes from " + (myUseLocalMirrors ? "local mirror " : "") + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); - repo.pull().fromRepository(repositoryUrl) - .withTimeout(myPullTimeout) - .call(); + try { + repo.pull().fromRepository(repositoryUrl) + .withTimeout(myPullTimeout) + .call(); + } catch (UnrelatedRepositoryException e) { + throw new UnrelatedRepositoryException(myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl), workingDir); + } myLogger.message("Changes successfully pulled"); } } @@ -185,12 +190,12 @@ } - private String getDefaultPullUrl(Settings settings, boolean useLocalMirror) throws IOException { + private String getDefaultPullUrl(HgVcsRoot root, boolean useLocalMirror) throws IOException { if (useLocalMirror) { - File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepository()); + File mirrorDir = myMirrorManager.getMirrorDir(root.getRepository()); return mirrorDir.getCanonicalPath(); } else { - return settings.getRepository(); + return root.getRepository(); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgFileUtil.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,36 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.util.FileUtil; + +import java.io.File; +import java.io.IOException; + +/** + * @author dmitry.neverov + */ +public final class HgFileUtil { + + private final static String TEMP_DIR_PREFIX = "hg"; + + private HgFileUtil() { + } + + /** + * Create a temp dir with short name + * @return created dir + * @throws IOException in case of I/O error + */ + public static File createTempDir() throws IOException { + File parentDir = new File(FileUtil.getTempDirectory()); + int suffix = 0; + File dir; + do { + suffix++; + dir = new File(parentDir, TEMP_DIR_PREFIX + suffix); + } while (!dir.createNewFile()); + dir.delete(); + dir.mkdir(); + return dir; + } + +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathProvider.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgPathProvider.java Tue May 15 10:33:21 2012 +0400 @@ -1,6 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import org.jetbrains.annotations.NotNull; /** @@ -8,6 +8,6 @@ */ public interface HgPathProvider { - String getHgPath(@NotNull Settings settings); + String getHgPath(@NotNull HgVcsRoot root); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Tue May 15 10:33:21 2012 +0400 @@ -7,9 +7,7 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import static com.intellij.openapi.util.io.FileUtil.delete; import static java.util.Collections.emptyMap; @@ -95,6 +93,20 @@ return isEmptyDir(myWorkingDir); } + @NotNull + public List<String> listFiles() throws VcsException { + List<FileStatus> fileStatuses = status() + .fromRevision("tip") + .toRevision("tip") + .hideStatus() + .showAllFiles() + .call(); + List<String> files = new ArrayList<String>(fileStatuses.size()); + for (FileStatus fileStatus : fileStatuses) + files.add(fileStatus.getPath()); + return files; + } + public String getWorkingDirRevision() throws VcsException { return id().inLocalRepository().call(); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManager.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManager.java Tue May 15 10:33:21 2012 +0400 @@ -26,6 +26,8 @@ @NotNull public List<File> getMirrors(); + public long getLastUsedTime(@NotNull final File mirrorDir); + /** * Forget specified dir. After call to this method with non-empty dir, * all urls which were mapped to this dir will be mapped to another.
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManagerImpl.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MirrorManagerImpl.java Tue May 15 10:33:21 2012 +0400 @@ -56,6 +56,7 @@ if (result == null) { result = createDirFor(url); } + updateLastUsedTime(result); return result; } @@ -319,6 +320,44 @@ return sb.toString(); } + public long getLastUsedTime(@NotNull final File mirrorDir) { + File dotHg = new File(mirrorDir, ".hg"); + File timestamp = new File(dotHg, "timestamp"); + if (timestamp.exists()) { + try { + List<String> lines = FileUtil.readFile(timestamp); + if (lines.isEmpty()) + return mirrorDir.lastModified(); + else + return Long.valueOf(lines.get(0)); + } catch (IOException e) { + return mirrorDir.lastModified(); + } + } else { + return mirrorDir.lastModified(); + } + } + + private void updateLastUsedTime(@NotNull final File dir) { + File dotHg = new File(dir, ".hg"); + //create timestamp only if .hg exist, otherwise subsequent clone in this directory will + //fail since directory is not empty + if (!dotHg.exists()) + return; + + lockDir(dir); + try { + File timestamp = new File(dotHg, "timestamp"); + if (!timestamp.exists()) + timestamp.createNewFile(); + FileUtil.writeFileAndReportErrors(timestamp, String.valueOf(System.currentTimeMillis())); + } catch (IOException e) { + LOG.error("Error while updating timestamp in " + dir.getAbsolutePath(), e); + } finally { + unlockDir(dir); + } + } + final static class StandartHash implements HashCalculator { public long calc(String value) { return Hash.calc(value);
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Tue May 15 10:33:21 2012 +0400 @@ -16,7 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -90,7 +90,7 @@ private File createTmpDir() throws VcsException { try { - return FileUtil.createTempDirectory("mercurial", "catresult"); + return HgFileUtil.createTempDir(); } catch (IOException e) { throw new VcsException("Unable to create temporary directory"); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangeSet.java Tue May 15 10:33:21 2012 +0400 @@ -29,7 +29,7 @@ @NotNull private Date myTimestamp; private String myDescription; private List<ChangeSetRevision> myParents = new ArrayList<ChangeSetRevision>(); - private List<ModifiedFile> myModifiedFiles = new ArrayList<ModifiedFile>(); + private List<FileStatus> myModifiedFiles = new ArrayList<FileStatus>(); public ChangeSet(final int revNumber, @NotNull final String id) { super(revNumber, id); @@ -102,12 +102,12 @@ return getParents().isEmpty(); } - public void setModifiedFiles(@NotNull final List<ModifiedFile> files) { + public void setModifiedFiles(@NotNull final List<FileStatus> files) { myModifiedFiles = files; } @NotNull - public List<ModifiedFile> getModifiedFiles() { + public List<FileStatus> getModifiedFiles() { return myModifiedFiles; } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Tue May 15 10:33:21 2012 +0400 @@ -1,17 +1,15 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import com.intellij.execution.process.ProcessNotCreatedException; import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.ExecResult; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ConnectionRefusedException; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownFileException; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownRevisionException; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.*; 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.io.IOException; import java.util.HashSet; import java.util.Set; @@ -34,16 +32,19 @@ //e.g. pull command in hg 2.1 exits with 1 if no new changes were pulled. private static final Set<Integer> ERROR_EXIT_CODES = setOf(-1, 255); + private static final String MERCURIAL_NOT_FOUND_MESSAGE_PREFIX = "Cannot run program \""; + private static final String MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX1 = "No such file or directory"; + private static final String MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX2 = "The system cannot find the file specified"; + private final Logger myLogger; private final String myCommand; private final ExecResult myDelegate; private final Set<String> myPrivateData; - public CommandResult(@NotNull Logger logger, @NotNull String command, @NotNull ExecResult execResult) { - this(logger, command, execResult, Collections.<String>emptySet()); - } - - public CommandResult(@NotNull Logger logger, @NotNull String command, @NotNull ExecResult execResult, @NotNull Set<String> privateData) { + public CommandResult(@NotNull Logger logger, + @NotNull String command, + @NotNull ExecResult execResult, + @NotNull Set<String> privateData) { myLogger = logger; myCommand = command; myDelegate = execResult; @@ -77,9 +78,32 @@ myLogger.warn(message); if (hasImportantException()) myLogger.error("Error during executing '" + getCommand() + "'", getException()); + throwVcsException(message); + } + + private void throwVcsException(@NotNull String message) throws VcsException { + //noinspection ThrowableResultOfMethodCallIgnored + Throwable e = getException(); + if (isMercurialNotFoundException(e)) { + assert e != null; + throw new MercurialNotFoundException(myCommand, e); + } throw new VcsException(message); } + private boolean isMercurialNotFoundException(@Nullable Throwable e) { + return e instanceof ProcessNotCreatedException && + e.getCause() instanceof IOException && + isMercurialNotFoundErrorMessage(e.getMessage()); + } + + private boolean isMercurialNotFoundErrorMessage(@Nullable String message) { + return message != null && + message.startsWith(MERCURIAL_NOT_FOUND_MESSAGE_PREFIX) && + (message.endsWith(MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX1) || + message.endsWith(MERCURIAL_NOT_FOUND_MESSAGE_SUFFIX2)); + } + private void logStderr(String stderr) { myLogger.warn("Error output produced by: " + getCommand()); myLogger.warn(stderr); @@ -96,6 +120,7 @@ } private boolean isFailure() { + //noinspection ThrowableResultOfMethodCallIgnored return getException() != null || isErrorExitCode(); } @@ -114,6 +139,7 @@ } private boolean hasImportantException() { + //noinspection ThrowableResultOfMethodCallIgnored Throwable exception = getException(); return exception instanceof NullPointerException; } @@ -130,6 +156,7 @@ @Nullable private String getExceptionMessage() { + //noinspection ThrowableResultOfMethodCallIgnored Throwable exception = getException(); if (exception == null) return null;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/FileStatus.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,65 @@ +/* + * 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; + +/** + * Status of a file in a repository + */ +public class FileStatus { + + @NotNull private final Status myStatus; + @NotNull private final String myPath; + + public FileStatus(@NotNull final Status status, @NotNull final String path) { + myStatus = status; + myPath = path; + } + + /** + * @return status of a file + */ + @NotNull + public Status getStatus() { + return myStatus; + } + + /** + * @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 FileStatus that = (FileStatus) o; + + return myPath.equals(that.myPath) && myStatus == that.myStatus; + } + + @Override + public int hashCode() { + int result = myStatus.hashCode(); + result = 31 * result + myPath.hashCode(); + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/HgVcsRoot.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,160 @@ +/* + * 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.util.StringUtil; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Map; + +/** + * Represents mercurial VCS root + */ +public class HgVcsRoot implements VcsRoot { + + private static final String DEFAULT_BRANCH_NAME = "default"; + + private final VcsRoot myRoot; + private final String myRepository; + private final String myHgCommandPath; + private final String myBranchName; + private final boolean myUncompressedTransfer; + private final String myCustomClonePath; + private final String myUserForTag; + private final AuthSettings myAuthSettings; + private File myCustomWorkingDir; + + public HgVcsRoot(@NotNull final VcsRoot vcsRoot) { + myRoot = vcsRoot; + myRepository = getProperty(Constants.REPOSITORY_PROP); + myHgCommandPath = getProperty(Constants.HG_COMMAND_PATH_PROP); + myBranchName = getProperty(Constants.BRANCH_NAME_PROP); + myCustomClonePath = getProperty(Constants.SERVER_CLONE_PATH_PROP); + myUncompressedTransfer = "true".equals(getProperty(Constants.UNCOMPRESSED_TRANSFER)); + myUserForTag = getProperty(Constants.USER_FOR_TAG); + myAuthSettings = new AuthSettings(getProperty(Constants.USERNAME), getProperty(Constants.PASSWORD)); + } + + 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; + } + + public boolean isUncompressedTransfer() { + return myUncompressedTransfer; + } + + /** + * @return path to hg command as it is set in VCS root settings + */ + public String getHgPath() { + return myHgCommandPath; + } + + @Nullable + public String getUserForTag() { + return myUserForTag; + } + + public String getRepositoryUrlWithCredentials() { + return myAuthSettings.getRepositoryUrlWithCredentials(myRepository); + } + + /** + * 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 AuthSettings getAuthSettings() { + return myAuthSettings; + } + + + + public String getVcsName() { + return myRoot.getVcsName(); + } + + public String getProperty(String propertyName) { + return myRoot.getProperty(propertyName); + } + + public String getProperty(String propertyName, String defaultValue) { + return myRoot.getProperty(propertyName, defaultValue); + } + + public Map<String, String> getProperties() { + return myRoot.getProperties(); + } + + public String convertToString() { + return myRoot.convertToString(); + } + + public String convertToPresentableString() { + return myRoot.convertToPresentableString(); + } + + public long getPropertiesHash() { + return myRoot.getPropertiesHash(); + } + + public long getVcsRepositoryPropertiesHash() { + return myRoot.getVcsRepositoryPropertiesHash(); + } + + public String getName() { + return myRoot.getName(); + } + + public long getId() { + return myRoot.getId(); + } + + public Map<String, String> getPublicProperties() { + return myRoot.getPublicProperties(); + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Tue May 15 10:33:21 2012 +0400 @@ -31,6 +31,8 @@ import java.text.SimpleDateFormat; import java.util.*; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Status.makeStatus; + public class LogCommand extends VcsRootCommand { private final static String ZERO_PARENT_ID = "0000000000000000000000000000000000000000"; @@ -216,8 +218,8 @@ } - private List<ModifiedFile> getModifiedFiles(@NotNull final Element logEntry) { - List<ModifiedFile> result = new ArrayList<ModifiedFile>(); + private List<FileStatus> getModifiedFiles(@NotNull final Element logEntry) { + List<FileStatus> result = new ArrayList<FileStatus>(); Element paths = logEntry.getChild("paths"); if (paths == null) return result; @@ -229,24 +231,10 @@ } - private ModifiedFile getModifiedFile(@NotNull final Element path) { + private FileStatus 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; - } + return new FileStatus(makeStatus(action), filePath); } private void assignTrivialParents(final @NotNull List<ChangeSet> csets) throws VcsException {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ModifiedFile.java Tue May 15 10:21:05 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * 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/Settings.java Tue May 15 10:21:05 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,146 +0,0 @@ -/* - * 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.util.StringUtil; -import jetbrains.buildServer.vcs.VcsRoot; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; - -/** - * 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; - private final String myUserForTag; - private final AuthSettings myAuthSettings; - - 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)); - myUserForTag = vcsRoot.getProperty(Constants.USER_FOR_TAG); - myAuthSettings = new AuthSettings(myUsername, myPassword); - } - - 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; - } - - @Nullable - public String getUserForTag() { - return myUserForTag; - } - - public String getRepositoryUrlWithCredentials() { - return myAuthSettings.getRepositoryUrlWithCredentials(myRepository); - } - - /** - * 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 AuthSettings getAuthSettings() { - return myAuthSettings; - } - - public static boolean isValidRepository(File dir) { - // need better way to check that repository copy is ok - return dir.isDirectory() && new File(dir, ".hg").isDirectory(); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Status.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,51 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import org.jetbrains.annotations.NotNull; + +import static com.intellij.openapi.util.text.StringUtil.isEmpty; + +/** + * File status, see 'hg help status'. + */ +public enum Status { + + ADDED("added"), + MODIFIED("modified"), + REMOVED("removed"), + CLEAN("clean"), + MISSING("missing"), + NOT_TRACKED("not tracked"), + IGNORED("ignored"), + UNKNOWN("unknown"); + + private final String myName; + + Status(@NotNull String name) { + myName = name; + } + + @NotNull + public String getName() { + return myName; + } + + public static Status makeStatus(@NotNull final String s) { + if (isEmpty(s)) + return UNKNOWN; + return makeStatus(s.charAt(0)); + } + + public static Status makeStatus(final char c) { + switch (c) { + case 'A': return ADDED; + case 'M': return MODIFIED; + case 'R': return REMOVED; + case 'C': return CLEAN; + case '!': return MISSING; + case '?': return NOT_TRACKED; + case 'I': return IGNORED; + case ' ': return ADDED; + default : return UNKNOWN; + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Tue May 15 10:33:21 2012 +0400 @@ -23,9 +23,13 @@ import java.util.ArrayList; import java.util.List; +import static com.intellij.openapi.util.text.StringUtil.isEmpty; + public class StatusCommand extends VcsRootCommand { private String myFromId; private String myToId; + private boolean myShowAllFiles = false; + private boolean myHideStatus = false; public StatusCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { super(hgPath, workingDir, authSettings); @@ -51,39 +55,64 @@ return this; } - public List<ModifiedFile> call() throws VcsException { + /** + * Adds option -A (--all) + * @return self + */ + public StatusCommand showAllFiles() { + myShowAllFiles = true; + return this; + } + + /** + * Adds option -n (--no-status) + * @return self + */ + public StatusCommand hideStatus() { + myHideStatus = true; + return this; + } + + public List<FileStatus> call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("status"); + if (myShowAllFiles) + cli.addParameter("-A"); + if (myHideStatus) + cli.addParameter("-n"); cli.addParameter("--rev"); String from = myFromId; - if (from == null) from = "0"; + if (from == null) + from = "0"; String to = myToId; - if (to == null) to = "0"; + if (to == null) + to = "0"; cli.addParameter(from + ":" + to); CommandResult res = runCommand(cli); return parseFiles(res.getStdout()); } - public static List<ModifiedFile> parseFiles(final String stdout) { - List<ModifiedFile> result = new ArrayList<ModifiedFile>(); + private List<FileStatus> parseFiles(@NotNull String stdout) { + List<FileStatus> result = new ArrayList<FileStatus>(); 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)); + for (String line : lines) { + if (isEmpty(line)) + continue; + FileStatus fileStatus = parseLine(line); + if (!myHideStatus && fileStatus.getStatus() == Status.UNKNOWN) + continue; + result.add(fileStatus); } 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; - } + @NotNull + private FileStatus parseLine(@NotNull String line) { + if (myHideStatus) + return new FileStatus(Status.UNKNOWN, line); + char modifier = line.charAt(0); + String path = line.substring(2); + Status status = Status.makeStatus(modifier); + return new FileStatus(status, path); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Tue May 15 10:33:21 2012 +0400 @@ -15,11 +15,6 @@ */ 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); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/MercurialNotFoundException.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,15 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class MercurialNotFoundException extends VcsException { + + public MercurialNotFoundException(@NotNull String failedHgCommand, Throwable cause) { + super("'" + failedHgCommand + "' command failed: mercurial executable not found", cause); + } + +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/UnrelatedRepositoryException.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/UnrelatedRepositoryException.java Tue May 15 10:33:21 2012 +0400 @@ -1,10 +1,20 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; /** * @author dmitry.neverov */ public class UnrelatedRepositoryException extends VcsException { + public UnrelatedRepositoryException() { + super("Repository is unrelated"); + } + + public UnrelatedRepositoryException(@NotNull String repositoryUrl, @NotNull File workingDir) { + super("Repository " + repositoryUrl + " is unrelated to the repository in " + workingDir.getAbsolutePath()); + } }
--- a/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Tue May 15 10:33:21 2012 +0400 @@ -7,4 +7,6 @@ <bean id="repoFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.RepoFactory" /> <bean id="hgPathProvider" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgPathProvider"/> <bean id="mirrorManager" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MirrorManagerImpl" /> + <bean id="hgVcsRootFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVcsRootFactory" /> + <bean id="testConnection" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.HgTestConnectionSupport" /> </beans>
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Cleanup.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Cleanup.java Tue May 15 10:33:21 2012 +0400 @@ -1,7 +1,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; import com.intellij.openapi.diagnostic.Logger; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.serverSide.impl.LogUtil; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsManager; @@ -24,16 +24,13 @@ private final VcsManager myVcsManager; private final MirrorManager myMirrorManager; private final PluginConfig myConfig; - private final HgPathProvider myHgPathProvider; public Cleanup(@NotNull final VcsManager vcsManager, @NotNull final MirrorManager mirrorManager, - @NotNull final PluginConfig config, - @NotNull final HgPathProvider hgPathProvider) { + @NotNull final PluginConfig config) { myVcsManager = vcsManager; myMirrorManager = mirrorManager; myConfig = config; - myHgPathProvider = hgPathProvider; } public void run() { @@ -68,18 +65,14 @@ Map<String, File> mirrorMap = myMirrorManager.getMappings(); List<File> result = new ArrayList<File>(); for (VcsRoot root : mercurialVcsRoots()) { - File mirrorDir = mirrorMap.get(urlOf(root)); + HgVcsRoot hgRoot = new HgVcsRoot(root); + File mirrorDir = mirrorMap.get(hgRoot.getRepository()); if (mirrorDir != null) result.add(mirrorDir); } return result; } - private String urlOf(VcsRoot root) { - Settings s = new Settings(myHgPathProvider, root); - return s.getRepository(); - } - private Collection<VcsRoot> mercurialVcsRoots() { List<VcsRoot> mercurialRoots = new ArrayList<VcsRoot>(); for (VcsRoot root : myVcsManager.getAllRegisteredVcsRoots()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgTestConnectionSupport.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,59 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.MercurialNotFoundException; +import jetbrains.buildServer.vcs.TestConnectionSupport; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class HgTestConnectionSupport implements TestConnectionSupport { + + private final HgVcsRootFactory myHgVcsRootFactory; + private final RepoFactory myRepoFactory; + private final MirrorManager myMirrorManager; + private final HgPathProvider myHgPathProvider; + + public HgTestConnectionSupport(@NotNull HgVcsRootFactory hgVcsRootFactory, + @NotNull RepoFactory repoFactory, + @NotNull MirrorManager mirrorManager, + @NotNull HgPathProvider hgPathProvider) { + myHgVcsRootFactory = hgVcsRootFactory; + myRepoFactory = repoFactory; + myMirrorManager = mirrorManager; + myHgPathProvider = hgPathProvider; + } + + + public String testConnection(@NotNull VcsRoot vcsRoot) throws VcsException { + HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot); + HgRepo repo = createRepo(root); + try { + repo.id().repository(root.getRepository()) + .withAuthSettings(root.getAuthSettings()) + .call(); + return null; + } catch (MercurialNotFoundException e) { + throw friendlyException(root, e); + } + } + + + private VcsException friendlyException(HgVcsRoot root, MercurialNotFoundException e) { + return new VcsException("Cannot find mercurial executable at path '" + myHgPathProvider.getHgPath(root) + "'", e); + } + + private ServerHgRepo createRepo(HgVcsRoot root) throws VcsException { + return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); + } + + private File getWorkingDir(HgVcsRoot root) { + File customDir = root.getCustomWorkingDir(); + return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootFactory.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,48 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.util.StringUtil; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsRoot; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class HgVcsRootFactory { + + private File myDefaultWorkFolderParent; + + public HgVcsRootFactory(@NotNull final ServerPluginConfig config) { + myDefaultWorkFolderParent = config.getCachesDir(); + } + + + public HgVcsRoot createHgRoot(@NotNull VcsRoot root) throws VcsException { + HgVcsRoot hgRoot = new HgVcsRoot(root); + String customClonePath = hgRoot.getCustomClonePath(); + if (!StringUtil.isEmptyOrSpaces(customClonePath) && !myDefaultWorkFolderParent.equals(new File(customClonePath).getAbsoluteFile())) { + File parentDir = new File(customClonePath); + createClonedRepositoryParentDir(parentDir); + + // take last part of repository path + String repPath = hgRoot.getRepositoryUrlWithCredentials(); + String[] splitted = repPath.split("[/\\\\]"); + if (splitted.length > 0) { + repPath = splitted[splitted.length-1]; + } + + File customWorkingDir = new File(parentDir, repPath); + hgRoot.setCustomWorkingDir(customWorkingDir); + } + return hgRoot; + } + + private void createClonedRepositoryParentDir(final File parentDir) throws VcsException { + if (!parentDir.exists() && !parentDir.mkdirs()) + throw new VcsException("Failed to create parent directory for cloned repository: " + parentDir.getAbsolutePath()); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ListFilesSupport.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,61 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.ListDirectChildrenPolicy; +import jetbrains.buildServer.vcs.VcsException; +import jetbrains.buildServer.vcs.VcsFileData; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import static com.intellij.openapi.util.text.StringUtil.isEmpty; +import static java.util.regex.Pattern.compile; +import static java.util.regex.Pattern.quote; + +/** + * @author dmitry.neverov + */ +public class ListFilesSupport implements ListDirectChildrenPolicy { + + private final MercurialVcsSupport myVcs; + private final HgVcsRoot myRoot; + private final HgRepo myRepo; + + public ListFilesSupport(@NotNull MercurialVcsSupport vcs, + @NotNull HgVcsRoot root, + @NotNull HgRepo repo) { + myVcs = vcs; + myRoot = root; + myRepo = repo; + } + + @NotNull + public List<VcsFileData> listFiles(@NotNull String dir) throws VcsException { + myVcs.syncRepository(myRoot); + String dirPath = isEmpty(dir) || dir.endsWith("/") ? dir : dir + "/"; + return listFilesIn(dirPath); + } + + + @NotNull + private List<VcsFileData> listFilesIn(@NotNull String dir) throws VcsException { + List<VcsFileData> result = new ArrayList<VcsFileData>(); + Pattern p = compile(quote(File.separator)); + for (String file : myRepo.listFiles()) { + String canonicalFile = p.matcher(file).replaceAll("/"); + if (!canonicalFile.startsWith(dir)) + continue; + String relativePath = canonicalFile.substring(dir.length()); + int idx = relativePath.indexOf("/"); + if (idx >= 0) { + result.add(new VcsFileData(relativePath.substring(0, idx), true)); + } else { + result.add(new VcsFileData(relativePath, false)); + } + } + return result; + } +}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Tue May 15 10:33:21 2012 +0400 @@ -25,7 +25,6 @@ import jetbrains.buildServer.serverSide.*; import jetbrains.buildServer.util.EventDispatcher; import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.util.cache.ResetCacheRegister; import jetbrains.buildServer.vcs.*; import jetbrains.buildServer.vcs.impl.VcsRootImpl; @@ -51,15 +50,16 @@ * <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, - CollectChangesBetweenRoots { + CollectChangesBetweenRoots, BuildPatchByCheckoutRules { private final VcsManager myVcsManager; - private final File myDefaultWorkFolderParent; private final MirrorManager myMirrorManager; private final ServerPluginConfig myConfig; private final HgPathProvider myHgPathProvider; private final RepoFactory myRepoFactory; + private final HgVcsRootFactory myHgVcsRootFactory; private final FileFilter myIgnoreDotHgFilter = new IgnoreDotHgFilter(); private final FileFilter myAcceptAllFilter = new AcceptAllFilter(); + private final HgTestConnectionSupport myTestConnection; public MercurialVcsSupport(@NotNull final VcsManager vcsManager, @NotNull final SBuildServer server, @@ -68,18 +68,21 @@ @NotNull final ServerPluginConfig config, @NotNull final HgPathProvider hgPathProvider, @NotNull final RepoFactory repoFactory, - @NotNull final MirrorManager mirrorManager) { + @NotNull final MirrorManager mirrorManager, + @NotNull final HgVcsRootFactory hgVcsRootFactory, + @NotNull final HgTestConnectionSupport testConnection) { myVcsManager = vcsManager; myConfig = config; - myDefaultWorkFolderParent = myConfig.getCachesDir(); myMirrorManager = mirrorManager; myHgPathProvider = hgPathProvider; myRepoFactory = repoFactory; + myHgVcsRootFactory = hgVcsRootFactory; + myTestConnection = testConnection; resetCacheHandlerManager.registerHandler(new MercurialResetCacheHandler(myMirrorManager)); dispatcher.addListener(new BuildServerAdapter() { @Override public void cleanupFinished() { - server.getExecutor().submit(new Cleanup(myVcsManager, myMirrorManager, myConfig, myHgPathProvider)); + server.getExecutor().submit(new Cleanup(myVcsManager, myMirrorManager, myConfig)); } @Override @@ -119,9 +122,9 @@ } } - private List<VcsChange> toVcsChanges(final List<ModifiedFile> modifiedFiles, String prevVer, String curVer, CheckoutRules rules) { + private List<VcsChange> toVcsChanges(final List<FileStatus> modifiedFiles, String prevVer, String curVer, CheckoutRules rules) { List<VcsChange> files = new ArrayList<VcsChange>(); - for (ModifiedFile mf: modifiedFiles) { + for (FileStatus mf: modifiedFiles) { final String path = rules.map(mf.getPath()); if (shouldInclude(path)) files.add(toVcsChange(mf, prevVer, curVer, path)); @@ -133,7 +136,7 @@ return path != null; } - private VcsChange toVcsChange(ModifiedFile mf, String prevVer, String curVer, String mappedPath) { + private VcsChange toVcsChange(FileStatus mf, String prevVer, String curVer, String mappedPath) { String normalizedPath = PathUtil.normalizeSeparator(mf.getPath()); VcsChangeInfo.Type changeType = getChangeType(mf.getStatus()); if (changeType == null) { @@ -143,7 +146,7 @@ return new VcsChange(changeType, mf.getStatus().getName(), normalizedPath, mappedPath, prevVer, curVer); } - private VcsChangeInfo.Type getChangeType(final ModifiedFile.Status status) { + private VcsChangeInfo.Type getChangeType(final Status status) { switch (status) { case ADDED:return VcsChangeInfo.Type.ADDED; case MODIFIED:return VcsChangeInfo.Type.CHANGED; @@ -164,9 +167,9 @@ @NotNull public byte[] getContent(@NotNull final String filePath, @NotNull final VcsRoot vcsRoot, @NotNull final String version) throws VcsException { ChangeSet cset = new ChangeSet(version); - Settings settings = createSettings(vcsRoot); - syncRepository(settings, cset); - HgRepo repo = createRepo(settings); + HgVcsRoot root = myHgVcsRootFactory.createHgRoot(vcsRoot); + syncRepository(root, cset); + HgRepo repo = createRepo(root); File parentDir = repo.cat().files(filePath).atRevision(cset).call(); File file = new File(parentDir, filePath); try { @@ -212,14 +215,14 @@ @NotNull public String getCurrentVersion(@NotNull final VcsRoot root) throws VcsException { - Settings settings = createSettings(root); - syncRepository(settings); - HgRepo repo = createRepo(settings); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + syncRepository(hgRoot); + HgRepo repo = createRepo(hgRoot); Map<String, ChangeSet> result = repo.branches().call(); - if (!result.containsKey(settings.getBranchName())) { - throw new VcsException("Unable to find current version for the branch: " + settings.getBranchName()); + if (!result.containsKey(hgRoot.getBranchName())) { + throw new VcsException("Unable to find current version for the branch: " + hgRoot.getBranchName()); } - return result.get(settings.getBranchName()).getFullVersion(); + return result.get(hgRoot.getBranchName()).getFullVersion(); } public boolean sourcesUpdatePossibleIfChangesNotFound(@NotNull final VcsRoot root) { @@ -233,28 +236,7 @@ @Override public TestConnectionSupport getTestConnectionSupport() { - return new TestConnectionSupport() { - public String testConnection(@NotNull final VcsRoot vcsRoot) throws VcsException { - Settings settings = createSettings(vcsRoot); - String idResult = createRepo(settings).id() - .repository(settings.getRepository()) - .withAuthSettings(settings.getAuthSettings()) - .call(); - StringBuilder res = new StringBuilder(); - res.append(quoteIfNeeded(settings.getHgCommandPath())); - res.append(" identify "); - res.append(quoteIfNeeded(settings.getAuthSettings().getRepositoryUrlWithHiddenPassword(settings.getRepository()))); - res.append('\n').append(idResult); - return res.toString(); - } - }; - } - - private String quoteIfNeeded(@NotNull String str) { - if (str.indexOf(' ') != -1) { - return "\"" + str + "\""; - } - return str; + return myTestConnection; } @Nullable @@ -286,13 +268,17 @@ } // builds patch from version to version - private void buildIncrementalPatch(final Settings settings, @NotNull final ChangeSet fromVer, @NotNull final ChangeSet toVer, final PatchBuilder builder, final CheckoutRules checkoutRules) + private void buildIncrementalPatch(@NotNull final HgVcsRoot root, + @NotNull final ChangeSet fromVer, + @NotNull final ChangeSet toVer, + @NotNull final PatchBuilder builder, + @NotNull final CheckoutRules checkoutRules) throws VcsException, IOException { - HgRepo repo = createRepo(settings); - List<ModifiedFile> modifiedFiles = repo.status().fromRevision(fromVer).toRevision(toVer).call(); + HgRepo repo = createRepo(root); + List<FileStatus> modifiedFiles = repo.status().fromRevision(fromVer).toRevision(toVer).call(); List<String> notDeletedFiles = new ArrayList<String>(); - for (ModifiedFile f: modifiedFiles) { - if (f.getStatus() != ModifiedFile.Status.REMOVED) { + for (FileStatus f: modifiedFiles) { + if (f.getStatus() != Status.REMOVED) { notDeletedFiles.add(f.getPath()); } } @@ -302,11 +288,11 @@ File parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call(); try { - for (ModifiedFile f: modifiedFiles) { + for (FileStatus f: modifiedFiles) { String mappedPath = checkoutRules.map(f.getPath()); if (mappedPath == null) continue; // skip final File virtualFile = new File(mappedPath); - if (f.getStatus() == ModifiedFile.Status.REMOVED) { + if (f.getStatus() == Status.REMOVED) { builder.deleteFile(virtualFile, true); } else { File realFile = new File(parentDir, f.getPath()); @@ -331,25 +317,27 @@ } // builds patch by exporting files using specified version - private void buildFullPatch(final Settings settings, @NotNull final ChangeSet toVer, final PatchBuilder builder, final CheckoutRules checkoutRules) - throws IOException, VcsException { - File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId()); + private void buildFullPatch(@NotNull final HgVcsRoot root, + @NotNull final ChangeSet toVer, + @NotNull final PatchBuilder builder, + @NotNull final CheckoutRules checkoutRules) throws IOException, VcsException { + File tempDir = HgFileUtil.createTempDir(); try { - HgRepo repo = createRepo(settings); + HgRepo repo = createRepo(root); if (repo.hasSubreposAtRevision(toVer)) { - Loggers.VCS.debug("Repository '" + settings.getRepository() + "' has submodules at revision " + toVer.getId() + ", use 'hg clone' to build clean patch"); - File mirrorDir = getWorkingDir(settings); - HgRepo cloneOfTheMirror = createRepo(settings, tempDir); + Loggers.VCS.debug("Repository '" + root.getRepository() + "' has submodules at revision " + toVer.getId() + ", use 'hg clone' to build clean patch"); + File mirrorDir = getWorkingDir(root); + HgRepo cloneOfTheMirror = createRepo(root, tempDir); cloneOfTheMirror.doClone().fromRepository(mirrorDir) .setUpdateWorkingDir(false) .setUsePullProtocol(false) .useUncompressedTransfer(false) .call(); - cloneOfTheMirror.setDefaultPath(settings.getRepository()); + cloneOfTheMirror.setDefaultPath(root.getRepository()); cloneOfTheMirror.update().toRevision(toVer).call(); buildPatchFromDirectory(builder, tempDir, checkoutRules, myIgnoreDotHgFilter); } else { - Loggers.VCS.debug("Repository '" + settings.getRepository() + "' doesn't have submodules at revision " + toVer.getId() + ", use 'hg archive' to build clean patch"); + Loggers.VCS.debug("Repository '" + root.getRepository() + "' doesn't have submodules at revision " + toVer.getId() + ", use 'hg archive' to build clean patch"); repo.archive().revision(toVer).toDir(tempDir).call(); buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter); } @@ -391,56 +379,56 @@ } /* clone the repo if it doesn't exist, pull the repo if it doesn't contain specified changeSet */ - private void syncRepository(final Settings settings, final ChangeSet cset) throws VcsException { - File workingDir = getWorkingDir(settings); + private void syncRepository(@NotNull final HgVcsRoot root, @NotNull final ChangeSet cset) throws VcsException { + File workingDir = getWorkingDir(root); lockWorkDir(workingDir); - HgRepo repo = createRepo(settings); + HgRepo repo = createRepo(root); try { if (repo.isValidRepository()) { if (repo.containsRevision(cset)) return; try { - repo.pull().fromRepository(settings.getRepository()) + repo.pull().fromRepository(root.getRepository()) .withTimeout(myConfig.getPullTimeout()) .call(); } catch (UnrelatedRepositoryException e) { - Loggers.VCS.warn("Repository at " + settings.getRepository() + " is unrelated, clone it again"); + Loggers.VCS.warn("Repository at " + root.getRepository() + " is unrelated, clone it again"); myMirrorManager.forgetDir(workingDir); - syncRepository(settings, cset); + syncRepository(root, cset); } } else { - repo.doClone().fromRepository(settings.getRepository()) - .useUncompressedTransfer(settings.isUncompressedTransfer()) + repo.doClone().fromRepository(root.getRepository()) + .useUncompressedTransfer(root.isUncompressedTransfer()) .setUpdateWorkingDir(false) .call(); - repo.setDefaultPath(settings.getRepository()); + repo.setDefaultPath(root.getRepository()); } } finally { unlockWorkDir(workingDir); } } - private void syncRepository(final Settings settings) throws VcsException { - File workingDir = getWorkingDir(settings); + public void syncRepository(@NotNull final HgVcsRoot root) throws VcsException { + File workingDir = getWorkingDir(root); lockWorkDir(workingDir); - HgRepo repo = createRepo(settings); + HgRepo repo = createRepo(root); try { if (repo.isValidRepository()) { try { - repo.pull().fromRepository(settings.getRepository()) + repo.pull().fromRepository(root.getRepository()) .withTimeout(myConfig.getPullTimeout()) .call(); } catch (UnrelatedRepositoryException e) { - Loggers.VCS.warn("Repository at " + settings.getRepository() + " is unrelated, clone it again"); + Loggers.VCS.warn("Repository at " + root.getRepository() + " is unrelated, clone it again"); myMirrorManager.forgetDir(workingDir); - syncRepository(settings); + syncRepository(root); } } else { - repo.doClone().fromRepository(settings.getRepository()) + repo.doClone().fromRepository(root.getRepository()) .setUpdateWorkingDir(false) - .useUncompressedTransfer(settings.isUncompressedTransfer()) + .useUncompressedTransfer(root.isUncompressedTransfer()) .call(); - repo.setDefaultPath(settings.getRepository()); + repo.setDefaultPath(root.getRepository()); } } finally { unlockWorkDir(workingDir); @@ -469,9 +457,9 @@ @NotNull private Map<String, String> getBranchesRevisions(@NotNull VcsRoot root) throws VcsException { - Settings settings = createSettings(root); - syncRepository(settings); - HgRepo repo = createRepo(settings); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + syncRepository(hgRoot); + HgRepo repo = createRepo(hgRoot); Map<String, String> result = new HashMap<String, String>(); for (Map.Entry<String, ChangeSet> entry : repo.branches().call().entrySet()) { result.put(entry.getKey(), entry.getValue().getId()); @@ -489,16 +477,16 @@ @Nullable public PersonalBranchDescription getPersonalBranchDescription(@NotNull VcsRoot root, @NotNull String branchName) throws VcsException { - Settings settings = createSettings(root); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); VcsRoot branchRoot = createBranchRoot(root, branchName); String baseVersion = getCurrentVersion(root); String branchVersion = getCurrentVersion(branchRoot); - String mergeBase = getMergeBase(settings, baseVersion, branchVersion); + String mergeBase = getMergeBase(hgRoot, baseVersion, branchVersion); if (mergeBase == null) return null; - List<ChangeSet> changeSets = createRepo(settings).log() + List<ChangeSet> changeSets = createRepo(hgRoot).log() .fromRevision(mergeBase) .toRevision(branchVersion) .showCommitsFromAllBranches() @@ -523,10 +511,10 @@ public List<ModificationData> collectChanges(@NotNull VcsRoot fromRoot, @NotNull String fromRootRevision, @NotNull VcsRoot toRoot, @Nullable String toRootRevision, @NotNull CheckoutRules checkoutRules) throws VcsException { - Settings settings = createSettings(toRoot); - syncRepository(settings); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(toRoot); + syncRepository(hgRoot); String toRevision = toRootRevision != null ? toRootRevision : getCurrentVersion(toRoot); - String mergeBase = getMergeBase(settings, fromRootRevision, toRevision); + String mergeBase = getMergeBase(hgRoot, fromRootRevision, toRevision); if (mergeBase == null) return Collections.emptyList(); return collectChanges(toRoot, mergeBase, toRootRevision, checkoutRules); @@ -534,22 +522,22 @@ @Nullable - private String getMergeBase(@NotNull Settings settings, @NotNull String revision1, @NotNull String revision2) throws VcsException { - String result = createRepo(settings).mergeBase() + private String getMergeBase(@NotNull HgVcsRoot root, @NotNull String revision1, @NotNull String revision2) throws VcsException { + String result = createRepo(root).mergeBase() .revision1(revision1) .revision2(revision2) .call(); if (result == null) - result = getMinusNthCommit(settings, 10); + result = getMinusNthCommit(root, 10); return result; } @Nullable - private String getMinusNthCommit(@NotNull Settings settings, int n) throws VcsException { - LogCommand log = createRepo(settings).log() - .inBranch(settings.getBranchName()) - .toNamedRevision(settings.getBranchName()); + private String getMinusNthCommit(@NotNull HgVcsRoot root, int n) throws VcsException { + LogCommand log = createRepo(root).log() + .inBranch(root.getBranchName()) + .toNamedRevision(root.getBranchName()); if (n > 0) log.setLimit(n); List<ChangeSet> changeSets = log.call(); @@ -565,10 +553,10 @@ } public List<ModificationData> collectChanges(@NotNull VcsRoot root, @NotNull String fromVersion, @Nullable String currentVersion, @NotNull CheckoutRules checkoutRules) throws VcsException { - Settings settings = createSettings(root); - syncRepository(settings); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + syncRepository(hgRoot); List<ModificationData> result = new ArrayList<ModificationData>(); - for (ChangeSet cset : getChangesets(settings, fromVersion, currentVersion)) { + for (ChangeSet cset : getChangesets(hgRoot, fromVersion, currentVersion)) { result.add(createModificationData(cset, root, checkoutRules)); } return result; @@ -591,13 +579,13 @@ @NotNull - private List<ChangeSet> getChangesets(@NotNull final Settings settings, @NotNull final String fromVersion, @Nullable final String toVersion) throws VcsException { + private List<ChangeSet> getChangesets(@NotNull final HgVcsRoot root, @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(); try { - List<ChangeSet> changesets = createRepo(settings).collectChanges() + List<ChangeSet> changesets = createRepo(root).collectChanges() .fromRevision(fromCommit) .toRevision(toCommit) .call(); @@ -617,21 +605,30 @@ @NotNull public BuildPatchPolicy getBuildPatchPolicy() { - return new BuildPatchByCheckoutRules() { - public void buildPatch(@NotNull final VcsRoot root, - @Nullable final String fromVersion, - @NotNull final String toVersion, - @NotNull final PatchBuilder builder, - @NotNull final CheckoutRules checkoutRules) throws IOException, VcsException { - Settings settings = createSettings(root); - syncRepository(settings); - if (fromVersion == null) { - buildFullPatch(settings, new ChangeSet(toVersion), builder, checkoutRules); - } else { - buildIncrementalPatch(settings, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder, checkoutRules); - } + return this; + } + + public void buildPatch(@NotNull VcsRoot root, @Nullable String fromVersion, @NotNull String toVersion, @NotNull PatchBuilder builder, @NotNull CheckoutRules checkoutRules) throws IOException, VcsException { + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + syncRepository(hgRoot); + ChangeSet to = new ChangeSet(toVersion); + if (fromVersion == null) { + buildFullPatch(hgRoot, new ChangeSet(toVersion), builder, checkoutRules); + } else { + ChangeSet from = new ChangeSet(fromVersion); + HgRepo repo = createRepo(hgRoot); + if (!repo.containsRevision(from)) { + Loggers.VCS.info("Cannot find revision " + fromVersion + " in repository " + hgRoot.getRepository() + ", will build a full patch"); + cleanCheckoutDir(builder, checkoutRules); + buildFullPatch(hgRoot, to, builder, checkoutRules); + } else { + buildIncrementalPatch(hgRoot, new ChangeSet(fromVersion), new ChangeSet(toVersion), builder, checkoutRules); } - }; + } + } + + private void cleanCheckoutDir(@NotNull PatchBuilder builder, @NotNull CheckoutRules checkoutRules) throws IOException { + builder.deleteDirectory(new File(checkoutRules.map("")), true); } private void lockWorkDir(@NotNull File workDir) { @@ -653,19 +650,19 @@ File tmpDir = null; try { tmpDir = createLabelingTmpDir(); - Settings settings = createSettings(root); - settings.setCustomWorkingDir(tmpDir); - syncRepository(settings); - HgRepo repo = createRepo(settings); - repo.update().branch(settings.getBranchName()).call(); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + hgRoot.setCustomWorkingDir(tmpDir); + syncRepository(hgRoot); + HgRepo repo = createRepo(hgRoot); + repo.update().branch(hgRoot.getBranchName()).call(); String fixedTagname = fixTagName(label); repo.tag().revision(version) .tagName(fixedTagname) - .byUser(settings.getUserForTag()) + .byUser(hgRoot.getUserForTag()) .call(); - repo.push().toRepository(settings.getRepository()).call(); + repo.push().toRepository(hgRoot.getRepository()).call(); return fixedTagname; } finally { if (tmpDir != null) @@ -683,36 +680,11 @@ return label.replace(':', '_').replace('\r', '_').replace('\n', '_'); } - private File getWorkingDir(Settings s) { - File customDir = s.getCustomWorkingDir(); - return customDir != null ? customDir : myMirrorManager.getMirrorDir(s.getRepository()); + private File getWorkingDir(HgVcsRoot root) { + File customDir = root.getCustomWorkingDir(); + return customDir != null ? customDir : myMirrorManager.getMirrorDir(root.getRepository()); } - private Settings createSettings(final VcsRoot root) throws VcsException { - 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); - createClonedRepositoryParentDir(parentDir); - - // take last part of repository path - String repPath = settings.getRepositoryUrlWithCredentials(); - String[] splitted = repPath.split("[/\\\\]"); - if (splitted.length > 0) { - repPath = splitted[splitted.length-1]; - } - - File customWorkingDir = new File(parentDir, repPath); - settings.setCustomWorkingDir(customWorkingDir); - } - return settings; - } - - private void createClonedRepositoryParentDir(final File parentDir) throws VcsException { - if (!parentDir.exists() && !parentDir.mkdirs()) { - throw new VcsException("Failed to create parent directory for cloned repository: " + parentDir.getAbsolutePath()); - } - } public boolean isAgentSideCheckoutAvailable() { return true; @@ -751,21 +723,42 @@ } } - private ServerHgRepo createRepo(@NotNull Settings s) throws VcsException { - return myRepoFactory.create(getWorkingDir(s), s.getHgCommandPath(), s.getAuthSettings()); + private ServerHgRepo createRepo(@NotNull HgVcsRoot root) throws VcsException { + return myRepoFactory.create(getWorkingDir(root), myHgPathProvider.getHgPath(root), root.getAuthSettings()); } - private HgRepo createRepo(@NotNull Settings s, @NotNull File customDir) throws VcsException { - return myRepoFactory.create(customDir, s.getHgCommandPath(), s.getAuthSettings()); + private HgRepo createRepo(@NotNull HgVcsRoot root, @NotNull File customDir) throws VcsException { + return myRepoFactory.create(customDir, myHgPathProvider.getHgPath(root), root.getAuthSettings()); } @NotNull public String getBranchName(@NotNull final VcsRoot root) { try { - Settings s = createSettings(root); - return s.getBranchName(); + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + return hgRoot.getBranchName(); } catch (VcsException e) { return "default"; } } + + @NotNull + @Override + public Map<String, String> getVcsRepositoryProperties(@NotNull VcsRoot root) { + Map<String, String> rootProperties = root.getProperties(); + Map<String, String> repositoryProperties = new HashMap<String, String>(); + repositoryProperties.put(Constants.REPOSITORY_PROP, rootProperties.get(Constants.REPOSITORY_PROP)); + return repositoryProperties; + } + + + @Override + public ListFilesPolicy getListFilesPolicy(@NotNull VcsRoot root) { + try { + HgVcsRoot hgRoot = myHgVcsRootFactory.createHgRoot(root); + HgRepo repo = createRepo(hgRoot); + return new ListFilesSupport(this, hgRoot, repo); + } catch (VcsException e) { + return null; + } + } }
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProvider.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProvider.java Tue May 15 10:33:21 2012 +0400 @@ -1,6 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import org.jetbrains.annotations.NotNull; /** @@ -16,12 +16,12 @@ } - public String getHgPath(@NotNull final Settings settings) { + public String getHgPath(@NotNull final HgVcsRoot root) { String serverWideHgPath = myConfig.getHgPath(); if (serverWideHgPath != null) { return serverWideHgPath; } else { - String pathFromRoot = settings.getHgPath(); + String pathFromRoot = root.getHgPath(); if (pathFromRoot.equals(unresolvedAgentHgPath())) { //try to use hg from the PATH: return "hg";
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentMirrorCleanerTest.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,120 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.agent.*; +import jetbrains.buildServer.log.Log4jFactory; +import jetbrains.buildServer.vcs.*; +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.util.Date; +import java.util.HashMap; + +import static java.util.Arrays.asList; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.LocalRepositoryUtil.copyRepository; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot; + +/** + * @author dmitry.neverov + */ +@Test +public class AgentMirrorCleanerTest { + + static { + Logger.setFactory(new Log4jFactory()); + } + + private TempFiles myTempFiles = new TempFiles(); + private Mockery myContext; + private MercurialAgentSideVcsSupport myVcsSupport; + private AgentMirrorCleaner myCleaner; + private BuildProgressLogger myLogger; + private File myWorkDir; + private int myBuildCounter; + private MirrorManager myMirrorManager; + + @BeforeMethod + public void setUp() throws Exception { + myContext = new Mockery(); + myWorkDir = myTempFiles.createTempDir(); + + 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())); + }}); + + AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig); + AgentHgPathProvider hgPathProvider = new AgentHgPathProvider(agentConfig); + myMirrorManager = new MirrorManagerImpl(pluginConfig); + myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, hgPathProvider, myMirrorManager); + myCleaner = new AgentMirrorCleaner(myMirrorManager); + myLogger = myContext.mock(BuildProgressLogger.class); + myContext.checking(new Expectations() {{ + allowing(myLogger).message(with(any(String.class))); + allowing(myLogger).warning(with(any(String.class))); + }}); + } + + @AfterMethod + public void tearDown() { + myTempFiles.cleanup(); + } + + + public void should_add_cleaners_only_for_roots_not_used_in_build() throws Exception { + //setup mirrors for 2 roots on an agent: + final File repo1 = myTempFiles.createTempDir(); + final File repo2 = myTempFiles.createTempDir(); + copyRepository(new File("mercurial-tests/testData/rep1"), repo1); + copyRepository(new File("mercurial-tests/testData/rep2"), repo2); + + final VcsRoot root1 = vcsRoot().withUrl(repo1.getAbsolutePath()).build(); + final VcsRoot root2 = vcsRoot().withUrl(repo2.getAbsolutePath()).build(); + //update will initialize mirrors + doUpdate(root1, "4:b06a290a363b", myWorkDir); + doUpdate(root2, "8:b6e2d176fe8e", new File(myWorkDir, "subdir")); + + final File mirrorDir1 = myMirrorManager.getMirrorDir(repo1.getAbsolutePath()); + final File mirrorDir2 = myMirrorManager.getMirrorDir(repo2.getAbsolutePath()); + final Date mirrorDir1LastUsedTime = new Date(myMirrorManager.getLastUsedTime(mirrorDir1)); + final Date mirrorDir2LastUsedTime = new Date(myMirrorManager.getLastUsedTime(mirrorDir2)); + + //run build which uses root1: + final DirectoryCleanersProviderContext ctx = myContext.mock(DirectoryCleanersProviderContext.class); + myContext.checking(new Expectations(){{ + AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++); + allowing(build).getVcsRootEntries(); will(returnValue(asList(new VcsRootEntry(root1, CheckoutRules.DEFAULT)))); + allowing(ctx).getRunningBuild(); will(returnValue(build)); + }}); + + //cleaner should add cleaners only for roots which are not used in the running build + final DirectoryCleanersRegistry registry = myContext.mock(DirectoryCleanersRegistry.class); + myContext.checking(new Expectations() {{ + never(registry).addCleaner(with(mirrorDir1), with(mirrorDir1LastUsedTime)); + one(registry).addCleaner(with(mirrorDir2), with(mirrorDir2LastUsedTime)); + }}); + + myCleaner.registerDirectoryCleaners(ctx, registry); + myContext.assertIsSatisfied(); + } + + + private void doUpdate(@NotNull VcsRoot vcsRoot, @NotNull String toVersion, @NotNull File workDir) throws VcsException { + final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++); + myContext.checking(new Expectations() {{ + allowing(build).getBuildLogger(); will(returnValue(myLogger)); + allowing(build).getSharedConfigParameters(); will(returnValue(new HashMap<String, String>() {{ + put("teamcity.hg.use.local.mirrors", "true"); + }})); + }}); + myVcsSupport.getUpdater(vcsRoot, CheckoutRules.DEFAULT, toVersion, workDir, build, false).process(IncludeRule.createDefaultInstance(), workDir); + } + +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CleanupTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CleanupTest.java Tue May 15 10:33:21 2012 +0400 @@ -48,7 +48,7 @@ myMirrorManager = new MirrorManagerImpl(config); myVcsManager = myContext.mock(VcsManager.class); - myCleanup = new Cleanup(myVcsManager, myMirrorManager, config, new ServerHgPathProvider(config)); + myCleanup = new Cleanup(myVcsManager, myMirrorManager, config); } @AfterMethod
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVcsRootTest.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,118 @@ +/* + * 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.buildTriggers.vcs.mercurial.command.HgVcsRoot; +import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import junit.framework.TestCase; +import org.testng.annotations.Test; + +/** + * @author Pavel.Sher + */ +@Test +public class HgVcsRootTest extends TestCase { + + public void test_url_without_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://user:pwd@host.com/path", root.getRepositoryUrlWithCredentials()); + } + + public void test_url_with_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("http://user:pwd@host.com/path"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://user:pwd@host.com/path", root.getRepositoryUrlWithCredentials()); + } + + public void test_url_with_username() { + VcsRootImpl vcsRoot = createVcsRoot("http://user@host.com/path"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://user:pwd@host.com/path", root.getRepositoryUrlWithCredentials()); + } + + public void test_url_with_at_after_slash() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path@"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://user:pwd@host.com/path@", root.getRepositoryUrlWithCredentials()); + } + + public void test_url_with_at_in_username() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path", "my.name@gmail.com", "1234"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://my.name%40gmail.com:1234@host.com/path", root.getRepositoryUrlWithCredentials()); + } + + /** TW-13768 */ + public void test_underscore_in_host() { + VcsRootImpl vcsRoot = createVcsRoot("http://Klekovkin.SDK_GARANT:8000/", "my.name@gmail.com", "1234"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://my.name%40gmail.com:1234@Klekovkin.SDK_GARANT:8000/", root.getRepositoryUrlWithCredentials()); + } + + /** TW-13768 */ + public void test_underscore_in_host_with_credentials_in_url() { + VcsRootImpl vcsRoot = createVcsRoot("http://me:mypass@Klekovkin.SDK_GARANT:8000/"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://me:mypass@Klekovkin.SDK_GARANT:8000/", root.getRepositoryUrlWithCredentials()); + } + + public void test_windows_path() throws Exception { + VcsRootImpl vcsRoot = createVcsRoot("c:\\windows\\path"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("c:\\windows\\path", root.getRepositoryUrlWithCredentials()); + } + + public void test_file_scheme_has_no_credentials() { + VcsRootImpl vcsRoot = createVcsRoot("file:///path/to/repo", "my.name@gmail.com", "1234"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("file:///path/to/repo", root.getRepositoryUrlWithCredentials()); + } + + public void uncompressed_transfer() { + VcsRootImpl vcsRoot = createVcsRoot("http://host.com/path"); + vcsRoot.addProperty(Constants.UNCOMPRESSED_TRANSFER, "true"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertTrue(root.isUncompressedTransfer()); + } + + //TW-18262 + public void ampersand_in_password() { + VcsRootImpl vcsRoot = createVcsRoot("http://some.org/path", "user", "m&n"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("http://user:m%26n@some.org/path", root.getRepositoryUrlWithCredentials()); + } + + //TW-18835 + public void test_ssh() { + VcsRootImpl vcsRoot = createVcsRoot("ssh://ourserver.com/mercurialrepo/", "user", "pwd"); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + assertEquals("ssh://user:pwd@ourserver.com/mercurialrepo/", root.getRepositoryUrlWithCredentials()); + } + + 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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ListFilesSupportTest.java Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,90 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import com.intellij.openapi.diagnostic.Logger; +import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.log.Log4jFactory; +import jetbrains.buildServer.vcs.ListDirectChildrenPolicy; +import jetbrains.buildServer.vcs.VcsFileData; +import jetbrains.buildServer.vcs.VcsRoot; +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 jetbrains.buildServer.buildTriggers.vcs.mercurial.LocalRepositoryUtil.copyRepository; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +/** + * @author dmitry.neverov + */ +@Test +public class ListFilesSupportTest { + + static { + Logger.setFactory(new Log4jFactory()); + } + + private MercurialVcsSupport myVcs; + private VcsRoot myRoot; + + @BeforeMethod + protected void setUp() throws Exception { + TempFiles tempFiles = new TempFiles(); + Mockery context = new Mockery(); + ServerPluginConfig myPluginConfig = new ServerPluginConfigBuilder() + .cachesDir(tempFiles.createTempDir()) + .build(); + myVcs = Util.createMercurialServerSupport(context, myPluginConfig); + + File repo = tempFiles.createTempDir(); + copyRepository(new File("mercurial-tests/testData/rep1"), repo); + myRoot = vcsRoot().withUrl(repo.getAbsolutePath()).build(); + } + + + public void should_support_list_files() throws Exception { + assertNotNull(myVcs.getListFilesPolicy(myRoot)); + } + + + public void list_root_dir() throws Exception { + ListDirectChildrenPolicy policy = getListFilesPolicy(); + List<VcsFileData> files = policy.listFiles(""); + assertTrue(files.contains(dir("dir1"))); + assertTrue(files.contains(dir("dir with space"))); + assertTrue(files.contains(file("file.txt"))); + } + + + public void list_subdir() throws Exception { + ListDirectChildrenPolicy policy = getListFilesPolicy(); + List<VcsFileData> files = policy.listFiles("dir1"); + assertTrue(files.contains(file("file1.txt"))); + assertTrue(files.contains(file("file3.txt"))); + assertTrue(files.contains(dir("subdir"))); + + files = policy.listFiles("dir1/subdir/"); + assertTrue(files.contains(file("file2.txt"))); + } + + @NotNull + private ListDirectChildrenPolicy getListFilesPolicy() { + ListDirectChildrenPolicy listFilesPolicy = (ListDirectChildrenPolicy) myVcs.getListFilesPolicy(myRoot); + assert listFilesPolicy != null; + return listFilesPolicy; + } + + private VcsFileData dir(@NotNull String path) { + return new VcsFileData(path, true); + } + + private VcsFileData file(@NotNull String path) { + return new VcsFileData(path, false); + } + +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Tue May 15 10:33:21 2012 +0400 @@ -32,8 +32,7 @@ import java.io.IOException; import java.util.*; -import static com.intellij.openapi.util.io.FileUtil.copyDir; -import static com.intellij.openapi.util.io.FileUtil.moveDirWithContent; +import static com.intellij.openapi.util.io.FileUtil.*; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot; @Test @@ -123,8 +122,7 @@ private ByteArrayOutputStream buildPatch(VcsRoot vcsRoot, String from, String to, CheckoutRules rules) throws IOException, VcsException { final ByteArrayOutputStream output = new ByteArrayOutputStream(); final PatchBuilderImpl builder = new PatchBuilderImpl(output); - - ((BuildPatchByCheckoutRules)myVcs.getBuildPatchPolicy()).buildPatch(vcsRoot, from, to, builder, rules); + myVcs.buildPatch(vcsRoot, from, to, builder, rules); builder.close(); return output; } @@ -233,6 +231,22 @@ } } + + public void should_throw_friendly_exception_when_cannot_run_hg() throws Exception { + VcsRootImpl root = createVcsRoot(simpleRepo()); + File nonExistingHg = myTempFiles.createTempFile(); + delete(nonExistingHg); + String nonExistingHgPath = nonExistingHg.getAbsolutePath(); + root.addProperty(Constants.HG_COMMAND_PATH_PROP, nonExistingHgPath); + try { + myVcs.getTestConnectionSupport().testConnection(root); + fail("Exception expected"); + } catch (VcsException e) { + assertEquals(e.getMessage(), "Cannot find mercurial executable at path '" + nonExistingHgPath + "'"); + } + } + + public void test_tag() throws IOException, VcsException { VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); cleanRepositoryAfterTest(simpleRepo()); @@ -364,16 +378,16 @@ VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); String repPath = vcsRoot.getProperty(Constants.REPOSITORY_PROP); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#test_branch"); - Settings settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); - assertEquals("test_branch", settings.getBranchName()); + HgVcsRoot hgRoot = new HgVcsRoot(vcsRoot); + assertEquals("test_branch", hgRoot.getBranchName()); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#"); - settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); - assertEquals("default", settings.getBranchName()); + hgRoot = new HgVcsRoot(vcsRoot); + assertEquals("default", hgRoot.getBranchName()); vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath); - settings = new Settings(new ServerHgPathProvider(myPluginConfig), vcsRoot); - assertEquals("default", settings.getBranchName()); + hgRoot = new HgVcsRoot(vcsRoot); + assertEquals("default", hgRoot.getBranchName()); } public void build_patch_using_custom_clone_path() throws IOException, VcsException { @@ -389,6 +403,20 @@ assertTrue(new File(cloneDir, new File(vcsRoot.getProperty(Constants.REPOSITORY_PROP)).getName()).isDirectory()); } + public void build_patch_from_newer_revision_to_earlier() throws Exception { + setName("patch5"); + VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); + ByteArrayOutputStream output = buildPatch(vcsRoot, "6:b9deb9a1c6f4", "3:9522278aa38d", CheckoutRules.DEFAULT); + checkPatchResult(output.toByteArray()); + } + + public void build_patch_from_unknown_revision() throws Exception { + setName("patch6"); + VcsRootImpl vcsRoot = createVcsRoot(simpleRepo()); + ByteArrayOutputStream output = buildPatch(vcsRoot, "6:hahahahahaha", "3:9522278aa38d", new CheckoutRules("+:.=>path")); + checkPatchResult(output.toByteArray()); + } + private String mergeCommittsRepo() { return new File("mercurial-tests/testData/rep2").getAbsolutePath(); } @@ -470,8 +498,8 @@ 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(new ServerHgPathProvider(myPluginConfig), root); - assertFalse(settings.isUncompressedTransfer()); + HgVcsRoot hgRoot = new HgVcsRoot(root); + assertFalse(hgRoot.isUncompressedTransfer()); }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProviderTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgPathProviderTest.java Tue May 15 10:33:21 2012 +0400 @@ -1,7 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.vcs.impl.VcsRootImpl; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -27,16 +26,16 @@ 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)); + HgVcsRoot root = createHgRoot(); + assertEquals(myVcsRootHgPath, provider.getHgPath(root)); } 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)); + HgVcsRoot root = createHgRoot(); + assertEquals(myServerWideHgPath, provider.getHgPath(root)); } @@ -46,9 +45,8 @@ } - private Settings createSettings(HgPathProvider hgPathProvider) throws Exception { - VcsRootImpl root = new VcsRootBuilder().withHgPath(myVcsRootHgPath).build(); - return new Settings(hgPathProvider, root); + private HgVcsRoot createHgRoot() throws Exception { + return new HgVcsRoot(new VcsRootBuilder().withHgPath(myVcsRootHgPath).build()); } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SettingsTest.java Tue May 15 10:21:05 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * 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.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.Test; - -/** - * @author Pavel.Sher - */ -@Test -public class SettingsTest extends TestCase { - - 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.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - /** 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.getRepositoryUrlWithCredentials()); - } - - /** 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.getRepositoryUrlWithCredentials()); - } - - public void test_windows_path() throws Exception { - VcsRootImpl vcsRoot = createVcsRoot("c:\\windows\\path"); - Settings settings = createSettings(vcsRoot); - assertEquals("c:\\windows\\path", settings.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - 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.getRepositoryUrlWithCredentials()); - } - - //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.getRepositoryUrlWithCredentials()); - } - - 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 Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Tue May 15 10:33:21 2012 +0400 @@ -36,7 +36,7 @@ } - public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull RepoFactory commandFactory) throws IOException { + public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull RepoFactory repoFactory) throws IOException { VcsManager vcsManager = context.mock(VcsManager.class); final SBuildServer server = context.mock(SBuildServer.class); final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); @@ -44,6 +44,11 @@ allowing(server).getExecutor(); will(returnValue(executor)); }}); EventDispatcher<BuildServerListener> dispatcher = EventDispatcher.create(BuildServerListener.class); - return new MercurialVcsSupport(vcsManager, server, dispatcher, new ResetCacheRegister(), config, new ServerHgPathProvider(config), commandFactory, new MirrorManagerImpl(config)); + HgVcsRootFactory hgVcsRootFactory = new HgVcsRootFactory(config); + MirrorManagerImpl mirrorManager = new MirrorManagerImpl(config); + ServerHgPathProvider hgPathProvider = new ServerHgPathProvider(config); + HgTestConnectionSupport testConnection = new HgTestConnectionSupport(hgVcsRootFactory, repoFactory, mirrorManager, hgPathProvider); + return new MercurialVcsSupport(vcsManager, server, dispatcher, new ResetCacheRegister(), config, hgPathProvider, + repoFactory, mirrorManager, hgVcsRootFactory, testConnection); } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Tue May 15 10:33:21 2012 +0400 @@ -72,21 +72,22 @@ VcsRoot vcsRoot = new VcsRootImpl(1, vcsRootProps); ServerPluginConfig config = new ServerPluginConfigBuilder().cachesDir(tf.createTempDir()).build(); MirrorManager mirrorManager = new MirrorManagerImpl(config); - Settings settings = new Settings(new ServerHgPathProvider(config), vcsRoot); - final File workingDir = mirrorManager.getMirrorDir(settings.getRepository()); - settings.setCustomWorkingDir(workingDir); + ServerHgPathProvider hgPathProvider = new ServerHgPathProvider(config); + HgVcsRoot root = new HgVcsRoot(vcsRoot); + final File workingDir = mirrorManager.getMirrorDir(root.getRepository()); + root.setCustomWorkingDir(workingDir); try { if (myCloneRequired) { - new HgRepo(workingDir, settings.getHgCommandPath(), settings.getAuthSettings()).doClone().fromRepository(settings.getRepository()).call(); + new HgRepo(workingDir, hgPathProvider.getHgPath(root), root.getAuthSettings()).doClone().fromRepository(root.getRepository()).call(); } - return executor.execute(settings, workingDir); + return executor.execute(root, hgPathProvider, workingDir); } finally { tf.cleanup(); } } public interface CommandExecutor<T> { - T execute(@NotNull Settings settings, File workingDir) throws VcsException; + T execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException; } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -1,5 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownFileException; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; @@ -38,8 +39,8 @@ cleanCatResultDirs(); setRepository("mercurial-tests/testData/rep1", true); runCommand(new CommandExecutor<File>() { - public File execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - return new CatCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).files("/non/existing/path").checkForFailure(false).call(); + public File execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + return new CatCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()).files("/non/existing/path").checkForFailure(false).call(); } }); } @@ -65,8 +66,8 @@ private File runCat(@NotNull final List<String> paths) throws IOException, VcsException { return runCommand(new CommandExecutor<File>() { - public File execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - CatCommand cat = new CatCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()); + public File execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + CatCommand cat = new CatCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()); return cat.execute(paths); } });
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -43,10 +43,11 @@ File workingDir = myTempFiles.createTempDir(); ServerPluginConfig config = new ServerPluginConfigBuilder().cachesDir(myTempFiles.createTempDir()).build(); - Settings settings = new Settings(new ServerHgPathProvider(config), root); - settings.setCustomWorkingDir(workingDir); + ServerHgPathProvider hgPathProvider = new ServerHgPathProvider(config); + HgVcsRoot hgRoot = new HgVcsRoot(root); + hgRoot.setCustomWorkingDir(workingDir); - new CloneCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).fromRepository(settings.getRepository()).call(); + new CloneCommand(hgPathProvider.getHgPath(hgRoot), workingDir, hgRoot.getAuthSettings()).fromRepository(hgRoot.getRepository()).call(); String[] files = new String[] {".hg", "dir1", "dir with space", "file.txt"}; for (String f : files) {
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -1,5 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.testng.annotations.Test; @@ -36,8 +37,8 @@ private Void runIdentify(final ChangeSet cset) throws IOException, VcsException { return runCommand(new CommandExecutor<Void>() { - public Void execute(@NotNull final Settings settings, File workingDir) throws VcsException { - new IdentifyCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) + public Void execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + new IdentifyCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()) .revision(cset) .inLocalRepository() .call();
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -16,6 +16,7 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import jetbrains.buildServer.TempFiles; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; @@ -110,22 +111,22 @@ List<ChangeSet> csets = runLog(fromId, toId); assertEquals(3, csets.size()); - List<ModifiedFile> files = csets.get(0).getModifiedFiles(); + List<FileStatus> files = csets.get(0).getModifiedFiles(); assertEquals(1, files.size()); - ModifiedFile file = files.get(0); - assertEquals(ModifiedFile.Status.ADDED, file.getStatus()); + FileStatus file = files.get(0); + assertEquals(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(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(Status.MODIFIED, file.getStatus()); assertEquals("dir1/file3.txt", file.getPath()); } @@ -173,9 +174,9 @@ 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 { - return new LogCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) - .inBranch(settings.getBranchName()) + public List<ChangeSet> execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + return new LogCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()) + .inBranch(root.getBranchName()) .withTemplate(myTemplateFile) .fromRevision(fromId) .toRevision(toId)
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -15,6 +15,7 @@ */ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.testng.annotations.Test; @@ -35,8 +36,8 @@ try { runCommand(new CommandExecutor<Boolean>() { - public Boolean execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { - new PushCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).toRepository(settings.getRepository()).call(); + public Boolean execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + new PushCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()).toRepository(root.getRepository()).call(); return null; } });
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -15,6 +15,7 @@ */ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.testng.annotations.Test; @@ -27,35 +28,35 @@ public class StatusCommandTest extends BaseCommandTestCase { public void testAddedFile() throws IOException, VcsException { setRepository("mercurial-tests/testData/rep1", true); - List<ModifiedFile> files = runStatus("9875b412a788", "1d446e82d356"); + List<FileStatus> files = runStatus("9875b412a788", "1d446e82d356"); assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.ADDED, md.getStatus()); + FileStatus md = files.get(0); + assertEquals(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"); + List<FileStatus> files = runStatus("7209b1f1d793", "9522278aa38d"); assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.REMOVED, md.getStatus()); + FileStatus md = files.get(0); + assertEquals(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"); + List<FileStatus> files = runStatus("9522278aa38d", "b06a290a363b"); assertEquals(1, files.size()); - ModifiedFile md = files.get(0); - assertEquals(ModifiedFile.Status.MODIFIED, md.getStatus()); + FileStatus md = files.get(0); + assertEquals(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 { - return new StatusCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) + private List<FileStatus> runStatus(final String fromId, final String toId) throws IOException, VcsException { + return runCommand(new CommandExecutor<List<FileStatus>>() { + public List<FileStatus> execute(@NotNull HgVcsRoot root, @NotNull HgPathProvider hgPathProvider, @NotNull File workingDir) throws VcsException { + return new StatusCommand(hgPathProvider.getHgPath(root), workingDir, root.getAuthSettings()) .fromRevision(fromId) .toRevision(toId) .call();
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommandTest.java Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommandTest.java Tue May 15 10:33:21 2012 +0400 @@ -16,8 +16,9 @@ public void test() throws Exception { VcsRootImpl root = new VcsRootBuilder().withUrl("some/repository").build(); ServerPluginConfig config = new ServerPluginConfigBuilder().build(); - Settings settings = new Settings(new ServerHgPathProvider(config), root); - VersionCommand versionCommand = new VersionCommand(settings, new File("..")); + final ServerHgPathProvider hgPathProvider = new ServerHgPathProvider(config); + HgVcsRoot hgRoot = new HgVcsRoot(root); + VersionCommand versionCommand = new VersionCommand(hgPathProvider.getHgPath(hgRoot), new File("..")); HgVersion version = versionCommand.call(); assertNotNull(version); }
--- a/mercurial-tests/src/testng.xml Tue May 15 10:21:05 2012 +0400 +++ b/mercurial-tests/src/testng.xml Tue May 15 10:33:21 2012 +0400 @@ -13,7 +13,7 @@ <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.HgVcsRootTest"/> <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"/> @@ -22,6 +22,8 @@ <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.UnrelatedResitoriesTest"/> <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.CleanupTest"/> <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialResetCacheHandlerTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.AgentMirrorCleanerTest"/> + <class name="jetbrains.buildServer.buildTriggers.vcs.mercurial.ListFilesSupportTest"/> </classes> </test> </suite>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/after/dir1/file1.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +aaa \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/after/dir1/file3.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +ccc \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/after/dir1/subdir/file2.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +bbb \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/before/dir with space/file with space.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +some text \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/before/dir1/file1.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +aaa \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/before/dir1/file3.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,2 @@ +ccc +ddd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch5/before/dir1/subdir/file2.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,2 @@ +modified +bbb \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/after/dir with space/file with space.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +some text \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/after/file_in_branch.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +file from the test_branch \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/after/path/dir1/file1.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +aaa \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/after/path/dir1/file3.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +ccc \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/after/path/dir1/subdir/file2.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +bbb \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/before/dir with space/file with space.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +some text \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/patch6/before/file_in_branch.txt Tue May 15 10:33:21 2012 +0400 @@ -0,0 +1,1 @@ +file from the test_branch \ No newline at end of file
--- a/mercurial.ipr Tue May 15 10:21:05 2012 +0400 +++ b/mercurial.ipr Tue May 15 10:33:21 2012 +0400 @@ -310,7 +310,7 @@ <SplitterProportionsDataImpl /> </option> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK" /> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK" /> <component name="ResourceManagerContainer"> <option name="myResourceBundles"> <value> @@ -444,6 +444,7 @@ <library name="TeamCityAPI-agent"> <CLASSES> <root url="jar://$TeamCityDistribution$/devPackage/agent-api.jar!/" /> + <root url="jar://$TeamCityDistribution$/buildAgent/lib/agent.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES>
--- a/mercurial.xml Tue May 15 10:21:05 2012 +0400 +++ b/mercurial.xml Tue May 15 10:33:21 2012 +0400 @@ -128,6 +128,7 @@ </path> <path id="library.teamcityapi-agent.classpath"> + <pathelement location="${path.variable.teamcitydistribution}/buildAgent/lib/agent.jar"/> <pathelement location="${path.variable.teamcitydistribution}/devPackage/agent-api.jar"/> </path>