Mercurial > hg > mercurial
changeset 401:998c38590166
Merge branch Faradi-7.0.x
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Fri, 02 Mar 2012 14:33:42 +0400 |
parents | 3491c67a0b35 (current diff) 68cc614b191b (diff) |
children | d310db2849d0 |
files | mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangedFilesCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseCommand.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ParseHgVersionException.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnknownFileException.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnknownRevisionException.java mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnrelatedRepositoryException.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesCommand.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesNoRevsets.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesWithRevsets.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactory.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactoryImpl.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseNoRevsets.java mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseWithRevsets.java |
diffstat | 114 files changed, 1517 insertions(+), 1166 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgDetector.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgDetector.java Fri Mar 02 14:33:42 2012 +0400 @@ -68,7 +68,7 @@ private boolean canRunHg(@NotNull final String hgPath, @NotNull final File workDir, boolean logWarnings) { VersionCommand versionCommand = new VersionCommand(hgPath, workDir); try { - HgVersion version = versionCommand.execute(); + HgVersion version = versionCommand.call(); if (isCompatible(version)) { return true; } else {
--- a/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,11 +1,10 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import com.intellij.openapi.util.Pair; import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildProgressLogger; import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; import jetbrains.buildServer.vcs.IncludeRule; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.VcsRoot; @@ -13,14 +12,9 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import static com.intellij.openapi.util.io.FileUtil.delete; -import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil.removePrivateData; -import static jetbrains.buildServer.util.FileUtil.isEmptyDir; /** * @author dmitry.neverov @@ -29,9 +23,9 @@ private final AgentPluginConfig myConfig; private final MirrorManager myMirrorManager; - private final HgPathProvider myHgPathProvider; - private final VcsRoot myRoot; private final Settings mySettings; + private final AuthSettings myAuthSettings; + private final String myHgPath; private final String myToVersion; private final BuildProgressLogger myLogger; private final boolean myUseLocalMirrors; @@ -45,9 +39,9 @@ @NotNull final AgentRunningBuild build) { myConfig = pluginConfig; myMirrorManager = mirrorManager; - myHgPathProvider = hgPathProvider; - myRoot = root; - mySettings = new Settings(myHgPathProvider, myRoot); + mySettings = new Settings(hgPathProvider, root); + myAuthSettings = mySettings.getAuthSettings(); + myHgPath = mySettings.getHgCommandPath(); myToVersion = toVersion; myLogger = build.getBuildLogger(); myUseLocalMirrors = myConfig.isUseLocalMirrors(build); @@ -59,9 +53,9 @@ try { checkRuleIsValid(rule); if (myUseLocalMirrors) - updateLocalMirror(); + updateLocalMirror(mySettings.getRepository(), myToVersion); updateRepository(workingDir); - updateWorkingDir(workingDir); + updateWorkingDir(workingDir, myToVersion, mySettings.getRepository()); } catch (Exception e) { throwVcsException(e); } @@ -72,234 +66,122 @@ } - private void throwVcsException(Exception e) throws VcsException { - if (e instanceof VcsException) - throw (VcsException) e; - else - throw new VcsException(e); - } - - - private void initRepository(Settings settings, File workingDir, boolean useLocalMirrors) throws VcsException { - try { - String defaultPullUrl = getDefaultPullUrl(settings, useLocalMirrors); - myLogger.message("Init repository at " + workingDir.getAbsolutePath() + ", remote repository is " + - removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new Init(settings, workingDir, defaultPullUrl).execute(); - } catch (IOException e) { - throw new VcsException("Error while initializing repository at " + workingDir.getAbsolutePath(), e); - } - } - - - private void updateRepository(File workingDir) throws VcsException, IOException { - String defaultPullUrl = getDefaultPullUrl(mySettings, myUseLocalMirrors); - if (isEmptyDir(workingDir)) { - workingDir.mkdirs(); - myLogger.message("Start cloning from " + removePrivateData(defaultPullUrl, Collections.singleton(mySettings.getPassword()))); - CloneCommand clone = new CloneCommand(mySettings, workingDir); - clone.setRepository(defaultPullUrl); - clone.setUsePullProtocol(false); - clone.setUpdateWorkingDir(false); - clone.execute(); - myLogger.message("Repository successfully cloned"); + private void updateLocalMirror(@NotNull String repositoryUrl, @NotNull String revision) throws VcsException, IOException { + File mirrorDir = myMirrorManager.getMirrorDir(repositoryUrl); + HgRepo mirrorRepo = new HgRepo(mirrorDir, myHgPath, myAuthSettings); + if (!mirrorRepo.isValidRepository()) { + delete(mirrorDir); + myLogger.message("Clone repository " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl) + " into local mirror " + mirrorRepo.path()); + mirrorRepo.doClone().fromRepository(repositoryUrl) + .setUpdateWorkingDir(false) + .setUsePullProtocol(false) + .useUncompressedTransfer(mySettings.isUncompressedTransfer()) + .call(); + myLogger.message("Clone successfully finished"); } else { - if (!Settings.isValidRepository(workingDir)) { - initRepository(mySettings, workingDir, myUseLocalMirrors); + myLogger.message("Update local mirror of " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl) + " at " + mirrorDir); + if (mirrorRepo.containsRevision(revision)) { + myLogger.message("Local mirror is already up-to-date"); } else { - ensureUseRightRepository(workingDir); + myLogger.message("Start pulling changes from " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); + mirrorRepo.pull().fromRepository(repositoryUrl) + .withTimeout(myPullTimeout) + .call(); + myLogger.message("Local mirror changes successfully pulled"); } - myLogger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(mySettings.getPassword()))); - new PullCommand(mySettings, workingDir, defaultPullUrl).execute(myPullTimeout); - myLogger.message("Changes successfully pulled"); } } - private void ensureUseRightRepository(File workingDir) throws VcsException { - boolean clonedFromWrongRepository = myUseLocalMirrors && !isClonedFromLocalMirror(workingDir) - || !myUseLocalMirrors && isClonedFromLocalMirror(workingDir); - - if (clonedFromWrongRepository) { - String rightRepository = myUseLocalMirrors ? "local mirror" : "remote repository"; - String wrongRepository = myUseLocalMirrors ? "remote repository" : "local mirror"; - myLogger.message("Repository in working directory is cloned from " + wrongRepository + ", clone it from " + rightRepository); - FileUtil.delete(workingDir); - initRepository(mySettings, workingDir, myUseLocalMirrors); - } - } - - - private void updateLocalMirror() throws VcsException, IOException { - Settings settings = new Settings(myHgPathProvider, myRoot); - File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepository()); - myLogger.message("Update local mirror at " + mirrorDir); - if (!Settings.isValidRepository(mirrorDir)) { - initRepository(settings, mirrorDir, false); - } - final String defaultPullUrl = getDefaultPullUrl(settings, false); - myLogger.message("Start pulling changes from " + removePrivateData(defaultPullUrl, Collections.singleton(settings.getPassword()))); - new PullCommand(settings, mirrorDir).execute(myPullTimeout); - myLogger.message("Local mirror changes successfully pulled"); - } - - - private void updateWorkingDir(@NotNull final File workingDir) throws VcsException, IOException { - String workingDirRevision = getWorkingDirRevision(mySettings, workingDir); - if (isInitialClone(workingDirRevision)) { - doUpdateWorkingDir(workingDir); + private void updateRepository(@NotNull File workingDir) throws VcsException, IOException { + String repositoryUrl = getDefaultPullUrl(mySettings, myUseLocalMirrors); + HgRepo repo = new HgRepo(workingDir, myHgPath, myAuthSettings); + myLogger.message("Update repository " + workingDir.getAbsolutePath()); + if (repo.isEmpty()) {//can do clone only in empty dir + myLogger.message("Start cloning from " + (myUseLocalMirrors ? "local mirror " : "") + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); + repo.doClone().fromRepository(repositoryUrl) + .setUsePullProtocol(false) + .setUpdateWorkingDir(false) + .useUncompressedTransfer(!myUseLocalMirrors && mySettings.isUncompressedTransfer()) + .call(); + repo.setDefaultPath(mySettings.getRepository()); + myLogger.message("Repository successfully cloned"); } else { - Map<String, Pair<String, String>> currentSubrepos = getSubrepositories(workingDir, workingDirRevision); - if (currentSubrepos.isEmpty()) { - doUpdateWorkingDir(workingDir); + if (!repo.isValidRepository()) + repo.init().call(); + repo.setDefaultPath(mySettings.getRepository()); + if (repo.containsRevision(myToVersion)) { + myLogger.message("Repository already contains revision " + myToVersion); } else { - Map<String, Pair<String, String>> toVersionSubrepos = getSubrepositories(workingDir, myToVersion); - Map<String, Pair<String, String>> subrepositoriesWithChangedUrls = getSubrepositoriesWithChangedUrls(currentSubrepos, toVersionSubrepos); - if (subrepositoriesWithChangedUrls.isEmpty()) { - doUpdateWorkingDir(workingDir); - } else { - logSubrepositoriesUrlsChanged(workingDirRevision, myToVersion, subrepositoriesWithChangedUrls); - FileUtil.delete(workingDir); - updateRepository(workingDir); - doUpdateWorkingDir(workingDir); - } + myLogger.message("Start pulling changes from " + (myUseLocalMirrors ? "local mirror " : "") + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); + repo.pull().fromRepository(repositoryUrl) + .withTimeout(myPullTimeout) + .call(); + myLogger.message("Changes successfully pulled"); } } } - private void logSubrepositoriesUrlsChanged(@NotNull final String fromVersion, - @NotNull final String toVersion, - @NotNull final Map<String, Pair<String, String>> subrepositoriesWithChangedUrls) { - StringBuilder sb = new StringBuilder(); - sb.append("Subrepositories' URLs were changed between revisions ").append(fromVersion).append("..").append(toVersion).append(":\n"); - for (Map.Entry<String, Pair<String, String>> entry : subrepositoriesWithChangedUrls.entrySet()) { - String path = entry.getKey(); - String oldUrl = entry.getValue().first; - String newUrl = entry.getValue().second; - sb.append("path: \"").append(path).append("\", old URL: \"").append(oldUrl).append("\", new URL: \"").append(newUrl).append("\";\n"); - } - sb.append("do clean checkout."); - myLogger.warning(sb.toString()); + private void updateWorkingDir(@NotNull File workingDir, @NotNull String toVersion, @NotNull String repositoryUrl) throws VcsException, IOException { + HgRepo repo = new HgRepo(workingDir, myHgPath, myAuthSettings); + updateSubrepositories(repo, toVersion, repositoryUrl); + doUpdateWorkingDir(repo, toVersion); } - - /*returns map: relative path -> (repository url, repository revision)*/ - private Map<String, Pair<String, String>> getSubrepositories(@NotNull final File workingDir, @NotNull final String revision) throws VcsException, IOException { - CatCommand cc = new CatCommand(mySettings, workingDir); - cc.setRevId(revision); - File catDir = null; - try { - catDir = cc.execute(Arrays.asList(".hgsub", ".hgsubstate"), false); - File hgsub = new File(catDir, ".hgsub"); - File hgsubstate = new File(catDir, ".hgsubstate"); - return readSubrepositories(hgsub, hgsubstate); - } catch (VcsException e) { - return Collections.emptyMap(); - } finally { - if (catDir != null) - delete(catDir); - } - } - - - private Map<String, Pair<String, String>> readSubrepositories(@NotNull final File hgsub, @NotNull final File hgsubstate) throws IOException { - if (hgsub.exists() && hgsubstate.exists()) { - Map<String, String> path2repo = readHgsub(hgsub); - Map<String, String> path2revision = readHgsubstate(hgsubstate); - Map<String, Pair<String, String>> result = new HashMap<String, Pair<String, String>>(); - for (Map.Entry<String, String> entry : path2repo.entrySet()) { - String path = entry.getKey(); - String repo = entry.getValue(); - String revision = path2revision.get(path); - if (revision != null) { - result.put(path, Pair.create(repo, revision)); + private void updateSubrepositories(@NotNull HgRepo repo, @NotNull String toVersion, @NotNull String parentRepositoryUrl) throws VcsException, IOException { + if (!repo.hasSubreposAtRevision(toVersion)) + return; + myLogger.message("Process subrepos of " + parentRepositoryUrl); + String workingDirRevision = repo.getWorkingDirRevision(); + Map<String, SubRepo> workingDirSubrepos = repo.getSubrepositories(workingDirRevision); + Map<String, SubRepo> subrepos = repo.getSubrepositories(toVersion); + for (Map.Entry<String, SubRepo> entry : subrepos.entrySet()) { + String path = entry.getKey(); + myLogger.message("Process subrepo " + path); + SubRepo subrepo = entry.getValue(); + SubRepo workingDirSubrepo = workingDirSubrepos.get(path); + if (workingDirSubrepo != null && subrepo.hasDifferentUrlThan(workingDirSubrepo)) { + myLogger.message("The url of subrepo was changed between revisions " + workingDirRevision + " and " + toVersion + " , delete the subrepo"); + delete(subrepo.dir()); + } + HgRepo subrepository = new HgRepo(subrepo.dir(), myHgPath, myAuthSettings); + if (myUseLocalMirrors && subrepo.vcsType() == SubRepo.VcsType.hg) { + if (subrepo.isRelative()) { + myLogger.message("Subrepo url " + subrepo.url() + " is relative, subrepo will be updated during parent repository update"); } else { - myLogger.warning("Cannot find revision for subrepository at path " + path + " skip it"); + if (!subrepository.isValidRepository() || !subrepository.containsRevision(subrepo.revision())) { + updateLocalMirror(subrepo.url(), subrepo.revision()); + File mirrorDir = myMirrorManager.getMirrorDir(subrepo.url()); + if (subrepository.isValidRepository()) { + myLogger.message("Pull from local mirror"); + subrepository.pull().fromRepository(mirrorDir) + .withTimeout(myPullTimeout) + .call(); + myLogger.message("done"); + } else { + myLogger.message("Clone subrepo from local mirror"); + subrepository.doClone().fromRepository(mirrorDir) + .setUpdateWorkingDir(false) + .setUsePullProtocol(false) + .call(); + subrepository.setDefaultPath(subrepo.url()); + myLogger.message("done"); + } + } } + } else { + myLogger.message("Local mirrors aren't used, subrepo will be updated during the parent repo update"); } - return result; - } else { - return Collections.emptyMap(); + updateSubrepositories(subrepository, subrepo.revision(), subrepo.url()); } } - /*returns map: relative path -> repository url */ - private Map<String, String> readHgsub(@NotNull final File hgsub) throws IOException { - Map<String, String> result = new HashMap<String, String>(); - for (String line : FileUtil.readFile(hgsub)) { - String[] parts = line.split(" = "); - if (parts.length == 2) { - result.put(parts[0], parts[1]); - } else { - myLogger.warning("Cannot parse the line '" + line + "' from .hgsub, skip it"); - } - } - return result; - } - - - /*returns map: relative path -> revision */ - private Map<String, String> readHgsubstate(@NotNull final File hgsubstate) throws IOException { - Map<String, String> result = new HashMap<String, String>(); - for (String line : FileUtil.readFile(hgsubstate)) { - String[] parts = line.split(" "); - if (parts.length == 2) { - result.put(parts[1], parts[0]); - } else { - myLogger.warning("Cannot parse the line '" + line + "' from .hgsubstate, skip it"); - } - } - return result; - } - - - /*returns map repository path -> (old url, new url)*/ - private Map<String, Pair<String, String>> getSubrepositoriesWithChangedUrls(@NotNull final Map<String, Pair<String, String>> subrepos1, @NotNull final Map<String, Pair<String, String>> subrepos2) { - Map<String, Pair<String, String>> result = new HashMap<String, Pair<String, String>>(); - for (Map.Entry<String, Pair<String, String>> entry : subrepos1.entrySet()) { - String path = entry.getKey(); - String url1 = entry.getValue().first; - Pair<String, String> urlRevision = subrepos2.get(path); - if (urlRevision != null && !url1.equals(urlRevision.first)) - result.put(path, Pair.create(url1, urlRevision.first)); - } - return result; - } - - - private boolean isInitialClone(@NotNull final String workingDirRevision) { - return "000000000000".equals(workingDirRevision); - } - - - private String getWorkingDirRevision(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - IdentifyCommand id = new IdentifyCommand(settings, workingDir); - id.setInLocalRepository(true); - return id.execute(); - } - - - private void doUpdateWorkingDir(@NotNull final File workingDir) throws VcsException { - myLogger.message("Updating folder " + workingDir.getAbsolutePath() + " to revision " + myToVersion); - UpdateCommand update = new UpdateCommand(mySettings, workingDir); - addUpdateAuthConfigParams(update); - update.setToId(new ChangeSet(myToVersion).getId()); - update.execute(); - myLogger.message("Folder successfully updated"); - } - - - private void addUpdateAuthConfigParams(@NotNull UpdateCommand update) { - String username = mySettings.getUsername(); - String password = mySettings.getPassword(); - if (username == null || password == null) - return; - update.withConfig("auth.tc.prefix", "*") - .withConfig("auth.tc.username", username) - .withConfig("auth.tc.password", password) - .withConfig("auth.tc.schemes", "http https"); + private void doUpdateWorkingDir(@NotNull HgRepo repo, @NotNull String revision) throws VcsException { + myLogger.message("Updating working dir " + repo.path() + " to revision " + revision); + repo.update().toRevision(revision).call(); + myLogger.message("Working dir updated"); } @@ -308,28 +190,23 @@ File mirrorDir = myMirrorManager.getMirrorDir(settings.getRepository()); return mirrorDir.getCanonicalPath(); } else { - return settings.getRepositoryUrlWithCredentials(); + return settings.getRepository(); } } private void checkRuleIsValid(IncludeRule includeRule) throws VcsException { if (includeRule.getTo() != null && includeRule.getTo().length() > 0) { - if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) { + if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); - } } } - public boolean isClonedFromLocalMirror(@NotNull final File workingDir) { - try { - File mirrorDir = myMirrorManager.getMirrorDir(mySettings.getRepository()); - File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc"); - String config = FileUtil.readText(hgrc); - return config.contains("default = " + mirrorDir.getCanonicalPath()); - } catch (Exception e) { - return false; - } + private void throwVcsException(Exception e) throws VcsException { + if (e instanceof VcsException) + throw (VcsException) e; + else + throw new VcsException(e); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,216 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.util.FileUtil; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static com.intellij.openapi.util.io.FileUtil.delete; +import static java.util.Collections.emptyMap; +import static jetbrains.buildServer.util.FileUtil.isEmptyDir; + +/** +* @author dmitry.neverov +*/ +public class HgRepo { + + protected final File myWorkingDir; + protected final String myHgPath; + protected final AuthSettings myAuthSettings; + private final Map<String, Map<String, SubRepo>> mySubreposCache = new HashMap<String, Map<String, SubRepo>>(); + + public HgRepo(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) { + myWorkingDir = workingDir; + myHgPath = hgPath; + myAuthSettings = authSettings; + } + + public PullCommand pull() { + return new PullCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public PushCommand push() { + return new PushCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public CloneCommand doClone() { + return new CloneCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public IdentifyCommand id() { + return new IdentifyCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public Init init() { + return new Init(myHgPath, myWorkingDir, myAuthSettings); + } + + public LogCommand log() { + return new LogCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public UpdateCommand update() { + return new UpdateCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public BranchesCommand branches() { + return new BranchesCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public StatusCommand status() { + return new StatusCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public TagCommand tag() { + return new TagCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public CatCommand cat() { + return new CatCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public ArchiveCommand archive() { + return new ArchiveCommand(myHgPath, myWorkingDir, myAuthSettings); + } + + public String path() { + return myWorkingDir.getAbsolutePath(); + } + + public File getWorkingDir() { + return myWorkingDir; + } + + public boolean isEmpty() { + return isEmptyDir(myWorkingDir); + } + + public String getWorkingDirRevision() throws VcsException { + return id().inLocalRepository().call(); + } + + public boolean containsRevision(@NotNull String revision) { + return containsRevision(new ChangeSet(revision)); + } + + public boolean containsRevision(@NotNull ChangeSet cset) { + try { + id().revision(cset).inLocalRepository().call(); + return true; + } catch (VcsException e) { + return false; + } + } + + public boolean isValidRepository() { + // need better way to check that repository copy is ok + return myWorkingDir.isDirectory() && new File(myWorkingDir, ".hg").isDirectory(); + } + + public void setDefaultPath(@NotNull String defaultPath) { + File hgrc = new File(new File(myWorkingDir, ".hg"), "hgrc"); + String content = "[paths]\ndefault = " + defaultPath; + FileUtil.writeFile(hgrc, content); + } + + public boolean hasSubreposAtRevision(@NotNull String revision) { + return !getSubrepositories(new ChangeSet(revision)).isEmpty(); + } + + public boolean hasSubreposAtRevision(@NotNull ChangeSet cset) { + return !getSubrepositories(cset).isEmpty(); + } + + public Map<String, SubRepo> getSubrepositories(@NotNull String revision) { + return getSubrepositories(new ChangeSet(revision)); + } + + public Map<String, SubRepo> getSubrepositories(@NotNull ChangeSet cset) { + String revId = cset.getId(); + Map<String, SubRepo> subrepos = mySubreposCache.get(revId); + if (subrepos != null) + return subrepos; + CatCommand cc = cat(); + cc.setRevId(revId); + File catDir = null; + try { + catDir = cc.execute(Arrays.asList(".hgsub", ".hgsubstate"), false); + File hgsub = new File(catDir, ".hgsub"); + File hgsubstate = new File(catDir, ".hgsubstate"); + subrepos = readSubrepositories(hgsub, hgsubstate); + mySubreposCache.put(revId, subrepos); + return subrepos; + } catch (VcsException e) { + return emptyMap(); + } finally { + if (catDir != null) + delete(catDir); + } + } + + @Override + public String toString() { + return myWorkingDir.getAbsolutePath(); + } + + private Map<String, SubRepo> readSubrepositories(@NotNull final File hgsub, @NotNull final File hgsubstate) { + if (hgsub.exists() && hgsubstate.exists()) { + try { + Map<String, String> path2repo = readHgsub(hgsub); + Map<String, String> path2revision = readHgsubstate(hgsubstate); + Map<String, SubRepo> result = new HashMap<String, SubRepo>(); + for (Map.Entry<String, String> entry : path2repo.entrySet()) { + String path = entry.getKey(); + String url = entry.getValue(); + String revision = path2revision.get(path); + if (revision != null) { + result.put(path, new SubRepo(this, path, url, revision)); + } else { +// myLogger.warning("Cannot find revision for subrepository at path " + path + " skip it"); + } + } + return result; + } catch (IOException e) { +// myLogger.warning("Error while trying to read subrepositories " + e.getMessage()); + return emptyMap(); + } + } else { + return emptyMap(); + } + } + + /*returns map: relative path -> repository url */ + private Map<String, String> readHgsub(@NotNull final File hgsub) throws IOException { + Map<String, String> result = new HashMap<String, String>(); + for (String line : FileUtil.readFile(hgsub)) { + String[] parts = line.split(" = "); + if (parts.length == 2) { + result.put(parts[0], parts[1]); + } else { +// myLogger.warning("Cannot parse the line '" + line + "' from .hgsub, skip it"); + } + } + return result; + } + + + /*returns map: relative path -> revision */ + private Map<String, String> readHgsubstate(@NotNull final File hgsubstate) throws IOException { + Map<String, String> result = new HashMap<String, String>(); + for (String line : FileUtil.readFile(hgsubstate)) { + String[] parts = line.split(" "); + if (parts.length == 2) { + result.put(parts[1], parts[0]); + } else { +// myLogger.warning("Cannot parse the line '" + line + "' from .hgsubstate, skip it"); + } + } + return result; + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersion.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersion.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,6 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ParseHgVersionException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ParseHgVersionException; import org.jetbrains.annotations.NotNull; /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/SubRepo.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,74 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** +* @author dmitry.neverov +*/ +public class SubRepo { + private final HgRepo myParentRepo; + private final String myPath; + private final String myUrl; + private final String myRevision; + private final VcsType myVcsType; + + public SubRepo(@NotNull HgRepo parentRepo, @NotNull String path, @NotNull String url, @NotNull String revision) { + myParentRepo = parentRepo; + myPath = path; + myUrl = url; + myRevision = revision; + myVcsType = parseVcsType(); + } + + @NotNull + public String path() { + return myPath; + } + + @NotNull + public String url() { + return myUrl; + } + + @NotNull + public String revision() { + return myRevision; + } + + @NotNull + public VcsType vcsType() { + return myVcsType; + } + + public boolean isRelative() { + return myUrl.startsWith(".."); + } + + @NotNull + File dir() { + return new File(myParentRepo.getWorkingDir(), myPath); + } + + public boolean hasDifferentUrlThan(@NotNull SubRepo other) { + return !myUrl.equals(other.url()); + } + + @Override + public String toString() { + return myPath + " = " + myUrl + "#" + myRevision; + } + + private VcsType parseVcsType() { + if (myUrl.startsWith("[svn]")) + return VcsType.svn; + if (myUrl.startsWith("[git]")) + return VcsType.git; + return VcsType.hg; + } + + public static enum VcsType { + hg, git, svn + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ArchiveCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -26,19 +26,21 @@ private File myDestDir; private String myToId; - public ArchiveCommand(@NotNull final Settings settings, @NotNull final File workingDir) { - super(settings, workingDir); + public ArchiveCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } - public void setDestDir(@NotNull File destDir) { + public ArchiveCommand toDir(@NotNull File destDir) { myDestDir = destDir; + return this; } - public void setToId(final String toId) { - myToId = toId; + public ArchiveCommand revision(@NotNull ChangeSet cset) { + myToId = cset.getId(); + return this; } - public void execute() throws VcsException { + public void call() throws VcsException { if (myDestDir == null) throw new IllegalStateException("Destination dir must be specified"); GeneralCommandLine cli = createCommandLine();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/AuthSettings.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,127 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.log.Loggers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.net.*; +import java.util.HashSet; +import java.util.Set; + +import static com.intellij.openapi.util.text.StringUtil.isEmpty; +import static java.util.Arrays.asList; + +/** + * @author dmitry.neverov + */ +public class AuthSettings { + + private final static Set<String> AUTH_PROTOS = new HashSet<String>(asList("http", "https", "ssh")); + private final String myUsername; + private final String myPassword; + + public AuthSettings() { + this(null, null); + } + + public AuthSettings(@Nullable String username, @Nullable String password) { + myUsername = username; + myPassword = password; + } + + public String getUsername() { + return myUsername; + } + + public String getPassword() { + return myPassword; + } + + public String getRepositoryUrlWithCredentials(@NotNull String repositoryUrl) { + if (isRequireCredentials(repositoryUrl)) { + if (containsCredentials(repositoryUrl)) + return repositoryUrl; + try { + return createURLWithCredentials(repositoryUrl); + } catch (MalformedURLException e) { + Loggers.VCS.warn("Error while parsing url " + repositoryUrl, e); + } + return repositoryUrl; + } else { + return repositoryUrl; + } + } + + public String getRepositoryUrlWithHiddenPassword(@NotNull String repositoryUrl) { + if (isEmpty(myPassword)) + return repositoryUrl; + return repositoryUrl.replace(myPassword, "******"); + } + + private boolean isRequireCredentials(@NotNull String repositoryUrl) { + for (String scheme : AUTH_PROTOS) { + if (repositoryUrl.startsWith(scheme + ":")) + return true; + } + return false; + } + + private boolean containsCredentials(final String repositoryUrl) { + try { + URL url = new URL(null, repositoryUrl, new FakeStreamHandler()); + String userInfo = url.getUserInfo(); + return userInfo != null && userInfo.contains(":"); + } catch (MalformedURLException e) { + return false; + } + } + + private String createURLWithCredentials(String originalUrl) throws MalformedURLException { + String userInfo = createUserInfo(); + if (!isEmpty(userInfo)) { + URL url = new URL(null, originalUrl, new FakeStreamHandler()); + return url.getProtocol() + "://" + + userInfo + "@" + + url.getHost() + + (url.getPort() != -1 ? ":" + url.getPort() : "") + + url.getFile() + + (url.getRef() != null ? url.getRef() : ""); + } else { + return originalUrl; + } + } + + private String createUserInfo() { + String userInfo = ""; + if (!isEmpty(myUsername)) { + userInfo += myUsername; + if (!isEmpty(myPassword)) { + userInfo += ":" + myPassword; + } + } + return getEscapedUserInfo(userInfo); + } + + private static String getEscapedUserInfo(String userInfo) { + try { + URI uri = new URI("http", userInfo, "somewhere.com", 80, "", "", ""); + String escapedURI = uri.toASCIIString(); + int from = "http://".length(); + int to = escapedURI.indexOf("somewhere.com") - 1; + String escapedUserInfo = escapedURI.substring(from, to); + escapedUserInfo = escapedUserInfo.replaceAll("&", "%26"); + return escapedUserInfo; + } catch (URISyntaxException e) { + assert false; + } + return userInfo; + } + + private class FakeStreamHandler extends URLStreamHandler { + @Override + protected URLConnection openConnection(URL u) throws IOException { + throw new UnsupportedOperationException(); + } + } +}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -57,4 +57,8 @@ protected Set<String> getPrivateData() { return emptySet(); } + + protected String getHgPath() { + return myHgPath; + } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BranchesCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -31,8 +31,8 @@ */ public class BranchesCommand extends VcsRootCommand { - public BranchesCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public BranchesCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } /** @@ -40,7 +40,7 @@ * @return see above * @throws jetbrains.buildServer.vcs.VcsException if error occurs */ - public Map<String, ChangeSet> execute() throws VcsException { + public Map<String, ChangeSet> call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("branches"); CommandResult res = runCommand(cli);
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -22,23 +22,52 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; import static com.intellij.openapi.util.io.FileUtil.delete; +import static java.util.Collections.singletonList; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandExecutionSettingsBuilder.with; public class CatCommand extends VcsRootCommand { private String myRevId; private final static int MAX_CMD_LEN = 900; + private List<String> myRelativePaths = new ArrayList<String>(); + private boolean myCheckForFailure = true; - public CatCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public CatCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); + } + + public CatCommand files(@NotNull String relativePath) { + myRelativePaths = singletonList(relativePath); + return this; + } + + public CatCommand files(@NotNull List<String> relativePaths) { + myRelativePaths = relativePaths; + return this; } - public void setRevId(final String revId) { + public CatCommand setRevId(final String revId) { myRevId = revId; + return this; + } + + public CatCommand atRevision(@NotNull ChangeSet cset) { + myRevId = cset.getId(); + return this; + } + + public CatCommand checkForFailure(boolean doCheckForFailure) { + myCheckForFailure = doCheckForFailure; + return this; + } + + public File call() throws VcsException { + return execute(myRelativePaths, myCheckForFailure); } public File execute(List<String> relPaths) throws VcsException {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ChangedFilesCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +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 com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * @author Pavel.Sher - */ -public class ChangedFilesCommand extends VcsRootCommand { - private String myRevId; - - public ChangedFilesCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); - } - - public void setRevId(@NotNull final String revId) { - myRevId = revId; - } - - public List<ModifiedFile> execute() throws VcsException { - File styleFile; - try { - styleFile = getStyleFile(); - } catch (IOException e) { - throw new VcsException("Unable to create style file: " + e.toString(), e); - } - try { - GeneralCommandLine cli = createCommandLine(); - cli.addParameter("log"); - cli.addParameter("-r"); - cli.addParameter(myRevId + ":" + myRevId); - cli.addParameter("--style=" + styleFile.getAbsolutePath()); - - CommandResult res = runCommand(cli); - return parseFiles(res.getStdout()); - } finally { - FileUtil.delete(styleFile); - } - } - - private File getStyleFile() throws IOException { - File styleFile = FileUtil.createTempFile("hg", "style"); - FileUtil.writeFile(styleFile, - "changeset = \"{file_mods}{file_adds}{file_dels}\"\n" + - "file_add = \"A {file_add}\\n\"\n" + - "file_del = \"R {file_del}\\n\"\n" + - "file_mod = \"M {file_mod}\\n\""); - return styleFile; - } - - private List<ModifiedFile> parseFiles(final String stdout) { - return StatusCommand.parseFiles(stdout); - } -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandExecutionSettingsBuilder.with; @@ -29,34 +30,48 @@ private String myRepository; private File myWorkingDir; private boolean myUsePullProtocol = true; + private boolean myUseUncompressedTransfer = false; - public CloneCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public CloneCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); myWorkingDir = workingDir; - myRepository = getSettings().getRepositoryUrlWithCredentials(); + } + + public CloneCommand fromRepository(@NotNull String repositoryUrl) { + myRepository = repositoryUrl; + return this; + } + + public CloneCommand fromRepository(@NotNull File localRepository) throws IOException { + return fromRepository(localRepository.getCanonicalPath()); + } + + public CloneCommand toRevision(@NotNull String revision) { + return toRevision(new ChangeSet(revision)); } - /** - * Sets repository to clone, by default uses repository from the specified settings - * @param repo repository path - */ - public void setRepository(@NotNull String repo) { - myRepository = repo; + public CloneCommand toRevision(@NotNull ChangeSet cset) { + myToId = cset.getId(); + return this; + } + + public CloneCommand setUpdateWorkingDir(boolean doUpdateWorkingDir) { + myUpdateWorkingDir = doUpdateWorkingDir; + return this; } - public void setToId(final String toId) { - myToId = toId; + public CloneCommand useUncompressedTransfer(boolean doUseUncompressedTransfer) { + myUseUncompressedTransfer = doUseUncompressedTransfer; + return this; } - public void setUpdateWorkingDir(final boolean updateWorkingDir) { - myUpdateWorkingDir = updateWorkingDir; + public CloneCommand setUsePullProtocol(boolean usePullProtocol) { + myUsePullProtocol = usePullProtocol; + return this; } - public void setUsePullProtocol(boolean usePullProtocol) { - myUsePullProtocol = usePullProtocol; - } - - public void execute() throws VcsException { + public void call() throws VcsException { + myWorkingDir.mkdirs(); GeneralCommandLine cli = createCommandLine(); File parent = myWorkingDir.getParentFile(); cli.setWorkDirectory(parent.getAbsolutePath()); @@ -70,10 +85,11 @@ if (!myUpdateWorkingDir) { cli.addParameter("-U"); } - if (getSettings().isUncompressedTransfer()) { + if (myUseUncompressedTransfer) { cli.addParameter("--uncompressed"); } - cli.addParameter(myRepository); + String repositoryUrl = myAuthSettings.getRepositoryUrlWithCredentials(myRepository); + cli.addParameter(repositoryUrl); cli.addParameter(myWorkingDir.getName()); runCommand(cli, with().timeout(24 * 3600)); // some repositories are quite large, we set timeout to 24 hours
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResult.java Fri Mar 02 14:33:42 2012 +0400 @@ -2,6 +2,10 @@ 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.util.StringUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -142,6 +146,7 @@ checkUnrelatedRepository(stderr); checkUnknownRevision(stderr); checkFileNotUnderTheRoot(stderr); + checkConnectionRefused(stderr); } private void checkUnrelatedRepository(@NotNull final String stderr) throws UnrelatedRepositoryException { @@ -173,6 +178,11 @@ } } + private void checkConnectionRefused(@NotNull final String stderr) throws ConnectionRefusedException { + if (stderr.equals("abort: error: Connection refused")) + throw new ConnectionRefusedException(); + } + private static Set<Integer> setOf(Integer... ints) { return new HashSet<Integer>(asList(ints)); }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -32,30 +32,50 @@ private boolean myInLocalRepository = false; private ChangeSet myChangeSet; private Integer myRevisionNumber; + private AuthSettings myAuthSettings; + private String myRepositoryUrl; - public IdentifyCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public IdentifyCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } - public void setInLocalRepository(boolean inLocalRepository) { - myInLocalRepository = inLocalRepository; + public IdentifyCommand revision(@NotNull String revision) { + myChangeSet = new ChangeSet(revision); + return this; + } + + public IdentifyCommand revision(@NotNull ChangeSet cset) { + myChangeSet = cset; + return this; } - public void setChangeSet(ChangeSet changeSet) { - myChangeSet = changeSet; + public IdentifyCommand inLocalRepository() { + myInLocalRepository = true; + return this; + } + + public IdentifyCommand revisionNumber(int revisionNumber) { + myRevisionNumber = revisionNumber; + return this; } - public void setRevisionNumber(int revisionNumber) { - myRevisionNumber = revisionNumber; + public IdentifyCommand withAuthSettings(@NotNull AuthSettings authSettings) { + myAuthSettings = authSettings; + return this; } - public String execute() throws VcsException { + public IdentifyCommand repository(@NotNull String repositoryUrl) { + myRepositoryUrl = repositoryUrl; + return this; + } + + public String call() throws VcsException { GeneralCommandLine cli = createCL(); cli.addParameter("identify"); if (myInLocalRepository) { cli.setWorkDirectory(this.getWorkDirectory().getAbsolutePath()); } else { - cli.addParameter(getSettings().getRepositoryUrlWithCredentials()); + cli.addParameter(myAuthSettings.getRepositoryUrlWithCredentials(myRepositoryUrl)); } if (myChangeSet != null) { cli.addParameter("--rev");
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Init.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Init.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,7 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; import com.intellij.execution.configurations.GeneralCommandLine; -import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -12,25 +11,14 @@ */ public class Init extends VcsRootCommand { - private final String myDefaultPullUrl; - - public Init(@NotNull final Settings settings, @NotNull File workingDir, @NotNull String defaultPullUrl) { - super(settings, workingDir); - myDefaultPullUrl = defaultPullUrl; + public Init(@NotNull final String hgPath, @NotNull final File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } - public void execute() throws VcsException { + public void call() throws VcsException { getWorkDirectory().mkdirs(); GeneralCommandLine cli = createCommandLine(); cli.addParameter("init"); runCommand(cli); - writeDefaultPath(); - } - - - private void writeDefaultPath() { - File hgrc = new File(new File(getWorkDirectory(), ".hg"), "hgrc"); - String content = "[paths]\ndefault = " + myDefaultPullUrl; - FileUtil.writeFile(hgrc, content); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -22,6 +22,7 @@ import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -41,48 +42,68 @@ private String myBranchName; private boolean myCalculateParents = true; private String myRevsets; - private final File myTemplate; + private File myTemplate; - public LogCommand(@NotNull Settings settings, @NotNull File workingDir, @NotNull final File template) { - super(settings, workingDir); + public LogCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); + } + + public LogCommand withTemplate(@NotNull File template) { myTemplate = template; - myBranchName = settings.getBranchName(); + return this; } - public void setFromRevId(String id) { - myFromId = id; + public LogCommand inBranch(@NotNull String branchName) { + myBranchName = branchName; + return this; } - public void setToRevId(String id) { - myToId = id; + public LogCommand fromRevision(@Nullable String fromRevision) { + myFromId = fromRevision == null ? fromRevision : new ChangeSet(fromRevision).getId(); + return this; + } + + public LogCommand toRevision(@Nullable String toRevision) { + myToId = toRevision == null ? toRevision: new ChangeSet(toRevision).getId(); + return this; } - public void setLimit(final int limit) { - myLimit = limit; + public LogCommand toNamedRevision(@Nullable String namedRevision) { + myToId = namedRevision; + return this; } - public void showCommitsFromAllBranches() { - myBranchName = null; + public LogCommand setLimit(final int limit) { + myLimit = limit; + return this; } - public void setCalculateParents(boolean doCalculate) { - myCalculateParents = doCalculate; + public LogCommand showCommitsFromAllBranches() { + myBranchName = null; + return this; } - public void setRevsets(String revsets) { - myRevsets = revsets; + public LogCommand dontCalculateParents() { + myCalculateParents = false; + return this; } - public List<ChangeSet> execute() throws VcsException { + public LogCommand withRevsets(String revsets) { + myRevsets = revsets; + return this; + } + + public List<ChangeSet> call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.setCharset(Charset.forName("UTF-8")); cli.addParameters("--encoding", "UTF-8"); cli.addParameter("log"); cli.addParameter("-v"); - cli.addParameter("--style=" + myTemplate.getAbsolutePath()); + if (myTemplate != null) + cli.addParameter("--style=" + myTemplate.getAbsolutePath()); if (myBranchName != null) { cli.addParameter("-b"); - cli.addParameter(getSettings().getBranchName()); + cli.addParameter(myBranchName); } cli.addParameter("-r"); if (myRevsets != null) { @@ -239,9 +260,9 @@ private String getIdOf(int revNumber) throws VcsException { if (revNumber < 0) return ZERO_PARENT_ID; - IdentifyCommand identify = new IdentifyCommand(getSettings(), getWorkDirectory()); - identify.setInLocalRepository(true); - identify.setRevisionNumber(revNumber); - return identify.execute(); + return new IdentifyCommand(getHgPath(), getWorkDirectory(), myAuthSettings) + .revisionNumber(revNumber) + .inLocalRepository() + .call(); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Analog of git merge-base. It returns a last common ancestor between two revisions. - * - * @author dmitry.neverov - */ -public interface MergeBaseCommand { - - /** - * Returns hash of least common ancestor between two revisions or null - * if common ancestor is not found - * @param revision1 first revision - * @param revision2 second revision - * @return see above - * @throws VcsException if some commands fail - */ - @Nullable - String execute(@NotNull String revision1, @NotNull String revision2) throws VcsException; - -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/ParseHgVersionException.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -/** - * @author dmitry.neverov - */ -public class ParseHgVersionException extends VcsException { - - public ParseHgVersionException(@NotNull String version) { - super("Cannot parse version '" + version + "'"); - } - -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PullCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; import static com.intellij.openapi.util.io.FileUtil.delete; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandExecutionSettingsBuilder.with; @@ -30,23 +31,35 @@ */ public class PullCommand extends VcsRootCommand { - private final String myPullUrl; + private String myPullUrl; + private int myTimeout; - public PullCommand(@NotNull Settings settings, @NotNull File workingDir) { - this(settings, workingDir, settings.getRepositoryUrlWithCredentials()); + public PullCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); + } + + public PullCommand fromRepository(@NotNull String pullUrl) { + myPullUrl = pullUrl; + return this; } - public PullCommand(@NotNull Settings settings, @NotNull File workingDir, @NotNull String pullUrl) { - super(settings, workingDir); - myPullUrl = pullUrl; + public PullCommand fromRepository(@NotNull File localRepository) throws IOException { + myPullUrl = localRepository.getCanonicalPath(); + return this; } - public void execute(int timeout) throws VcsException { + public PullCommand withTimeout(int timeout) { + myTimeout = timeout; + return this; + } + + public void call() throws VcsException { ensureRepositoryIsNotLocked(); GeneralCommandLine cli = createCommandLine(); cli.addParameter("pull"); - cli.addParameter(myPullUrl); - runCommand(cli, with().timeout(timeout)); + String pullUrl = myAuthSettings != null ? myAuthSettings.getRepositoryUrlWithCredentials(myPullUrl) : myPullUrl; + cli.addParameter(pullUrl); + runCommand(cli, with().timeout(myTimeout)); } private void ensureRepositoryIsNotLocked() {
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -27,23 +27,23 @@ * @author pavel */ public class PushCommand extends VcsRootCommand { - private boolean myForced; + + private String myRepositoryUrl; - public PushCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public PushCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } - public void setForce(boolean force) { - myForced = force; + public PushCommand toRepository(@NotNull String repositoryUrl) { + myRepositoryUrl = repositoryUrl; + return this; } - public void execute() throws VcsException { + public void call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("push"); - if (myForced) { - cli.addParameter("-f"); - } - cli.addParameter(getSettings().getRepositoryUrlWithCredentials()); + String repositoryUrl = myAuthSettings != null ? myAuthSettings.getRepositoryUrlWithCredentials(myRepositoryUrl) : myRepositoryUrl; + cli.addParameter(repositoryUrl); runCommand(cli, with().failureWhenStderrNotEmpty()); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/Settings.java Fri Mar 02 14:33:42 2012 +0400 @@ -18,17 +18,12 @@ import jetbrains.buildServer.buildTriggers.vcs.mercurial.Constants; import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgPathProvider; import jetbrains.buildServer.buildTriggers.vcs.mercurial.PathUtil; -import jetbrains.buildServer.log.Loggers; import jetbrains.buildServer.util.StringUtil; import jetbrains.buildServer.vcs.VcsRoot; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.IOException; -import java.net.*; -import java.util.HashSet; -import java.util.Set; /** * Represents Mercurial repository settings @@ -46,6 +41,7 @@ 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; @@ -57,6 +53,7 @@ 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() { @@ -116,86 +113,8 @@ return myUserForTag; } - private final static Set<String> AUTH_PROTOS = new HashSet<String>(); - static { - AUTH_PROTOS.add("http"); - AUTH_PROTOS.add("https"); - AUTH_PROTOS.add("ssh"); - } - public String getRepositoryUrlWithCredentials() { - if (isRequireCredentials()) { - if (containsCredentials(myRepository)) - return myRepository; - try { - return createURLWithCredentials(myRepository); - } catch (MalformedURLException e) { - Loggers.VCS.warn("Error while parsing url " + myRepository, e); - } - return myRepository; - } else { - return myRepository; - } - } - - private boolean containsCredentials(final String repository) { - try { - URL url = new URL(null, repository, new FakeStreamHandler()); - String userInfo = url.getUserInfo(); - return userInfo != null && userInfo.contains(":"); - } catch (MalformedURLException e) { - return false; - } - } - - private String createURLWithCredentials(final String originalUrl) throws MalformedURLException { - String userInfo = createUserInfo(); - if (!"".equals(userInfo)) { - URL url = new URL(null, originalUrl, new FakeStreamHandler()); - return url.getProtocol() + "://" - + userInfo + "@" - + url.getHost() - + (url.getPort() != -1 ? ":" + url.getPort() : "") - + url.getFile() - + (url.getRef() != null ? url.getRef() : ""); - } else { - return originalUrl; - } - } - - private boolean isRequireCredentials() { - for (String scheme : AUTH_PROTOS) { - if (myRepository.startsWith(scheme + ":")) { - return true; - } - } - return false; - } - - private String createUserInfo() { - String userInfo = ""; - if (!StringUtil.isEmpty(myUsername)) { - userInfo += myUsername; - if (!StringUtil.isEmpty(myPassword)) { - userInfo += ":" + myPassword; - } - } - return getEscapedUserInfo(userInfo); - } - - private static String getEscapedUserInfo(String userInfo) { - try { - URI uri = new URI("http", userInfo, "somewhere.com", 80, "", "", ""); - String escapedURI = uri.toASCIIString(); - int from = "http://".length(); - int to = escapedURI.indexOf("somewhere.com") - 1; - String escapedUserInfo = escapedURI.substring(from, to); - escapedUserInfo = escapedUserInfo.replaceAll("&", "%26"); - return escapedUserInfo; - } catch (URISyntaxException e) { - assert false; - } - return userInfo; + return myAuthSettings.getRepositoryUrlWithCredentials(myRepository); } /** @@ -216,15 +135,12 @@ 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(); } - - private class FakeStreamHandler extends URLStreamHandler { - @Override - protected URLConnection openConnection(URL u) throws IOException { - throw new UnsupportedOperationException(); - } - } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -27,19 +27,31 @@ private String myFromId; private String myToId; - public StatusCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public StatusCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); + } + + public StatusCommand fromRevision(@NotNull ChangeSet fromCset) { + myFromId = fromCset.getId(); + return this; } - public void setFromRevId(final String fromId) { - myFromId = fromId; + public StatusCommand fromRevision(@NotNull String fromRevision) { + myFromId = new ChangeSet(fromRevision).getId(); + return this; } - public void setToRevId(final String toId) { - myToId = toId; + public StatusCommand toRevision(@NotNull ChangeSet toCset) { + myToId = toCset.getId(); + return this; } - public List<ModifiedFile> execute() throws VcsException { + public StatusCommand toRevision(@NotNull String toRevision) { + myToId = new ChangeSet(toRevision).getId(); + return this; + } + + public List<ModifiedFile> call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("status"); cli.addParameter("--rev");
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/TagCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -18,6 +18,7 @@ import com.intellij.execution.configurations.GeneralCommandLine; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; @@ -26,23 +27,26 @@ private String myRevId; private String myUsername; - public TagCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public TagCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir, authSettings); } - public void setTag(@NotNull final String tag) { - myTag = tag; + public TagCommand tagName(@NotNull String tagName) { + myTag = tagName; + return this; } - public void setRevId(@NotNull final String revId) { - myRevId = revId; + public TagCommand revision(@NotNull String revision) { + myRevId = new ChangeSet(revision).getId(); + return this; } - public void setUser(@NotNull final String username) { + public TagCommand byUser(@Nullable final String username) { myUsername = username; + return this; } - public void execute() throws VcsException { + public void call() throws VcsException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("tag"); setUser(cli);
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnknownFileException.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -/** - * @author dmitry.neverov - */ -public class UnknownFileException extends VcsException { - - private final String myPath; - - public UnknownFileException(@NotNull String path) { - super("Unknown file " + path); - myPath = path; - } - - public String getPath() { - return myPath; - } - -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnknownRevisionException.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -/** - * @author dmitry.neverov - */ -public class UnknownRevisionException extends VcsException { - - private final String myRevision; - - public UnknownRevisionException(@NotNull final String revision) { - super("Unknown revision " + revision); - myRevision = revision; - } - - @NotNull - public String getRevision() { - return myRevision; - } - -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UnrelatedRepositoryException.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; - -import jetbrains.buildServer.vcs.VcsException; - -/** - * @author dmitry.neverov - */ -public class UnrelatedRepositoryException extends VcsException { - -}
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/UpdateCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -20,8 +20,6 @@ import org.jetbrains.annotations.NotNull; import java.io.File; -import java.util.HashMap; -import java.util.Map; import static com.intellij.openapi.util.io.FileUtil.delete; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandExecutionSettingsBuilder.with; @@ -31,32 +29,38 @@ private static final int UPDATE_TIMEOUT_SECONDS = 8 * 3600;//8 hours private String myToId; - private final Map<String, String> myConfigParams = new HashMap<String, String>(); + private String myBranchName; - public UpdateCommand(@NotNull Settings settings, @NotNull File workingDir) { - super(settings, workingDir); + public UpdateCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir,authSettings); } - public void setToId(final String toId) { - myToId = toId; - } - - public UpdateCommand withConfig(@NotNull String paramName, @NotNull String paramValue) { - myConfigParams.put(paramName, paramValue); + public UpdateCommand branch(@NotNull String branchName) { + myBranchName = branchName; return this; } - public void execute() throws VcsException { + public UpdateCommand toRevision(@NotNull String revision) { + return toRevision(new ChangeSet(revision)); + } + + public UpdateCommand toRevision(@NotNull ChangeSet cset) { + myToId = cset.getId(); + return this; + } + + public void call() throws VcsException { ensureWorkingDirIsNotLocked(); + GeneralCommandLine cli = createCommandLine(); cli.addParameter("update"); - addConfigParams(cli); + addAuthConfigParams(cli); cli.addParameter("-C"); cli.addParameter("-r"); if (myToId != null) { cli.addParameter(myToId); } else { - cli.addParameter(getSettings().getBranchName()); + cli.addParameter(myBranchName); } runCommand(cli, with().timeout(UPDATE_TIMEOUT_SECONDS)); } @@ -67,11 +71,15 @@ delete(lock); } - private void addConfigParams(GeneralCommandLine cmd) { - for (Map.Entry<String, String> entry : myConfigParams.entrySet()) { - cmd.addParameter("--config"); - cmd.addParameter(entry.getKey() + "=" + entry.getValue()); - } + private void addAuthConfigParams(GeneralCommandLine cmd) { + if (myAuthSettings == null) + return; + if (myAuthSettings.getUsername() == null || myAuthSettings.getPassword() == null) + return; + cmd.addParameters("--config", "auth.tc.prefix=*"); + cmd.addParameters("--config", "auth.tc.username=" + myAuthSettings.getUsername()); + cmd.addParameters("--config", "auth.tc.password=" + myAuthSettings.getPassword()); + cmd.addParameters("--config", "auth.tc.schemes=http https"); } @NotNull
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VcsRootCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -15,18 +15,14 @@ */ public class VcsRootCommand extends BaseCommand { - private final Settings mySettings; + protected final AuthSettings myAuthSettings; - public VcsRootCommand(@NotNull final Settings settings, @NotNull final File workDir) { - super(settings.getHgCommandPath(), workDir); - mySettings = settings; + public VcsRootCommand(@NotNull String hgPath, @NotNull File workingDir, @NotNull AuthSettings authSettings) { + super(hgPath, workingDir); + myAuthSettings = authSettings; } - public Settings getSettings() { - return mySettings; - } - protected CommandResult runCommand(@NotNull GeneralCommandLine cli) throws VcsException { return CommandUtil.runCommand(cli, with()); } @@ -36,7 +32,7 @@ } protected Set<String> getPrivateData() { - String password = mySettings.getPassword(); + String password = myAuthSettings.getPassword(); return password != null ? Collections.singleton(password) : Collections.<String>emptySet(); } }
--- a/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -2,6 +2,7 @@ import com.intellij.execution.configurations.GeneralCommandLine; import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgVersion; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ParseHgVersionException; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -22,7 +23,7 @@ } - public HgVersion execute() throws VcsException, ParseHgVersionException { + public HgVersion call() throws VcsException, ParseHgVersionException { GeneralCommandLine cli = createCommandLine(); cli.addParameter("version"); cli.addParameter("--quiet");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/ConnectionRefusedException.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,14 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; + +/** + * @author dmitry.neverov + */ +public class ConnectionRefusedException extends VcsException { + + public ConnectionRefusedException() { + super("Connection refused"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/ParseHgVersionException.java Fri Mar 02 14:33:42 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 ParseHgVersionException extends VcsException { + + public ParseHgVersionException(@NotNull String version) { + super("Cannot parse version '" + version + "'"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/UnknownFileException.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,22 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class UnknownFileException extends VcsException { + + private final String myPath; + + public UnknownFileException(@NotNull String path) { + super("Unknown file " + path); + myPath = path; + } + + public String getPath() { + return myPath; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/UnknownRevisionException.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,23 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +/** + * @author dmitry.neverov + */ +public class UnknownRevisionException extends VcsException { + + private final String myRevision; + + public UnknownRevisionException(@NotNull final String revision) { + super("Unknown revision " + revision); + myRevision = revision; + } + + @NotNull + public String getRevision() { + return myRevision; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/exception/UnrelatedRepositoryException.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,10 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception; + +import jetbrains.buildServer.vcs.VcsException; + +/** + * @author dmitry.neverov + */ +public class UnrelatedRepositoryException extends VcsException { + +}
--- a/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-server/src/META-INF/build-server-plugin-mercurial.xml Fri Mar 02 14:33:42 2012 +0400 @@ -4,7 +4,7 @@ <beans default-autowire="constructor"> <bean id="mercurialServer" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.MercurialVcsSupport" /> <bean id="config" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerPluginConfigImpl" /> - <bean id="commandFactory" class="jetbrains.buildServer.buildTriggers.vcs.mercurial.CommandFactoryImpl" /> + <bean id="commandFactory" 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" /> </beans>
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesCommand.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * @author dmitry.neverov - */ -public interface CollectChangesCommand { - - @NotNull - public List<ChangeSet> execute(@NotNull String fromCommit, @NotNull String toCommit) throws VcsException; - -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesNoRevsets.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import com.intellij.openapi.util.Pair; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.util.graph.DAG; -import jetbrains.buildServer.util.graph.DAGIterator; -import jetbrains.buildServer.util.graph.DAGs; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.*; - -/** - * @author dmitry.neverov - */ -public class CollectChangesNoRevsets implements CollectChangesCommand { - - private final Settings mySettings; - private final File myWorkingDir; - private final File myTemplate; - - public CollectChangesNoRevsets(@NotNull final Settings settings, - @NotNull final File workingDir, - @NotNull final File template) { - mySettings = settings; - myWorkingDir = workingDir; - myTemplate = template; - } - - - @NotNull - public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { - List<ChangeSet> csets = getRevisionsReachableFrom(toCommit); - Map<String, ChangeSet> csetsMap = getChangesetMap(csets); - if (csetsMap.containsKey(fromCommit)) { - DAG<String> dag = DAGs.createFromEdges(getEdges(csets)); - DAGIterator<String> iter = dag.iterator(toCommit); - iter.markUninteresting(fromCommit); - List<ChangeSet> result = new ArrayList<ChangeSet>(); - while (iter.hasNext()) { - String commit = iter.next(); - ChangeSet cset = csetsMap.get(commit); - if (cset == null) - throw new IllegalStateException("Cannot find cset for id " + commit + ", csets map: " + csetsMap); - result.add(cset); - } - Collections.reverse(result); - return result; - } else { - return Collections.emptyList(); - } - } - - - private Map<String, ChangeSet> getChangesetMap(@NotNull final List<ChangeSet> csets) { - Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); - for (ChangeSet cset : csets) { - result.put(cset.getId(), cset); - } - return result; - } - - - private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { - LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); - log.setFromRevId(new ChangeSetRevision(revision).getId()); - log.showCommitsFromAllBranches(); - log.setToRevId("0"); - return log.execute(); - } - - - private List<Pair<String, String>> getEdges(List<ChangeSet> csets) { - List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); - for (ChangeSet cset : csets) { - for (ChangeSetRevision parent : cset.getParents()) { - result.add(Pair.create(cset.getId(), parent.getId())); - } - } - return result; - } -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CollectChangesWithRevsets.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ChangeSet; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.List; - -/** - * @author dmitry.neverov - */ -public class CollectChangesWithRevsets implements CollectChangesCommand { - - private final Settings mySettings; - private final File myWorkingDir; - private final File myTemplate; - - public CollectChangesWithRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final File template) { - mySettings = settings; - myWorkingDir = workingDir; - myTemplate = template; - } - - @NotNull - public List<ChangeSet> execute(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { - LogCommand log = new LogCommand(mySettings, myWorkingDir, myTemplate); - log.showCommitsFromAllBranches(); - log.setRevsets("ancestors(" + toCommit + ") - ancestors(" + fromCommit + ")"); - return log.execute(); - } -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactory.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.MergeBaseCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; - -/** - * @author dmitry.neverov - */ -public interface CommandFactory { - - @NotNull - public MergeBaseCommand createMergeBase(@NotNull Settings settings, @NotNull File workingDir) throws VcsException; - - @NotNull - public LogCommand createLog(@NotNull final Settings settings, @NotNull final File workingDir); - - @NotNull - public CollectChangesCommand getCollectChangesCommand(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException; - -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/CommandFactoryImpl.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.LogCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.MergeBaseCommand; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.VersionCommand; -import jetbrains.buildServer.util.FileUtil; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.io.IOException; - -/** - * @author dmitry.neverov - */ -public final class CommandFactoryImpl implements CommandFactory { - - //hg version which supports revsets - private final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0); - private final static String LOG_TEMPLATE_NAME = "log.template"; - - private final File myDefaultWorkingDir; - private final File myLogTemplate; - - - public CommandFactoryImpl(@NotNull final ServerPluginConfig config) throws IOException { - myDefaultWorkingDir = config.getCachesDir(); - myLogTemplate = createLogTemplate(config.getPluginDataDir()); - } - - - @NotNull - public MergeBaseCommand createMergeBase(@NotNull Settings settings, @NotNull File workingDir) throws VcsException { - HgVersion hgVersion = getHgVersion(settings); - if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) - return new MergeBaseWithRevsets(settings, workingDir, this); - else - return new MergeBaseNoRevsets(settings, workingDir, this); - } - - - @NotNull - public LogCommand createLog(@NotNull final Settings settings, @NotNull final File workingDir) { - return new LogCommand(settings, workingDir, myLogTemplate); - } - - @NotNull - public CollectChangesCommand getCollectChangesCommand(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - HgVersion hgVersion = getHgVersion(settings); - if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) { - return new CollectChangesWithRevsets(settings, workingDir, myLogTemplate); - } else { - return new CollectChangesNoRevsets(settings, workingDir, myLogTemplate); - } - } - - private File createLogTemplate(@NotNull final File templateFileDir) throws IOException { - File template = new File(templateFileDir, LOG_TEMPLATE_NAME); - FileUtil.copyResource(CommandFactoryImpl.class, "/buildServerResources/log.template", template); - return template; - } - - private HgVersion getHgVersion(@NotNull final Settings settings) throws VcsException { - VersionCommand versionCommand = new VersionCommand(settings, myDefaultWorkingDir); - return versionCommand.execute(); - } -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupport.java Fri Mar 02 14:33:42 2012 +0400 @@ -19,6 +19,8 @@ import jetbrains.buildServer.Used; import jetbrains.buildServer.buildTriggers.vcs.AbstractVcsPropertiesProcessor; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownRevisionException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.log.Loggers; import jetbrains.buildServer.serverSide.*; import jetbrains.buildServer.util.EventDispatcher; @@ -37,8 +39,6 @@ import java.io.IOException; import java.util.*; -import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces; - /** * Mercurial VCS plugin for TeamCity works as follows: * <ul> @@ -57,7 +57,7 @@ private final MirrorManager myMirrorManager; private final ServerPluginConfig myConfig; private final HgPathProvider myHgPathProvider; - private final CommandFactory myCommandFactory; + private final RepoFactory myRepoFactory; private final FileFilter myIgnoreDotHgFilter = new IgnoreDotHgFilter(); private final FileFilter myAcceptAllFilter = new AcceptAllFilter(); @@ -67,14 +67,14 @@ @NotNull final ResetCacheRegister resetCacheHandlerManager, @NotNull final ServerPluginConfig config, @NotNull final HgPathProvider hgPathProvider, - @NotNull final CommandFactory commandFactory, + @NotNull final RepoFactory repoFactory, @NotNull final MirrorManager mirrorManager) { myVcsManager = vcsManager; myConfig = config; myDefaultWorkFolderParent = myConfig.getCachesDir(); myMirrorManager = mirrorManager; myHgPathProvider = hgPathProvider; - myCommandFactory = commandFactory; + myRepoFactory = repoFactory; resetCacheHandlerManager.registerHandler(new MercurialResetCacheHandler(myMirrorManager)); dispatcher.addListener(new BuildServerAdapter() { @Override @@ -161,10 +161,8 @@ ChangeSet cset = new ChangeSet(version); Settings settings = createSettings(vcsRoot); syncRepository(settings, cset); - File workingDir = getWorkingDir(settings); - CatCommand cc = new CatCommand(settings, workingDir); - cc.setRevId(cset.getId()); - File parentDir = cc.execute(Collections.singletonList(filePath)); + HgRepo repo = createRepo(settings); + File parentDir = repo.cat().files(filePath).atRevision(cset).call(); File file = new File(parentDir, filePath); try { return FileUtil.loadFileBytes(file); @@ -211,13 +209,11 @@ public String getCurrentVersion(@NotNull final VcsRoot root) throws VcsException { Settings settings = createSettings(root); syncRepository(settings); - File workingDir = getWorkingDir(settings); - BranchesCommand branches = new BranchesCommand(settings, workingDir); - Map<String, ChangeSet> result = branches.execute(); + HgRepo repo = createRepo(settings); + 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()); } - return result.get(settings.getBranchName()).getFullVersion(); } @@ -235,14 +231,15 @@ return new TestConnectionSupport() { public String testConnection(@NotNull final VcsRoot vcsRoot) throws VcsException { Settings settings = createSettings(vcsRoot); - File workingDir = getWorkingDir(settings); - IdentifyCommand id = new IdentifyCommand(settings, workingDir); + String idResult = createRepo(settings).id() + .repository(settings.getRepository()) + .withAuthSettings(settings.getAuthSettings()) + .call(); StringBuilder res = new StringBuilder(); res.append(quoteIfNeeded(settings.getHgCommandPath())); res.append(" identify "); - final String obfuscatedUrl = CommandUtil.removePrivateData(settings.getRepositoryUrlWithCredentials(), Collections.singleton(settings.getPassword())); - res.append(quoteIfNeeded(obfuscatedUrl)); - res.append('\n').append(id.execute()); + res.append(quoteIfNeeded(settings.getAuthSettings().getRepositoryUrlWithHiddenPassword(settings.getRepository()))); + res.append('\n').append(idResult); return res.toString(); } }; @@ -252,7 +249,6 @@ if (str.indexOf(' ') != -1) { return "\"" + str + "\""; } - return str; } @@ -287,11 +283,8 @@ // 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) throws VcsException, IOException { - File workingDir = getWorkingDir(settings); - StatusCommand st = new StatusCommand(settings, workingDir); - st.setFromRevId(fromVer.getId()); - st.setToRevId(toVer.getId()); - List<ModifiedFile> modifiedFiles = st.execute(); + HgRepo repo = createRepo(settings); + List<ModifiedFile> modifiedFiles = repo.status().fromRevision(fromVer).toRevision(toVer).call(); List<String> notDeletedFiles = new ArrayList<String>(); for (ModifiedFile f: modifiedFiles) { if (f.getStatus() != ModifiedFile.Status.REMOVED) { @@ -299,12 +292,10 @@ } } - if (notDeletedFiles.isEmpty()) return; + if (notDeletedFiles.isEmpty()) + return; - CatCommand cc = new CatCommand(settings, workingDir); - cc.setRevId(toVer.getId()); - File parentDir = cc.execute(notDeletedFiles); - + File parentDir = repo.cat().files(notDeletedFiles).atRevision(toVer).call(); try { for (ModifiedFile f: modifiedFiles) { String mappedPath = checkoutRules.map(f.getPath()); @@ -339,27 +330,22 @@ throws IOException, VcsException { File tempDir = FileUtil.createTempDirectory("mercurial", toVer.getId()); try { - File mirrorDir = getWorkingDir(settings); - if (hasSubrepositories(settings, toVer)) { + HgRepo repo = createRepo(settings); + if (repo.hasSubreposAtRevision(toVer)) { Loggers.VCS.debug("Repository '" + settings.getRepository() + "' has submodules at revision " + toVer.getId() + ", use 'hg clone' to build clean patch"); - CloneCommand cl = new CloneCommand(settings, tempDir); - cl.setRepository(mirrorDir.getAbsolutePath()); - cl.setToId(toVer.getId()); - cl.setUpdateWorkingDir(false); - cl.setUsePullProtocol(myConfig.isUsePullProtocol()); - cl.execute(); - - UpdateCommand up = new UpdateCommand(settings, tempDir); - up.setToId(toVer.getId()); - up.execute(); - + File mirrorDir = getWorkingDir(settings); + HgRepo cloneOfTheMirror = createRepo(settings, tempDir); + cloneOfTheMirror.doClone().fromRepository(mirrorDir) + .setUpdateWorkingDir(false) + .setUsePullProtocol(false) + .useUncompressedTransfer(false) + .call(); + cloneOfTheMirror.setDefaultPath(settings.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"); - ArchiveCommand archive = new ArchiveCommand(settings, mirrorDir); - archive.setDestDir(tempDir); - archive.setToId(toVer.getId()); - archive.execute(); + repo.archive().revision(toVer).toDir(tempDir).call(); buildPatchFromDirectory(builder, tempDir, checkoutRules, myAcceptAllFilter); } } finally { @@ -367,38 +353,6 @@ } } - private boolean hasSubrepositories(@NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { - String hgsub = getFileContent(".hgsub", settings, cset); - return !isEmptyOrSpaces(hgsub); - } - - /** - * Returns file's content or empty string if it doesn't exist. - * @param path path of the file of interest - * @param settings root settings - * @param cset repository cset (should be present in the repository) - * @return see above - */ - @NotNull - private String getFileContent(@NotNull final String path, @NotNull final Settings settings, @NotNull final ChangeSet cset) throws VcsException { - File dir = getWorkingDir(settings); - CatCommand cat = new CatCommand(settings, dir); - cat.setRevId(cset.getId()); - File parentDir = cat.execute(Collections.singletonList(path), false); - try { - File f = new File(parentDir, path); - if (f.isFile()) - return FileUtil.readText(f); - else - return ""; - } catch (Exception e) { - return ""; - } finally { - deleteTmpDir(parentDir); - } - } - - private void buildPatchFromDirectory(final PatchBuilder builder, final File repRoot, final CheckoutRules checkoutRules, @NotNull final FileFilter filter) throws IOException { buildPatchFromDirectory(repRoot, builder, repRoot, checkoutRules, filter); } @@ -431,28 +385,29 @@ } } - /** - * clone the repo if it doesn't exist, pull the repo if it doesn't contain specified changeSet - */ + /* 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); lockWorkDir(workingDir); + HgRepo repo = createRepo(settings); try { - if (Settings.isValidRepository(workingDir)) { - if (!isChangeSetExist(settings, workingDir, cset)) { - try { - PullCommand pull = new PullCommand(settings, workingDir); - pull.execute(myConfig.getPullTimeout()); - } catch (UnrelatedRepositoryException e) { - Loggers.VCS.warn("Repository at " + settings.getRepository() + " is unrelated, clone it again"); - myMirrorManager.forgetDir(workingDir); - syncRepository(settings, cset); - } + if (repo.isValidRepository()) { + if (repo.containsRevision(cset)) + return; + try { + repo.pull().fromRepository(settings.getRepository()) + .withTimeout(myConfig.getPullTimeout()) + .call(); + } catch (UnrelatedRepositoryException e) { + Loggers.VCS.warn("Repository at " + settings.getRepository() + " is unrelated, clone it again"); + myMirrorManager.forgetDir(workingDir); + syncRepository(settings, cset); } } else { - CloneCommand cl = new CloneCommand(settings, workingDir); - cl.setUpdateWorkingDir(false); - cl.execute(); + repo.doClone().fromRepository(settings.getRepository()) + .useUncompressedTransfer(settings.isUncompressedTransfer()) + .setUpdateWorkingDir(false) + .call(); } } finally { unlockWorkDir(workingDir); @@ -462,45 +417,29 @@ private void syncRepository(final Settings settings) throws VcsException { File workingDir = getWorkingDir(settings); lockWorkDir(workingDir); + HgRepo repo = createRepo(settings); try { - if (Settings.isValidRepository(workingDir)) { + if (repo.isValidRepository()) { try { - PullCommand pull = new PullCommand(settings, workingDir); - pull.execute(myConfig.getPullTimeout()); + repo.pull().fromRepository(settings.getRepository()) + .withTimeout(myConfig.getPullTimeout()) + .call(); } catch (UnrelatedRepositoryException e) { Loggers.VCS.warn("Repository at " + settings.getRepository() + " is unrelated, clone it again"); myMirrorManager.forgetDir(workingDir); syncRepository(settings); } } else { - CloneCommand cl = new CloneCommand(settings, workingDir); - cl.setUpdateWorkingDir(false); - cl.execute(); + repo.doClone().fromRepository(settings.getRepository()) + .setUpdateWorkingDir(false) + .useUncompressedTransfer(settings.isUncompressedTransfer()) + .call(); } } finally { unlockWorkDir(workingDir); } } - /** - * Check if changeSet is present in local repository. - * @param settings root settings - * @param workDir where to run a command - * @param cset change set of interest - * @return true if changeSet is present in local repository - */ - private boolean isChangeSetExist(Settings settings, File workDir, ChangeSet cset) { - try { - IdentifyCommand identify = new IdentifyCommand(settings, workDir); - identify.setInLocalRepository(true); - identify.setChangeSet(cset); - identify.execute(); - return true; - } catch (VcsException e) { - return false; - } - } - @Override public LabelingSupport getLabelingSupport() { return this; @@ -525,10 +464,9 @@ private Map<String, String> getBranchesRevisions(@NotNull VcsRoot root) throws VcsException { Settings settings = createSettings(root); syncRepository(settings); - File workingDir = getWorkingDir(settings); - BranchesCommand branches = new BranchesCommand(settings, workingDir); + HgRepo repo = createRepo(settings); Map<String, String> result = new HashMap<String, String>(); - for (Map.Entry<String, ChangeSet> entry : branches.execute().entrySet()) { + for (Map.Entry<String, ChangeSet> entry : repo.branches().call().entrySet()) { result.put(entry.getKey(), entry.getValue().getId()); } return result; @@ -553,11 +491,11 @@ if (mergeBase == null) return null; - LogCommand lc = myCommandFactory.createLog(settings, getWorkingDir(settings)); - lc.setFromRevId(new ChangeSetRevision(mergeBase).getId()); - lc.setToRevId(new ChangeSetRevision(branchVersion).getId()); - lc.showCommitsFromAllBranches(); - List<ChangeSet> changeSets = lc.execute(); + List<ChangeSet> changeSets = createRepo(settings).log() + .fromRevision(mergeBase) + .toRevision(branchVersion) + .showCommitsFromAllBranches() + .call(); if (changeSets.size() > 1) {//when branch points to the commit in original branch we get 1 cset String branchId = changeSets.get(1).getId(); String username = changeSets.get(changeSets.size() - 1).getUser(); @@ -590,7 +528,10 @@ @Nullable private String getMergeBase(@NotNull Settings settings, @NotNull String revision1, @NotNull String revision2) throws VcsException { - String result = myCommandFactory.createMergeBase(settings, getWorkingDir(settings)).execute(revision1, revision2); + String result = createRepo(settings).mergeBase() + .revision1(revision1) + .revision2(revision2) + .call(); if (result == null) result = getMinusNthCommit(settings, 10); return result; @@ -599,11 +540,12 @@ @Nullable private String getMinusNthCommit(@NotNull Settings settings, int n) throws VcsException { - LogCommand log = myCommandFactory.createLog(settings, getWorkingDir(settings)); - log.setToRevId(settings.getBranchName()); + LogCommand log = createRepo(settings).log() + .inBranch(settings.getBranchName()) + .toNamedRevision(settings.getBranchName()); if (n > 0) log.setLimit(n); - List<ChangeSet> changeSets = log.execute(); + List<ChangeSet> changeSets = log.call(); if (changeSets.isEmpty()) return null; return changeSets.get(0).getId(); @@ -647,10 +589,11 @@ return Collections.emptyList(); String fromCommit = new ChangeSetRevision(fromVersion).getId(); String toCommit = new ChangeSetRevision(toVersion).getId(); - File workingDir = getWorkingDir(settings); - CollectChangesCommand log = myCommandFactory.getCollectChangesCommand(settings, workingDir); try { - List<ChangeSet> changesets = log.execute(fromCommit, toCommit); + List<ChangeSet> changesets = createRepo(settings).collectChanges() + .fromRevision(fromCommit) + .toRevision(toCommit) + .call(); Iterator<ChangeSet> iter = changesets.iterator(); while (iter.hasNext()) { ChangeSet cset = iter.next(); @@ -706,20 +649,16 @@ Settings settings = createSettings(root); settings.setCustomWorkingDir(tmpDir); syncRepository(settings); - File workingDir = getWorkingDir(settings); - new UpdateCommand(settings, workingDir).execute(); + HgRepo repo = createRepo(settings); + repo.update().branch(settings.getBranchName()).call(); String fixedTagname = fixTagName(label); - TagCommand tc = new TagCommand(settings, workingDir); - tc.setRevId(new ChangeSet(version).getId()); - tc.setTag(fixedTagname); - String user = settings.getUserForTag(); - if (user != null) - tc.setUser(user); - tc.execute(); + repo.tag().revision(version) + .tagName(fixedTagname) + .byUser(settings.getUserForTag()) + .call(); - PushCommand pc = new PushCommand(settings, workingDir); - pc.execute(); + repo.push().toRepository(settings.getRepository()).call(); return fixedTagname; } finally { if (tmpDir != null) @@ -805,6 +744,14 @@ } } + private ServerHgRepo createRepo(@NotNull Settings s) { + return myRepoFactory.create(getWorkingDir(s), s.getHgCommandPath(), s.getAuthSettings()); + } + + private HgRepo createRepo(@NotNull Settings s, @NotNull File customDir) { + return myRepoFactory.create(customDir, s.getHgCommandPath(), s.getAuthSettings()); + } + @NotNull public String getBranchName(@NotNull final VcsRoot root) { try {
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseNoRevsets.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import com.intellij.openapi.util.Pair; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.util.graph.DAG; -import jetbrains.buildServer.util.graph.DAGs; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.*; - -/** - * Implementation of merge-base for hg versions which don't have revsets - * @author dmitry.neverov - */ -public final class MergeBaseNoRevsets implements MergeBaseCommand { - - private final Settings mySettings; - private final File myWorkingDir; - private final CommandFactoryImpl myCommandFactory; - - public MergeBaseNoRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final CommandFactoryImpl commandFactory) { - mySettings = settings; - myWorkingDir = workingDir; - myCommandFactory = commandFactory; - } - - - @Nullable - public String execute(@NotNull final String revision1, @NotNull final String revision2) { - if (revision1.equals(revision2)) - return revision1; - try { - List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>(); - fillEdges(edges, getRevisionsReachableFrom(revision1)); - fillEdges(edges, getRevisionsReachableFrom(revision2)); - DAG<String> dag = DAGs.createFromEdges(edges); - List<String> commonAncestors = dag.getCommonAncestors(new ChangeSetRevision(revision1).getId(), new ChangeSetRevision(revision2).getId()); - return commonAncestors.isEmpty() ? null : commonAncestors.get(0); - } catch (VcsException e) { - return null; - } - } - - - private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { - LogCommand log = myCommandFactory.createLog(mySettings, myWorkingDir); - log.setFromRevId(new ChangeSetRevision(revision).getId()); - log.showCommitsFromAllBranches(); - log.setToRevId("0"); - return log.execute(); - } - - - private void fillEdges(List<Pair<String, String>> edges, List<ChangeSet> csets) { - for (ChangeSet cset : csets) { - for (ChangeSetRevision parent : cset.getParents()) { - edges.add(Pair.create(cset.getId(), parent.getId())); - } - } - } -}
--- a/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MergeBaseWithRevsets.java Thu Mar 01 20:16:58 2012 +0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -package jetbrains.buildServer.buildTriggers.vcs.mercurial; - -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; -import jetbrains.buildServer.vcs.VcsException; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.List; - -/** - * Implementation of merge-base using hg revsets - * @author dmitry.neverov - */ -public final class MergeBaseWithRevsets implements MergeBaseCommand { - - private final Settings mySettings; - private final File myWorkingDir; - private final CommandFactoryImpl myCommandFactory; - - public MergeBaseWithRevsets(@NotNull final Settings settings, @NotNull final File workingDir, @NotNull final CommandFactoryImpl commandFactory) { - mySettings = settings; - myWorkingDir = workingDir; - myCommandFactory = commandFactory; - } - - public String execute(@NotNull final String revision1, @NotNull final String revision2) throws VcsException { - try { - LogCommand log = myCommandFactory.createLog(mySettings, myWorkingDir); - log.setRevsets("ancestor(" + new ChangeSetRevision(revision1).getId() + ", " + new ChangeSetRevision(revision2).getId() + ")"); - log.showCommitsFromAllBranches(); - log.setCalculateParents(false); - List<ChangeSet> csets = log.execute(); - return csets.isEmpty() ? null : csets.get(0).getId(); - } catch (VcsException e) { - return null; - } - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/RepoFactory.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,32 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.util.FileUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +/** + * @author dmitry.neverov + */ +public final class RepoFactory { + + private final static String LOG_TEMPLATE_NAME = "log.template"; + private final File myLogTemplate; + + public RepoFactory(@NotNull ServerPluginConfig config) throws IOException { + myLogTemplate = createLogTemplate(config.getPluginDataDir()); + } + + @NotNull + public ServerHgRepo create(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) { + return new ServerHgRepo(workingDir, hgPath, authSettings).withLogTemplate(myLogTemplate); + } + + private File createLogTemplate(@NotNull final File templateFileDir) throws IOException { + File template = new File(templateFileDir, LOG_TEMPLATE_NAME); + FileUtil.copyResource(RepoFactory.class, "/buildServerResources/log.template", template); + return template; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/ServerHgRepo.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,52 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * @author dmitry.neverov + */ +public class ServerHgRepo extends HgRepo { + + private final static HgVersion REVSET_HG_VERSION = new HgVersion(1, 7, 0); + private File myLogTemplate; + + public ServerHgRepo(@NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) { + super(workingDir, hgPath, authSettings); + } + + public ServerHgRepo withLogTemplate(@NotNull File logTemplate) { + myLogTemplate = logTemplate; + return this; + } + + public LogCommand log() { + return new LogCommand(myHgPath, myWorkingDir, myAuthSettings).withTemplate(myLogTemplate); + } + + public MergeBaseCommand mergeBase() throws VcsException { + HgVersion hgVersion = getHgVersion(); + if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) + return new MergeBaseWithRevsets(this); + else + return new MergeBaseNoRevsets(this); + } + + @NotNull + public CollectChangesCommand collectChanges() throws VcsException { + HgVersion hgVersion = getHgVersion(); + if (hgVersion.isEqualsOrGreaterThan(REVSET_HG_VERSION)) { + return new CollectChangesWithRevsets(this); + } else { + return new CollectChangesNoRevsets(this); + } + } + + private HgVersion getHgVersion() throws VcsException { + VersionCommand versionCommand = new VersionCommand(myHgPath, myWorkingDir); + return versionCommand.call(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,32 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author dmitry.neverov + */ +public abstract class CollectChangesCommand { + + protected String myFromRevision; + protected String myToRevision; + + @NotNull + public abstract List<ChangeSet> call(@NotNull String fromCommit, @NotNull String toCommit) throws VcsException; + + public abstract List<ChangeSet> call() throws VcsException; + + public CollectChangesCommand fromRevision(@NotNull String fromRevision) { + myFromRevision = fromRevision; + return this; + } + + public CollectChangesCommand toRevision(@NotNull String toRevision) { + myToRevision = toRevision; + return this; + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesNoRevsets.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,80 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.ServerHgRepo; +import jetbrains.buildServer.util.graph.DAG; +import jetbrains.buildServer.util.graph.DAGIterator; +import jetbrains.buildServer.util.graph.DAGs; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +/** + * @author dmitry.neverov + */ +public class CollectChangesNoRevsets extends CollectChangesCommand { + + private ServerHgRepo myRepo; + + public CollectChangesNoRevsets(@NotNull ServerHgRepo repo) { + myRepo = repo; + } + + @Override + public List<ChangeSet> call() throws VcsException { + return call(myFromRevision, myToRevision); + } + + @NotNull + public List<ChangeSet> call(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + List<ChangeSet> csets = getRevisionsReachableFrom(toCommit); + Map<String, ChangeSet> csetsMap = getChangesetMap(csets); + if (csetsMap.containsKey(fromCommit)) { + DAG<String> dag = DAGs.createFromEdges(getEdges(csets)); + DAGIterator<String> iter = dag.iterator(toCommit); + iter.markUninteresting(fromCommit); + List<ChangeSet> result = new ArrayList<ChangeSet>(); + while (iter.hasNext()) { + String commit = iter.next(); + ChangeSet cset = csetsMap.get(commit); + if (cset == null) + throw new IllegalStateException("Cannot find cset for id " + commit + ", csets map: " + csetsMap); + result.add(cset); + } + Collections.reverse(result); + return result; + } else { + return Collections.emptyList(); + } + } + + + private Map<String, ChangeSet> getChangesetMap(@NotNull final List<ChangeSet> csets) { + Map<String, ChangeSet> result = new HashMap<String, ChangeSet>(); + for (ChangeSet cset : csets) { + result.put(cset.getId(), cset); + } + return result; + } + + + private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { + return myRepo.log() + .fromRevision(revision) + .toRevision("0") + .showCommitsFromAllBranches() + .call(); + } + + + private List<Pair<String, String>> getEdges(List<ChangeSet> csets) { + List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); + for (ChangeSet cset : csets) { + for (ChangeSetRevision parent : cset.getParents()) { + result.add(Pair.create(cset.getId(), parent.getId())); + } + } + return result; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CollectChangesWithRevsets.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,32 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author dmitry.neverov + */ +public class CollectChangesWithRevsets extends CollectChangesCommand { + + private HgRepo myRepo; + + public CollectChangesWithRevsets(@NotNull HgRepo repo) { + myRepo = repo; + } + + @Override + public List<ChangeSet> call() throws VcsException { + return call(myFromRevision, myToRevision); + } + + @NotNull + public List<ChangeSet> call(@NotNull final String fromCommit, @NotNull final String toCommit) throws VcsException { + return myRepo.log() + .showCommitsFromAllBranches() + .withRevsets("ancestors(" + toCommit + ") - ancestors(" + fromCommit + ")") + .call(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseCommand.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,42 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Analog of git merge-base. It returns a last common ancestor between two revisions. + * + * @author dmitry.neverov + */ +public abstract class MergeBaseCommand { + + protected final HgRepo myRepo; + protected String myRevision1; + protected String myRevision2; + + protected MergeBaseCommand(@NotNull HgRepo repo) { + myRepo = repo; + } + + public MergeBaseCommand revision1(String revision1) { + myRevision1 = revision1; + return this; + } + + public MergeBaseCommand revision2(String revision2) { + myRevision2 = revision2; + return this; + } + + /** + * Returns hash of least common ancestor between two revisions or null + * if common ancestor is not found + * @return see above + * @throws VcsException if some commands fail + */ + @Nullable + public abstract String call() throws VcsException; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseNoRevsets.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,54 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import com.intellij.openapi.util.Pair; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.util.graph.DAG; +import jetbrains.buildServer.util.graph.DAGs; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of merge-base for hg versions which don't have revsets + * @author dmitry.neverov + */ +public final class MergeBaseNoRevsets extends MergeBaseCommand { + + public MergeBaseNoRevsets(@NotNull HgRepo repo) { + super(repo); + } + + public String call() { + if (myRevision1.equals(myRevision2)) + return myRevision1; + try { + List<Pair<String, String>> edges = new ArrayList<Pair<String, String>>(); + fillEdges(edges, getRevisionsReachableFrom(myRevision1)); + fillEdges(edges, getRevisionsReachableFrom(myRevision2)); + DAG<String> dag = DAGs.createFromEdges(edges); + List<String> commonAncestors = dag.getCommonAncestors(new ChangeSetRevision(myRevision1).getId(), new ChangeSetRevision(myRevision2).getId()); + return commonAncestors.isEmpty() ? null : commonAncestors.get(0); + } catch (VcsException e) { + return null; + } + } + + private List<ChangeSet> getRevisionsReachableFrom(@NotNull final String revision) throws VcsException { + return myRepo.log() + .fromRevision(revision) + .toRevision("0") + .showCommitsFromAllBranches() + .call(); + } + + + private void fillEdges(List<Pair<String, String>> edges, List<ChangeSet> csets) { + for (ChangeSet cset : csets) { + for (ChangeSetRevision parent : cset.getParents()) { + edges.add(Pair.create(cset.getId(), parent.getId())); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-server/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/MergeBaseWithRevsets.java Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,31 @@ +package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; + +import jetbrains.buildServer.buildTriggers.vcs.mercurial.HgRepo; +import jetbrains.buildServer.vcs.VcsException; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Implementation of merge-base using hg revsets + * @author dmitry.neverov + */ +public final class MergeBaseWithRevsets extends MergeBaseCommand { + + public MergeBaseWithRevsets(@NotNull HgRepo repo) { + super(repo); + } + + public String call() throws VcsException { + try { + List<ChangeSet> csets = myRepo.log() + .withRevsets("ancestor(" + new ChangeSetRevision(myRevision1).getId() + ", " + new ChangeSetRevision(myRevision2).getId() + ")") + .showCommitsFromAllBranches() + .dontCalculateParents() + .call(); + return csets.isEmpty() ? null : csets.get(0).getId(); + } catch (VcsException e) { + return null; + } + } +}
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -200,7 +200,7 @@ assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP))); } - public void new_repository_is_cloned_from_local_mirror() throws IOException, VcsException { + private void new_repository_is_cloned_from_local_mirror() throws IOException, VcsException { VcsRoot root = createVcsRoot(simpleRepo()); File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true); File mirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0); @@ -209,7 +209,7 @@ assertTrue(hgrcContent.contains("default = " + mirrorDir.getCanonicalPath())); } - public void repository_cloned_from_remote_start_cloning_from_local_mirror() throws IOException, VcsException { + private void repository_cloned_from_remote_start_cloning_from_local_mirror() throws IOException, VcsException { VcsRoot root = createVcsRoot(simpleRepo()); //clone from remote repository File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null)); @@ -222,7 +222,7 @@ assertTrue(hgrcContent2.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror } - public void repository_cloned_from_local_mirror_start_cloning_from_remote() throws IOException, VcsException { + private void repository_cloned_from_local_mirror_start_cloning_from_remote() throws IOException, VcsException { VcsRoot root = createVcsRoot(simpleRepo()); //clone from remote repository File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true);
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutWithSubreposTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -6,6 +6,8 @@ import jetbrains.buildServer.agent.BuildAgentConfiguration; import jetbrains.buildServer.agent.BuildProgressLogger; import jetbrains.buildServer.agent.vcs.UpdateByIncludeRules2; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ConnectionRefusedException; import jetbrains.buildServer.log.Log4jFactory; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.CheckoutRules; @@ -22,7 +24,15 @@ import java.io.File; import java.io.IOException; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static java.util.Arrays.asList; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.getHgPath; +import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; /** * @author dmitry.neverov @@ -37,7 +47,9 @@ private BuildProgressLogger myLogger; private UpdateByIncludeRules2 myVcsSupport; private int myBuildCounter = 0; - private File myR1Dir; + private List<Process> myProcesses; + private File myDefaultWorkDir; + private MirrorManagerImpl myMirrorManager; static { Logger.setFactory(new Log4jFactory()); @@ -45,8 +57,10 @@ @BeforeMethod public void setUp() throws Exception { + myProcesses = new ArrayList<Process>(); myOriginalRepositoriesParentDir = myTempFiles.createTempDir(); - myWorkDir = new File(myOriginalRepositoriesParentDir, "agentWorkDir"); + myDefaultWorkDir = new File(myOriginalRepositoriesParentDir, "agentWorkDir"); + myWorkDir = myDefaultWorkDir; myContext = new Mockery(); final BuildAgentConfiguration agentConfig = myContext.mock(BuildAgentConfiguration.class); @@ -56,39 +70,85 @@ }}); final AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig); - myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, new AgentHgPathProvider(agentConfig), new MirrorManagerImpl(pluginConfig)); + myMirrorManager = new MirrorManagerImpl(pluginConfig); + myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig, new AgentHgPathProvider(agentConfig), myMirrorManager); myLogger = myContext.mock(BuildProgressLogger.class); myContext.checking(new Expectations() {{ allowing(myLogger).message(with(any(String.class))); allowing(myLogger).warning(with(any(String.class))); }}); - - myR1Dir = copy(new File("mercurial-tests/testData/subrepos/r1")); - copy(new File("mercurial-tests/testData/subrepos/r2")); - copy(new File("mercurial-tests/testData/subrepos/r3")); } @AfterMethod public void tearDown() { myTempFiles.cleanup(); + for (Process p : myProcesses) { + p.destroy(); + } } public void subrepository_url_changed() throws Exception { - VcsRootImpl root = new VcsRootBuilder() - .withUrl(myR1Dir.getAbsolutePath()) - .build(); + File myR1Dir = copy(new File("mercurial-tests/testData/subrepos/r1")); + copy(new File("mercurial-tests/testData/subrepos/r2")); + copy(new File("mercurial-tests/testData/subrepos/r3")); + VcsRootImpl root = vcsRoot().withUrl(myR1Dir.getAbsolutePath()).build(); doUpdate(root, "34017377d9c3"); doUpdate(root, "d350e7209906"); } + public void should_support_local_mirrors_for_subrepos() throws Exception { + File r1 = copy(new File("mercurial-tests/testData/subrepos/http_r1")); + File r2 = copy(new File("mercurial-tests/testData/subrepos/http_r2")); + File r3 = copy(new File("mercurial-tests/testData/subrepos/http_r3")); + Process server1 = serve(r1, 8001); + Process server2 = serve(r2, 8002); + Process server3 = serve(r3, 8003); + myProcesses.addAll(asList(server1, server2, server3)); + + final String url1 = "http://localhost:8001"; + final String url2 = "http://localhost:8002"; + final String url3 = "http://localhost:8003"; + VcsRoot root1 = vcsRoot().withUrl(url1).build(); + VcsRoot root3 = vcsRoot().withUrl(url3).build(); + + myWorkDir = new File(myDefaultWorkDir, "1"); + doUpdate(root1, "3d6694af00e4", true); + server1.destroy(); + + HgRepo mirror1 = new HgRepo(myMirrorManager.getMirrorDir(url1), getHgPath(), new AuthSettings()); + assertTrue("R1 mirror not updated to the latest revision", mirror1.containsRevision("3d6694af00e4")); + + try { + myWorkDir = new File(myDefaultWorkDir, "3"); + doUpdate(root3, "e1dc5eeb1bec", true); + doUpdate(root3, "999fb1eb9735", true); + } catch (ConnectionRefusedException e) { + fail("Contact remote repository when up-to-date subrepo local mirror exists"); + } + + HgRepo mirror2 = new HgRepo(myMirrorManager.getMirrorDir(url2), getHgPath(), new AuthSettings()); + assertTrue("R2 mirror not updated to the latest revision", mirror2.containsRevision("7de2f844e1a2")); + } + + private Process serve(@NotNull File repo, int port) throws IOException { + return new ProcessBuilder(getHgPath(), "serve", "-a", "localhost", "-p", String.valueOf(port)).directory(repo).start(); + } + + private void doUpdate(final VcsRoot vcsRoot, final String toVersion) throws VcsException { + doUpdate(vcsRoot, toVersion, false); + } + + private void doUpdate(final VcsRoot vcsRoot, final String toVersion, final boolean useLocalMirrors) throws VcsException { final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++); myContext.checking(new Expectations() {{ allowing(build).getBuildLogger(); will(returnValue(myLogger)); - allowing(build).getSharedConfigParameters(); will(returnValue(Collections.emptyMap())); + allowing(build).getSharedConfigParameters(); will(returnValue(new HashMap<String, String>() {{ + put("teamcity.hg.use.local.mirrors", useLocalMirrors ? "true" : "false"); + }})); }}); myVcsSupport.getUpdater(vcsRoot, CheckoutRules.DEFAULT, toVersion, myWorkDir, build, false).process(IncludeRule.createDefaultInstance(), myWorkDir); } @@ -103,4 +163,6 @@ } return copyDir; } + + }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersionTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgVersionTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,6 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ParseHgVersionException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.ParseHgVersionException; import junit.framework.TestCase; import org.jetbrains.annotations.NotNull; import org.testng.annotations.Test;
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -193,7 +193,7 @@ moveDirWithContent(new File(r1, "hg"), new File(r1, ".hg")); moveDirWithContent(new File(r3, "hg"), new File(r3, ".hg")); - VcsRootImpl root = createVcsRoot(r1.getAbsolutePath()); + VcsRootImpl root = vcsRoot().withUrl(r1.getAbsolutePath()).build(); setName("clean_patch_with_subrepositories"); checkPatchResult(buildPatch(root, null, "3:d350e7209906", CheckoutRules.DEFAULT).toByteArray());
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/UnrelatedResitoriesTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/UnrelatedResitoriesTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,8 +1,8 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial; +import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.TempFiles; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings; -import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.UnknownRevisionException; +import jetbrains.buildServer.log.Log4jFactory; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.CheckoutRules; import jetbrains.buildServer.vcs.VcsException; @@ -34,6 +34,10 @@ private Mockery myContext; private ServerPluginConfig myPluginConfig; + static { + Logger.setFactory(new Log4jFactory()); + } + @BeforeMethod public void setUp() throws Exception { myContext = new Mockery(); @@ -64,14 +68,14 @@ public void should_return_no_changes_when_fromRevision_is_from_unrelated_repository() throws Exception { - final CommandFactory factory = myContext.mock(CommandFactory.class); - final CollectChangesCommand commandExecutedWithException = myContext.mock(CollectChangesCommand.class); - myVcs = createVcs(factory); +// final CommandFactory factory = myContext.mock(CommandFactory.class); +// final CollectChangesCommand commandExecutedWithException = myContext.mock(CollectChangesCommand.class); + myVcs = createVcs(); myContext.checking(new Expectations(){{ - allowing(factory).getCollectChangesCommand(with(any(Settings.class)), with(any(File.class))); - will(returnValue(commandExecutedWithException)); - allowing(commandExecutedWithException).execute(with(any(String.class)), with(any(String.class))); - will(throwException(new UnknownRevisionException("1234"))); +// allowing(factory).getCollectChangesCommand(with(any(Settings.class)), with(any(File.class))); +// will(returnValue(commandExecutedWithException)); +// allowing(commandExecutedWithException).call(with(any(String.class)), with(any(String.class))); +// will(throwException(new UnknownRevisionException("1234"))); }}); String currentVersionOfOldRepo = syncRepository(); @@ -98,7 +102,7 @@ return Util.createMercurialServerSupport(myContext, myPluginConfig); } - private MercurialVcsSupport createVcs(@NotNull final CommandFactory factory) throws IOException { - return Util.createMercurialServerSupport(myContext, myPluginConfig, factory); - } +// private MercurialVcsSupport createVcs(/*@NotNull final CommandFactory factory*/) throws IOException { +// return Util.createMercurialServerSupport(myContext, myPluginConfig, new CommandFactoryImpl(myPluginConfig)); +// } }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/Util.java Fri Mar 02 14:33:42 2012 +0400 @@ -32,11 +32,11 @@ public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, ServerPluginConfig config) throws IOException { - return createMercurialServerSupport(context, config, new CommandFactoryImpl(config)); + return createMercurialServerSupport(context, config, new RepoFactory(config)); } - public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull CommandFactory commandFactory) throws IOException { + public static MercurialVcsSupport createMercurialServerSupport(@NotNull Mockery context, @NotNull ServerPluginConfig config, @NotNull RepoFactory commandFactory) throws IOException { VcsManager vcsManager = context.mock(VcsManager.class); final SBuildServer server = context.mock(SBuildServer.class); final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/BaseCommandTestCase.java Fri Mar 02 14:33:42 2012 +0400 @@ -77,7 +77,7 @@ settings.setCustomWorkingDir(workingDir); try { if (myCloneRequired) { - new CloneCommand(settings, workingDir).execute(); + new HgRepo(workingDir, settings.getHgCommandPath(), settings.getAuthSettings()).doClone().fromRepository(settings.getRepository()).call(); } return executor.execute(settings, workingDir);
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CatCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -1,5 +1,6 @@ package jetbrains.buildServer.buildTriggers.vcs.mercurial.command; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownFileException; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.vcs.VcsException; import org.jetbrains.annotations.NotNull; @@ -38,8 +39,7 @@ setRepository("mercurial-tests/testData/rep1", true); runCommand(new CommandExecutor<File>() { public File execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - CatCommand cat = new CatCommand(settings, workingDir); - return cat.execute(asList("/non/existing/path"), false); + return new CatCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).files("/non/existing/path").checkForFailure(false).call(); } }); } @@ -66,7 +66,7 @@ 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, workingDir); + CatCommand cat = new CatCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()); return cat.execute(paths); } });
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CloneCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -46,8 +46,7 @@ Settings settings = new Settings(new ServerHgPathProvider(config), root); settings.setCustomWorkingDir(workingDir); - CloneCommand clone = new CloneCommand(settings, workingDir); - clone.execute(); + new CloneCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).fromRepository(settings.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/CommandResultTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/CommandResultTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -3,6 +3,8 @@ import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.ExecResult; import jetbrains.buildServer.StreamGobbler; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnknownRevisionException; +import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.vcs.VcsException; import org.apache.log4j.Level; import org.jetbrains.annotations.NonNls;
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/IdentifyCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -37,10 +37,10 @@ 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 { - IdentifyCommand identify = new IdentifyCommand(settings, workingDir); - identify.setInLocalRepository(true); - identify.setChangeSet(cset); - identify.execute(); + new IdentifyCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) + .revision(cset) + .inLocalRepository() + .call(); return null; } });
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/LogCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -174,10 +174,12 @@ private List<ChangeSet> runLog(final String fromId, final String toId) throws IOException, VcsException { return runCommand(new CommandExecutor<List<ChangeSet>>() { public List<ChangeSet> execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { - LogCommand lc = new LogCommand(settings, workingDir, myTemplateFile); - lc.setFromRevId(fromId); - lc.setToRevId(toId); - return lc.execute(); + return new LogCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) + .inBranch(settings.getBranchName()) + .withTemplate(myTemplateFile) + .fromRevision(fromId) + .toRevision(toId) + .call(); } }); }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/PushCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -36,8 +36,7 @@ try { runCommand(new CommandExecutor<Boolean>() { public Boolean execute(@NotNull final Settings settings, @NotNull File workingDir) throws VcsException { - PushCommand cmd = new PushCommand(settings, workingDir); - cmd.execute(); + new PushCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()).toRepository(settings.getRepository()).call(); return null; } });
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/StatusCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -55,10 +55,10 @@ private List<ModifiedFile> runStatus(final String fromId, final String toId) throws IOException, VcsException { return runCommand(new CommandExecutor<List<ModifiedFile>>() { public List<ModifiedFile> execute(@NotNull final Settings settings, @NotNull final File workingDir) throws VcsException { - StatusCommand st = new StatusCommand(settings, workingDir); - st.setFromRevId(fromId); - st.setToRevId(toId); - return st.execute(); + return new StatusCommand(settings.getHgCommandPath(), workingDir, settings.getAuthSettings()) + .fromRevision(fromId) + .toRevision(toId) + .call(); } }); }
--- a/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommandTest.java Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/command/VersionCommandTest.java Fri Mar 02 14:33:42 2012 +0400 @@ -18,7 +18,7 @@ ServerPluginConfig config = new ServerPluginConfigBuilder().build(); Settings settings = new Settings(new ServerHgPathProvider(config), root); VersionCommand versionCommand = new VersionCommand(settings, new File("..")); - HgVersion version = versionCommand.execute(); + HgVersion version = versionCommand.call(); assertNotNull(version); }
--- a/mercurial-tests/testData/subrepos/README Thu Mar 01 20:16:58 2012 +0400 +++ b/mercurial-tests/testData/subrepos/README Fri Mar 02 14:33:42 2012 +0400 @@ -8,4 +8,23 @@ 0:916933c1dd8e Initial commit r3 history: -0:9e4a2fef1a1c Initial commit \ No newline at end of file +0:9e4a2fef1a1c Initial commit + + +http subrepos: + +http_r1: +2:3d6694af00e4 third +1:a2d737193093 second +0:2516e4a826e8 initial commit + +http_r2: +2:7de2f844e1a2 Register subrepo r1 -> r1:1 +1:f54386da1b42 add .hgsub +0:97bef7492664 initial + +http_r3: +3:999fb1eb9735 Update subrepos -> r1:2, r2:2 +2:e1dc5eeb1bec register subrepos -> r1:1, r2:1 +1:94b99ee983ed add .hgsub +0:44c53c0ea688 initial
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/branchheads.cache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +a2d73719309307517fd15eccb8afefb61c3c9af7 1 +a2d73719309307517fd15eccb8afefb61c3c9af7 default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/last-message.txt Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +third \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/requires Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,4 @@ +revlogv1 +store +fncache +dotencode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/store/fncache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,3 @@ +data/a.i +data/b.i +data/c.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/tags.cache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +2 3d6694af00e4ee8d8ea7924c38b58c40f08609d4 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/undo.branch Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r1/hg/undo.desc Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +2 +commit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/branchheads.cache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +f54386da1b42a9f8b1773aa26074d178f9afe28f 1 +f54386da1b42a9f8b1773aa26074d178f9afe28f default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/last-message.txt Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +Register subrepo r1 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/requires Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,4 @@ +revlogv1 +store +fncache +dotencode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/store/fncache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,3 @@ +data/a.i +data/.hgsub.i +data/.hgsubstate.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/tags.cache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +2 7de2f844e1a209e9f3fd0395465862fdd1361709 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/undo.branch Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +default \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r2/hg/undo.desc Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +2 +commit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r3/hg/branchheads.cache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,2 @@ +e1dc5eeb1bece84478e9c85aec0f784d43e4b310 2 +e1dc5eeb1bece84478e9c85aec0f784d43e4b310 default
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r3/hg/last-message.txt Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +Update subrepos \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r3/hg/requires Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,4 @@ +revlogv1 +store +fncache +dotencode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r3/hg/store/fncache Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,3 @@ +data/a.i +data/.hgsub.i +data/.hgsubstate.i
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial-tests/testData/subrepos/http_r3/hg/undo.branch Fri Mar 02 14:33:42 2012 +0400 @@ -0,0 +1,1 @@ +default \ No newline at end of file