Mercurial > hg > mercurial
view mercurial-agent/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialIncludeRuleUpdater.java @ 538:8468457fe4d3
Report subrepo changes - initial version
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Tue, 29 Jan 2013 20:53:19 +0400 |
parents | 1ca68585ffce |
children | 1e5b80e2c023 |
line wrap: on
line source
package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.agent.AgentRunningBuild; import jetbrains.buildServer.agent.BuildProgressLogger; import jetbrains.buildServer.agent.vcs.IncludeRuleUpdater; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.AuthSettings; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.HgVcsRoot; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.exception.UnrelatedRepositoryException; import jetbrains.buildServer.vcs.IncludeRule; import jetbrains.buildServer.vcs.VcsException; import jetbrains.buildServer.vcs.VcsRoot; import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import static com.intellij.openapi.util.io.FileUtil.delete; /** * @author dmitry.neverov */ public class MercurialIncludeRuleUpdater implements IncludeRuleUpdater { private final AgentPluginConfig myConfig; private final MirrorManager myMirrorManager; private final AgentRepoFactory myRepoFactory; private final HgVcsRoot myRoot; private final AuthSettings myAuthSettings; private final String myHgPath; private final String myToVersion; private final BuildProgressLogger myLogger; private final boolean myUseLocalMirrors; private int myPullTimeout; private final boolean myUseTraceback; public MercurialIncludeRuleUpdater(@NotNull AgentPluginConfig pluginConfig, @NotNull MirrorManager mirrorManager, @NotNull HgPathProvider hgPathProvider, @NotNull AgentRepoFactory repoFactory, @NotNull VcsRoot root, @NotNull String toVersion, @NotNull AgentRunningBuild build) { myConfig = pluginConfig; myMirrorManager = mirrorManager; myRepoFactory = repoFactory; myRoot = new HgVcsRoot(root); myAuthSettings = myRoot.getAuthSettings(); myHgPath = hgPathProvider.getHgPath(myRoot); myToVersion = toVersion; myLogger = build.getBuildLogger(); myUseLocalMirrors = myConfig.isUseLocalMirrors(build); myPullTimeout = myConfig.getPullTimeout(build); myUseTraceback = myConfig.runWithTraceback(build); } public void process(@NotNull IncludeRule rule, @NotNull File workingDir) throws VcsException { try { checkRuleIsValid(rule); if (myUseLocalMirrors) updateLocalMirror(myRoot.getRepository(), myToVersion); updateRepository(workingDir); updateWorkingDir(workingDir, myToVersion, myRoot.getRepository()); } catch (Exception e) { throwVcsException(e); } } public void dispose() throws VcsException { } private void updateLocalMirror(@NotNull String repositoryUrl, @NotNull String revision) throws VcsException, IOException { File mirrorDir = myMirrorManager.getMirrorDir(repositoryUrl); HgRepo mirrorRepo = myRepoFactory.create(mirrorDir, myHgPath, myAuthSettings); if (!mirrorRepo.isValidRepository()) { delete(mirrorDir); myLogger.message("Clone repository " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl) + " into local mirror " + mirrorRepo.path()); mirrorRepo.doClone().fromRepository(repositoryUrl) .withTraceback(myUseTraceback) .setUpdateWorkingDir(false) .setUsePullProtocol(false) .useUncompressedTransfer(myRoot.isUncompressedTransfer()) .call(); myLogger.message("Clone successfully finished"); } else { 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 { myLogger.message("Start pulling changes from " + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); mirrorRepo.pull().fromRepository(repositoryUrl) .withTraceback(myUseTraceback) .withTimeout(myPullTimeout) .call(); myLogger.message("Local mirror changes successfully pulled"); } } } private void updateRepository(@NotNull File workingDir) throws VcsException, IOException { String repositoryUrl = getDefaultPullUrl(myRoot, myUseLocalMirrors); HgRepo repo = myRepoFactory.create(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) .withTraceback(myUseTraceback) .setUsePullProtocol(false) .setUpdateWorkingDir(false) .useUncompressedTransfer(!myUseLocalMirrors && myRoot.isUncompressedTransfer()) .call(); repo.setDefaultPath(myRoot.getRepository()); myLogger.message("Repository successfully cloned"); } else { if (!repo.isValidRepository()) repo.init().call(); repo.setDefaultPath(myRoot.getRepository()); if (repo.containsRevision(myToVersion)) { myLogger.message("Repository already contains revision " + myToVersion); } else { myLogger.message("Start pulling changes from " + (myUseLocalMirrors ? "local mirror " : "") + myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl)); try { repo.pull().fromRepository(repositoryUrl) .withTraceback(myUseTraceback) .withTimeout(myPullTimeout) .call(); } catch (UnrelatedRepositoryException e) { throw new UnrelatedRepositoryException(myAuthSettings.getRepositoryUrlWithHiddenPassword(repositoryUrl), workingDir); } myLogger.message("Changes successfully pulled"); } } } private void updateWorkingDir(@NotNull File workingDir, @NotNull String toVersion, @NotNull String repositoryUrl) throws VcsException, IOException { HgRepo repo = myRepoFactory.create(workingDir, myHgPath, myAuthSettings); updateSubrepositories(repo, toVersion, repositoryUrl); doUpdateWorkingDir(repo, toVersion); } 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(); SubRepo subrepoConfig = entry.getValue(); myLogger.message("Process subrepoConfig at path " + path + " (url: " + subrepoConfig.url() + ")"); SubRepo workingDirSubrepo = workingDirSubrepos.get(path); if (workingDirSubrepo != null && subrepoConfig.hasDifferentUrlThan(workingDirSubrepo)) { myLogger.message("The url of subrepoConfig was changed between revisions " + workingDirRevision + " and " + toVersion + " , delete the subrepoConfig"); delete(subrepoConfig.dir()); } HgRepo subrepository = myRepoFactory.create(subrepoConfig.dir(), myHgPath, myAuthSettings); String subrepoUrl; try { subrepoUrl = subrepoConfig.resolveUrl(parentRepositoryUrl); if (myUseLocalMirrors && subrepoConfig.vcsType() == SubRepo.VcsType.hg && !SubRepo.isRelativeUrl(subrepoUrl)) syncSubrepo(subrepository, subrepoUrl, subrepoConfig.revision()); } catch (URISyntaxException e) { myLogger.warning("Failed to resolve subrepo url '" + subrepoConfig.url() + "': " + e.getMessage()); subrepoUrl = subrepoConfig.url(); } updateSubrepositories(subrepository, subrepoConfig.revision(), subrepoUrl); } } private void syncSubrepo(@NotNull HgRepo subrepository, @NotNull String url, @NotNull String revision) throws VcsException, IOException { if (!subrepository.isValidRepository() || !subrepository.containsRevision(revision)) { updateLocalMirror(url, revision); File mirrorDir = myMirrorManager.getMirrorDir(url); if (subrepository.isValidRepository()) { myLogger.message("Pull from local mirror"); subrepository.pull().fromRepository(mirrorDir) .withTraceback(myUseTraceback) .withTimeout(myPullTimeout) .call(); myLogger.message("done"); } else { myLogger.message("Clone subrepo from local mirror"); subrepository.doClone().fromRepository(mirrorDir) .withTraceback(myUseTraceback) .setUpdateWorkingDir(false) .setUsePullProtocol(false) .call(); subrepository.setDefaultPath(url); myLogger.message("done"); } } } private void doUpdateWorkingDir(@NotNull HgRepo repo, @NotNull String revision) throws VcsException { myLogger.message("Updating working dir " + repo.path() + " to revision " + revision); repo.update().withTraceback(myUseTraceback).toRevision(revision).call(); myLogger.message("Working dir updated"); } private String getDefaultPullUrl(HgVcsRoot root, boolean useLocalMirror) throws IOException { if (useLocalMirror) { File mirrorDir = myMirrorManager.getMirrorDir(root.getRepository()); return mirrorDir.getCanonicalPath(); } else { return root.getRepository(); } } private void checkRuleIsValid(IncludeRule includeRule) throws VcsException { if (includeRule.getTo() != null && includeRule.getTo().length() > 0) { if (!".".equals(includeRule.getFrom()) && includeRule.getFrom().length() != 0) throw new VcsException("Invalid include rule: " + includeRule.toString() + ", Mercurial plugin supports mapping of the form: +:.=>dir only."); } } private void throwVcsException(Exception e) throws VcsException { if (e instanceof VcsException) throw (VcsException) e; else throw new VcsException(e); } }