Mercurial > hg > mercurial
view mercurial-common/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/HgRepo.java @ 891:d1a5fc6c1d6e
Log agent-side checkout progress with blocks
author | Dmitry Neverov <dmitry.neverov@jetbrains.com> |
---|---|
date | Fri, 07 Nov 2014 14:55:14 +0100 |
parents | 6df89e185a3c |
children | 15fce0c26e18 |
line wrap: on
line source
/* * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.buildServer.buildTriggers.vcs.mercurial; import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*; import jetbrains.buildServer.log.Loggers; 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.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static jetbrains.buildServer.buildTriggers.vcs.mercurial.HgFileUtil.deleteDir; import static jetbrains.buildServer.util.FileUtil.isEmptyDir; /** * @author dmitry.neverov */ public class HgRepo { protected final CommandSettingsFactory myCommandSettingsFactory; protected final File myWorkingDir; protected final String myHgPath; protected final AuthSettings myAuthSettings; protected final Map<String, Map<String, SubRepo>> mySubreposCache = new HashMap<String, Map<String, SubRepo>>(); public HgRepo(@NotNull CommandSettingsFactory commandSettingsFactory, @NotNull File workingDir, @NotNull String hgPath, @NotNull AuthSettings authSettings) { myCommandSettingsFactory = commandSettingsFactory; myWorkingDir = workingDir; myHgPath = hgPath; myAuthSettings = authSettings; } public PullCommand pull() { return new PullCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public PushCommand push() { return new PushCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public CloneCommand doClone() { return new CloneCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public IdentifyCommand id() { return new IdentifyCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public Init init() { return new Init(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public LogCommand log() { return new LogCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } @NotNull public CommitsAndMountPointsCommand logSubstates() throws VcsException { return new CommitsAndMountPointsCommand(this, myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public UpdateCommand update() { return new UpdateCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public BranchesCommand branches() { return new BranchesCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public BookmarksCommand bookmarks() { return new BookmarksCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public UpdateBookmarkCommand updateBookmark() { return new UpdateBookmarkCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public TagsCommand tags() { return new TagsCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public Map<String, String> getBranchRevisions(boolean includeBookmarks, boolean includeTags) throws VcsException { Map<String, String> revisions = new HashMap<String, String>(); if (includeTags) revisions.putAll(tags().call()); if (includeBookmarks && version().call().isEqualsOrGreaterThan(BookmarksCommand.REQUIRED_HG_VERSION)) revisions.putAll(bookmarks().call()); revisions.putAll(branches().call()); return revisions; } public StatusCommand status() { return new StatusCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public TagCommand tag() { return new TagCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public CatCommand cat() { return new CatCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public ArchiveCommand archive() { return new ArchiveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, myAuthSettings); } public VersionCommand version() { return new VersionCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public ParentsCommand parents() { return new ParentsCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public MergeCommand merge() { return new MergeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public ResolveCommand resolve() { return new ResolveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public CommitCommand commit() { return new CommitCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public AddRemoveCommand addRemove() { return new AddRemoveCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } public String path() { return myWorkingDir.getAbsolutePath(); } public File getWorkingDir() { return myWorkingDir; } public boolean isEmpty() { return isEmptyDir(myWorkingDir); } public boolean isBookmark(@NotNull String branch) throws VcsException { if (branches().call().keySet().contains(branch)) return false; return bookmarks().call().keySet().contains(branch); } public void resetBookmarks() { File dotHg = new File(getWorkingDir(), ".hg"); FileUtil.delete(new File(dotHg, "bookmarks")); FileUtil.delete(new File(dotHg, "bookmarks.current")); } public PurgeCommand purge() { return new PurgeCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir); } @NotNull public CommandResult runCommand(@NotNull String command, @NotNull String... args) throws VcsException { return new FreeStyleCommand(myCommandSettingsFactory.create(), myHgPath, myWorkingDir, command, args).call(); } public String getHgPath() { return myHgPath; } @NotNull public List<String> listFiles(@NotNull String revision) throws VcsException { List<FileStatus> fileStatuses = status() .fromRevision(revision) .toRevision(revision) .hideStatus() .showAllFiles() .call(); List<String> files = new ArrayList<String>(fileStatuses.size()); for (FileStatus fileStatus : fileStatuses) files.add(fileStatus.getPath()); return files; } @NotNull public String getWorkingDirRevision() throws VcsException { List<String> workingDirParents = parents().call(); if (workingDirParents.isEmpty()) return LogCommand.ZERO_PARENT_SHORT_ID;//'hg id' shows zeroid when a working dir has no parents //if a working dir is in an uncommitted merge state, choose the first parent return workingDirParents.get(0); } 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) throws VcsException { try { File hgrc = new File(new File(myWorkingDir, ".hg"), "hgrc"); String content = "%include " + Constants.TEAMCITY_HG_CONFIG_FILE_NAME + "\n\n[paths]\ndefault = " + defaultPath; FileUtil.writeFileAndReportErrors(hgrc, content); } catch (IOException e) { throw new VcsException(e); } } public void setTeamCityConfig(@NotNull String configContent) throws VcsException { try { File teamcityConfig = new File(new File(myWorkingDir, ".hg"), Constants.TEAMCITY_HG_CONFIG_FILE_NAME); FileUtil.writeFileAndReportErrors(teamcityConfig, configContent); } catch (IOException e) { throw new VcsException(e); } } 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 List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String revision) throws VcsException { if (containsSubrepoConfigChange(revision)) { List<String> parents = parents().ofRevision(revision).call(); return getSubrepoConfigChanges(revision, parents); } return emptyList(); } public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull ChangeSet cset) { if (containsSubrepoConfigChange(cset)) { List<String> parents = new ArrayList<String>(); for (ChangeSetRevision p : cset.getParents()) { parents.add(p.getId()); } return getSubrepoConfigChanges(cset.getId(), parents); } return emptyList(); } public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String fromRevision, @NotNull String toRevision) { return getSubrepoConfigChanges(toRevision, asList(fromRevision)); } public List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String revision, @NotNull List<String> parentRevisions) { Map<String, SubRepo> curSubrepos = getSubrepositories(revision); List<Map<String, SubRepo>> prevSubrepos = new ArrayList<Map<String, SubRepo>>(); for (String parentRevision : parentRevisions) { prevSubrepos.add(getSubrepositories(parentRevision)); } return getSubrepoConfigChanges(revision, prevSubrepos, curSubrepos); } private List<HgSubrepoConfigChange> getSubrepoConfigChanges(@NotNull String mainRepoRevision, @NotNull List<Map<String, SubRepo>> prevSubrepos, @NotNull Map<String, SubRepo> curSubrepos) { List<HgSubrepoConfigChange> configChanges = new ArrayList<HgSubrepoConfigChange>(); for (Map.Entry<String, SubRepo> e : curSubrepos.entrySet()) { String path = e.getKey(); SubRepo curSubrepo = e.getValue(); List<SubRepo> prevs = new ArrayList<SubRepo>(); for (Map<String, SubRepo> prev : prevSubrepos) { SubRepo prevSubrepo = prev.remove(path); if (prevSubrepo == null) //no subrepo at this path in previous revision continue; if (prevSubrepo.equals(curSubrepo)) //subrepo configuration doesn't change since previous revision continue; prevs.add(prevSubrepo); } configChanges.add(new HgSubrepoConfigChange(mainRepoRevision, e.getKey(), prevs, curSubrepo)); } for (Map<String, SubRepo> prev : prevSubrepos) { for (Map.Entry<String, SubRepo> e : prev.entrySet()) { configChanges.add(new HgSubrepoConfigChange(mainRepoRevision, e.getKey(), e.getValue(), null)); } } return configChanges; } private boolean containsSubrepoConfigChange(@NotNull ChangeSet cset) { for (FileStatus f : cset.getModifiedFiles()) { if (containsSubrepoConfigChange(f)) return true; } return false; } private boolean containsSubrepoConfigChange(@NotNull String revision) throws VcsException { List<FileStatus> changedFiles = status() .fromRevision(revision) .toRevision(revision) .showAllFiles() .call(); for (FileStatus f : changedFiles) { if (containsSubrepoConfigChange(f)) return true; } return false; } private boolean containsSubrepoConfigChange(@NotNull FileStatus f) { return f.getPath().equals(".hgsubstate"); } //path->subrepo @NotNull public Map<String, SubRepo> getSubrepositories(@NotNull final ChangeSet cset) { final String revId = cset.getId(); Map<String, SubRepo> subrepos = mySubreposCache.get(revId); if (subrepos != null) { return new HashMap<String, SubRepo>(subrepos); } File catDir = null; final CatCommand cc = cat().setRevId(revId).files(asList(".hgsub", ".hgsubstate")).checkForFailure(false); try { catDir = cc.call(); subrepos = HgSubs.readSubrepositories(new File(catDir, ".hgsub"), new File(catDir, ".hgsubstate")); mySubreposCache.put(revId, subrepos); return new HashMap<String, SubRepo>(subrepos); } catch (VcsException e) { return emptyMap(); } finally { deleteDir(catDir, Loggers.VCS); } } @Override public String toString() { return myWorkingDir.getAbsolutePath(); } @NotNull public static String shortId(@NotNull final String s) { if (s.length() > 12) return s.substring(0, 12); return s; } }