mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[log] Load refs and commits synchronously, speed-up git log startup
=> IDEA-126380 avoid diverging of log & refs if they are queried by
separate commands, and the repository changes between these requests.
=> IDEA-117553 initial startup loading becomes faster.
* Tell plugins to return refs, users and commits altogether, they
should worry about synchronousness by themselves.
* For Git:
+ call log --decorate=full on refresh, thus getting all
references which are attached to requested commits.
+ Add all branches there by reading them from branch files.
+ Ignore other tags on startup.
+ On refresh check new tags ('git tag' is fast), and load more commits
if needed.
+ Ignore rare case if some old tag pointers moved.
+ on startup don't use --decorate for speed-up, instead just read
branches manually. Some validation will follow.
* Provide trivial implementation for hg.
This commit is contained in:
@@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides the information needed to build the VCS log, such as the list of most recent commits with their parents.
|
||||
@@ -17,20 +18,26 @@ import java.util.List;
|
||||
public interface VcsLogProvider {
|
||||
|
||||
/**
|
||||
* Reads the most recent correctly ordered commits from the log. <br/>
|
||||
* Commits should be at least topologically ordered, better considering commit time as well. <br/>
|
||||
* Commits will be shown in the log in this order.
|
||||
* @param requirements some limitations on commit data that should be returned.
|
||||
* Reads the most recent commits from the log together with all repository references.<br/>
|
||||
* Commits should be at least topologically ordered, better considering commit time as well: they will be shown in the log in this order.
|
||||
* <p/>
|
||||
* This method is called both on the startup and on refresh.
|
||||
*
|
||||
* @param requirements some limitations on commit data that should be returned, e.g. the number of commits.
|
||||
* @return given amount of ordered commits and <b>all</b> references in the repository.
|
||||
*/
|
||||
@NotNull
|
||||
List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException;
|
||||
DetailedLogData readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException;
|
||||
|
||||
/**
|
||||
* <p>Reads the whole history, but only hashes & parents.</p>
|
||||
* <p>Also reports authors/committers of this repository to the given user registry.</p>
|
||||
* Reads the whole history.
|
||||
* <p/>
|
||||
* Reports commits to the consumer to avoid creation & even temporary storage of a too large commits collection.
|
||||
*
|
||||
* @return all references and all authors in the repository.
|
||||
*/
|
||||
void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
|
||||
@NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException;
|
||||
@NotNull
|
||||
LogData readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException;
|
||||
|
||||
/**
|
||||
* Reads those details of the given commits, which are necessary to be shown in the log table.
|
||||
@@ -44,12 +51,6 @@ public interface VcsLogProvider {
|
||||
@NotNull
|
||||
List<? extends VcsFullCommitDetails> readFullDetails(@NotNull VirtualFile root, @NotNull List<String> hashes) throws VcsException;
|
||||
|
||||
/**
|
||||
* Read all references (branches, tags, etc.) for the given roots.
|
||||
*/
|
||||
@NotNull
|
||||
Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException;
|
||||
|
||||
/**
|
||||
* <p>Returns the VCS which is supported by this provider.</p>
|
||||
* <p>If there will be several VcsLogProviders which support the same VCS, only one will be chosen. It is undefined, which one.</p>
|
||||
@@ -106,4 +107,20 @@ public interface VcsLogProvider {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Container for references and users.
|
||||
*/
|
||||
interface LogData {
|
||||
@NotNull Set<VcsRef> getRefs();
|
||||
@NotNull Set<VcsUser> getUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Container for the ordered list of commits together with their details, and references.
|
||||
*/
|
||||
interface DetailedLogData {
|
||||
@NotNull List<VcsCommitMetadata> getCommits();
|
||||
@NotNull Set<VcsRef> getRefs();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.vcs.log;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -24,7 +23,7 @@ import static com.intellij.vcs.log.VcsLogProvider.Requirements;
|
||||
|
||||
/**
|
||||
* Extension of the standard {@link Requirements} which contains data used by some VCSs. <br/>
|
||||
* An object of this object is actually passed to {@link VcsLogProvider#readFirstBlock(VirtualFile, Requirements)}, but VcsLogProviders
|
||||
* An object of this object is actually passed to {@link #readFirstBlock(com.intellij.util.Consumer}, but VcsLogProviders
|
||||
* which need this additional information must check for instanceof before casting & be able to fallback.
|
||||
*/
|
||||
public interface VcsLogProviderRequirementsEx extends Requirements {
|
||||
@@ -41,10 +40,4 @@ public interface VcsLogProviderRequirementsEx extends Requirements {
|
||||
@NotNull
|
||||
Set<VcsRef> getPreviousRefs();
|
||||
|
||||
/**
|
||||
* Returns current refs.
|
||||
*/
|
||||
@NotNull
|
||||
Set<VcsRef> getCurrentRefs();
|
||||
|
||||
}
|
||||
|
||||
@@ -26,16 +26,14 @@ public class DataPack implements VcsLogDataPack {
|
||||
private boolean myFull;
|
||||
|
||||
@NotNull
|
||||
static DataPack build(@NotNull List<? extends GraphCommit<Integer>> commits, @NotNull RefsModel refsModel,
|
||||
@NotNull NotNullFunction<Hash, Integer> indexGetter, @NotNull NotNullFunction<Integer, Hash> hashGetter,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers, boolean full) {
|
||||
return build(buildPermanentGraph(commits, refsModel, indexGetter, hashGetter, providers), providers, refsModel, full);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static DataPack build(@NotNull PermanentGraph<Integer> permanentGraph, @NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull RefsModel refsModel, boolean full) {
|
||||
return new DataPack(refsModel, permanentGraph, createGraphFacade(permanentGraph), providers, full);
|
||||
static DataPack build(@NotNull List<? extends GraphCommit<Integer>> commits,
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> refs,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull VcsLogHashMap hashMap,
|
||||
boolean full) {
|
||||
RefsModel refsModel = new RefsModel(refs, hashMap.asIndexGetter());
|
||||
PermanentGraph<Integer> graph = buildPermanentGraph(commits, refsModel, hashMap.asIndexGetter(), hashMap.asHashGetter(), providers);
|
||||
return new DataPack(refsModel, graph, createGraphFacade(graph), providers, full);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -57,11 +55,11 @@ public class DataPack implements VcsLogDataPack {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static PermanentGraph<Integer> buildPermanentGraph(@NotNull List<? extends GraphCommit<Integer>> commits,
|
||||
@NotNull RefsModel refsModel,
|
||||
@NotNull NotNullFunction<Hash, Integer> indexGetter,
|
||||
@NotNull NotNullFunction<Integer, Hash> hashGetter,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers) {
|
||||
private static PermanentGraph<Integer> buildPermanentGraph(@NotNull List<? extends GraphCommit<Integer>> commits,
|
||||
@NotNull RefsModel refsModel,
|
||||
@NotNull NotNullFunction<Hash, Integer> indexGetter,
|
||||
@NotNull NotNullFunction<Integer, Hash> hashGetter,
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers) {
|
||||
if (commits.isEmpty()) {
|
||||
return EmptyPermanentGraph.getInstance();
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ import com.intellij.vcs.log.VcsLogProvider;
|
||||
import com.intellij.vcs.log.VcsRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class EmptyDataPack {
|
||||
|
||||
@NotNull
|
||||
public static DataPack getInstance() {
|
||||
RefsModel emptyModel = new RefsModel(Collections.<VirtualFile, Collection<VcsRef>>emptyMap(), new ConstantFunction<Hash, Integer>(0));
|
||||
RefsModel emptyModel = new RefsModel(Collections.<VirtualFile, Set<VcsRef>>emptyMap(), new ConstantFunction<Hash, Integer>(0));
|
||||
return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), new EmptyGraphFacade(), Collections.<VirtualFile, VcsLogProvider>emptyMap(), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ import java.util.*;
|
||||
|
||||
public class RefsModel implements VcsLogRefs {
|
||||
|
||||
@NotNull private final Map<VirtualFile, Collection<VcsRef>> myRefs;
|
||||
@NotNull private final Map<VirtualFile, Set<VcsRef>> myRefs;
|
||||
@NotNull private final NotNullFunction<Hash, Integer> myIndexGetter;
|
||||
|
||||
@NotNull private final Collection<VcsRef> myBranches;
|
||||
@NotNull private final MultiMap<Hash, VcsRef> myRefsToHashes;
|
||||
@NotNull private final TIntObjectHashMap<SmartList<VcsRef>> myRefsToIndices;
|
||||
|
||||
public RefsModel(@NotNull Map<VirtualFile, Collection<VcsRef>> refsByRoot, @NotNull NotNullFunction<Hash, Integer> indexGetter) {
|
||||
public RefsModel(@NotNull Map<VirtualFile, Set<VcsRef>> refsByRoot, @NotNull NotNullFunction<Hash, Integer> indexGetter) {
|
||||
myRefs = refsByRoot;
|
||||
myIndexGetter = indexGetter;
|
||||
|
||||
@@ -85,7 +85,7 @@ public class RefsModel implements VcsLogRefs {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<VirtualFile, Collection<VcsRef>> getAllRefsByRoot() {
|
||||
public Map<VirtualFile, Set<VcsRef>> getAllRefsByRoot() {
|
||||
return myRefs;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcs.log.*;
|
||||
@@ -62,7 +63,8 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
@NotNull final VcsUserRegistryImpl userRegistry,
|
||||
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
|
||||
@NotNull final Consumer<DataPack> dataPackUpdateHandler,
|
||||
@NotNull Consumer<Exception> exceptionHandler, int recentCommitsCount) {
|
||||
@NotNull Consumer<Exception> exceptionHandler,
|
||||
int recentCommitsCount) {
|
||||
myProject = project;
|
||||
myHashMap = hashMap;
|
||||
myProviders = providers;
|
||||
@@ -95,16 +97,11 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
@Override
|
||||
public DataPack readFirstBlock() {
|
||||
try {
|
||||
Map<VirtualFile, Collection<VcsRef>> refs = loadRefsFromVcs(myProviders);
|
||||
Set<VirtualFile> roots = myProviders.keySet();
|
||||
Map<VirtualFile, VcsLogProvider.Requirements> requirements = prepareSimpleRequirements(roots, myRecentCommitCount);
|
||||
Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = loadRecentCommitsFromVcs(myProviders, requirements,
|
||||
myUserRegistry, myTopCommitsDetailsCache,
|
||||
myHashMap);
|
||||
List<? extends GraphCommit<Integer>> compoundLog = compound(commits.values());
|
||||
DataPack dataPack = DataPack.build(compoundLog, new RefsModel(refs, myHashMap.asIndexGetter()),
|
||||
myHashMap.asIndexGetter(), myHashMap.asHashGetter(), myProviders, false);
|
||||
mySingleTaskController.request(RefreshRequest.RELOAD_ALL); // build/rebuild the full log in bg
|
||||
LogInfo data = loadRecentData(new CommitCountRequirements(myRecentCommitCount).asMap(myProviders.keySet()));
|
||||
Collection<List<GraphCommit<Integer>>> commits = data.getCommits();
|
||||
Map<VirtualFile, Set<VcsRef>> refs = data.getRefs();
|
||||
DataPack dataPack = DataPack.build(multiRepoJoin(commits), refs, myProviders, myHashMap, false);
|
||||
mySingleTaskController.request(RefreshRequest.RELOAD_ALL); // build/rebuild the full log in background
|
||||
return dataPack;
|
||||
}
|
||||
catch (VcsException e) {
|
||||
@@ -113,6 +110,36 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LogInfo loadRecentData(@NotNull final Map<VirtualFile, VcsLogProvider.Requirements> requirements) throws VcsException {
|
||||
final StopWatch sw = StopWatch.start("loading commits");
|
||||
final LogInfo logInfo = new LogInfo();
|
||||
new ProviderIterator() {
|
||||
@Override
|
||||
public void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
|
||||
VcsLogProvider.DetailedLogData data = provider.readFirstBlock(root, requirements.get(root));
|
||||
storeUsersAndDetails(data.getCommits());
|
||||
logInfo.put(root, compactCommits(data.getCommits()));
|
||||
logInfo.put(root, data.getRefs());
|
||||
sw.rootCompleted(root);
|
||||
}
|
||||
}.iterate(getProvidersForRoots(requirements.keySet()));
|
||||
myUserRegistry.flush();
|
||||
sw.report();
|
||||
return logInfo;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<VirtualFile, VcsLogProvider> getProvidersForRoots(@NotNull Set<VirtualFile> roots) {
|
||||
return ContainerUtil.map2Map(roots,
|
||||
new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider>>() {
|
||||
@Override
|
||||
public Pair<VirtualFile, VcsLogProvider> fun(VirtualFile root) {
|
||||
return Pair.create(root, myProviders.get(root));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(@NotNull Collection<VirtualFile> rootsToRefresh) {
|
||||
if (!rootsToRefresh.isEmpty()) {
|
||||
@@ -121,101 +148,39 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<VirtualFile, VcsLogProvider.Requirements> prepareSimpleRequirements(@NotNull Collection<VirtualFile> roots,
|
||||
final int commitCount) {
|
||||
final VcsLogProvider.Requirements requirements = new VcsLogProvider.Requirements() {
|
||||
@Override
|
||||
public int getCommitCount() {
|
||||
return commitCount;
|
||||
}
|
||||
};
|
||||
return ContainerUtil.map2Map(roots, new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider.Requirements>>() {
|
||||
@Override
|
||||
public Pair<VirtualFile, VcsLogProvider.Requirements> fun(VirtualFile file) {
|
||||
return Pair.create(file, requirements);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<VirtualFile, Collection<VcsRef>> loadRefsFromVcs(@NotNull Map<VirtualFile, VcsLogProvider> providers)
|
||||
throws VcsException {
|
||||
final StopWatch sw = StopWatch.start("loading refs");
|
||||
final Map<VirtualFile, Collection<VcsRef>> refs = ContainerUtil.newHashMap();
|
||||
new ProviderIterator() {
|
||||
@Override
|
||||
void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
|
||||
refs.put(root, provider.readAllRefs(root));
|
||||
sw.rootCompleted(root);
|
||||
}
|
||||
}.iterate(providers);
|
||||
sw.report();
|
||||
return refs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<VirtualFile, List<? extends GraphCommit<Integer>>> loadRecentCommitsFromVcs(
|
||||
@NotNull Map<VirtualFile, VcsLogProvider> providers,
|
||||
@NotNull final Map<VirtualFile, VcsLogProvider.Requirements> requirements,
|
||||
@NotNull final VcsUserRegistryImpl userRegistry,
|
||||
@NotNull final Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
|
||||
@NotNull final VcsLogHashMap hashMap) throws VcsException
|
||||
{
|
||||
final StopWatch sw = StopWatch.start("loading commits");
|
||||
final Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = ContainerUtil.newHashMap();
|
||||
new ProviderIterator() {
|
||||
@Override
|
||||
public void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
|
||||
List<? extends VcsCommitMetadata> metadatas = provider.readFirstBlock(root, requirements.get(root));
|
||||
storeUsersAndDetails(metadatas, userRegistry, topCommitsDetailsCache);
|
||||
commits.put(root, compactCommits(metadatas, hashMap));
|
||||
sw.rootCompleted(root);
|
||||
}
|
||||
}.iterate(providers);
|
||||
userRegistry.flush();
|
||||
sw.report();
|
||||
return commits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compounds logs from different repositories into a single multi-repository log.
|
||||
*/
|
||||
@NotNull
|
||||
private static List<? extends GraphCommit<Integer>> compound(@NotNull Collection<List<? extends GraphCommit<Integer>>> commits) {
|
||||
private static <T extends GraphCommit<Integer>> List<T> multiRepoJoin(@NotNull Collection<List<T>> commits) {
|
||||
StopWatch sw = StopWatch.start("multi-repo join");
|
||||
List<? extends GraphCommit<Integer>> joined = new VcsLogMultiRepoJoiner<Integer>().join(commits);
|
||||
List<T> joined = new VcsLogMultiRepoJoiner<Integer, T>().join(commits);
|
||||
sw.report();
|
||||
return joined;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<GraphCommit<Integer>> compactCommits(@NotNull List<? extends TimedVcsCommit> commits,
|
||||
@NotNull final VcsLogHashMap hashMap) {
|
||||
private List<GraphCommit<Integer>> compactCommits(@NotNull List<? extends TimedVcsCommit> commits) {
|
||||
StopWatch sw = StopWatch.start("compacting commits");
|
||||
List<GraphCommit<Integer>> map = ContainerUtil.map(commits, new Function<TimedVcsCommit, GraphCommit<Integer>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public GraphCommit<Integer> fun(@NotNull TimedVcsCommit commit) {
|
||||
return compactCommit(commit, hashMap);
|
||||
return compactCommit(commit);
|
||||
}
|
||||
});
|
||||
hashMap.flush();
|
||||
myHashMap.flush();
|
||||
sw.report();
|
||||
return map;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static GraphCommitImpl<Integer> compactCommit(@NotNull TimedVcsCommit commit, @NotNull VcsLogHashMap hashMap) {
|
||||
return new GraphCommitImpl<Integer>(hashMap.getCommitIndex(commit.getId()),
|
||||
ContainerUtil.map(commit.getParents(), hashMap.asIndexGetter()), commit.getTimestamp());
|
||||
private GraphCommitImpl<Integer> compactCommit(@NotNull TimedVcsCommit commit) {
|
||||
return new GraphCommitImpl<Integer>(myHashMap.getCommitIndex(commit.getId()),
|
||||
ContainerUtil.map(commit.getParents(), myHashMap.asIndexGetter()), commit.getTimestamp());
|
||||
}
|
||||
|
||||
private static void storeUsersAndDetails(@NotNull List<? extends VcsCommitMetadata> metadatas, @NotNull VcsUserRegistryImpl userRegistry,
|
||||
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache) {
|
||||
private void storeUsersAndDetails(@NotNull Collection<? extends VcsCommitMetadata> metadatas) {
|
||||
for (VcsCommitMetadata detail : metadatas) {
|
||||
userRegistry.addUser(detail.getAuthor());
|
||||
userRegistry.addUser(detail.getCommitter());
|
||||
topCommitsDetailsCache.put(detail.getId(), detail);
|
||||
myUserRegistry.addUser(detail.getAuthor());
|
||||
myUserRegistry.addUser(detail.getCommitter());
|
||||
myTopCommitsDetailsCache.put(detail.getId(), detail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,17 +188,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
|
||||
@NotNull private DataPack myCurrentDataPack;
|
||||
|
||||
// collects loaded info from different roots, which refresh was requested consecutively within a single task
|
||||
private final Map<VirtualFile, LogAndRefs> myLoadedInfos = ContainerUtil.newHashMap();
|
||||
|
||||
private class LogAndRefs {
|
||||
List<? extends GraphCommit<Integer>> log;
|
||||
Collection<VcsRef> refs;
|
||||
LogAndRefs(Collection<VcsRef> refs, List<? extends GraphCommit<Integer>> commits) {
|
||||
this.refs = refs;
|
||||
this.log = commits;
|
||||
}
|
||||
}
|
||||
@NotNull private final LogInfo myLoadedInfo = new LogInfo();
|
||||
|
||||
MyRefreshTask(@NotNull DataPack currentDataPack) {
|
||||
super(VcsLogRefresherImpl.this.myProject, "Refreshing history...", false);
|
||||
@@ -271,30 +226,28 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
private DataPack doRefresh(@NotNull Collection<VirtualFile> roots) {
|
||||
StopWatch sw = StopWatch.start("refresh");
|
||||
PermanentGraph<Integer> permanentGraph = myCurrentDataPack.isFull() ? myCurrentDataPack.getPermanentGraph() : null;
|
||||
Map<VirtualFile, Collection<VcsRef>> currentRefs = myCurrentDataPack.getRefsModel().getAllRefsByRoot();
|
||||
Map<VirtualFile, Set<VcsRef>> currentRefs = myCurrentDataPack.getRefsModel().getAllRefsByRoot();
|
||||
try {
|
||||
if (permanentGraph != null) {
|
||||
int commitCount = myRecentCommitCount;
|
||||
for (int attempt = 0; attempt <= 1; attempt++) {
|
||||
loadLogAndRefs(roots, currentRefs, commitCount);
|
||||
List<? extends GraphCommit<Integer>> compoundLog = compoundLoadedLogs(myLoadedInfos.values());
|
||||
Map<VirtualFile, Collection<VcsRef>> allNewRefs = getAllNewRefs(myLoadedInfos, currentRefs);
|
||||
List<? extends GraphCommit<Integer>> compoundLog = multiRepoJoin(myLoadedInfo.getCommits());
|
||||
Map<VirtualFile, Set<VcsRef>> allNewRefs = getAllNewRefs(myLoadedInfo, currentRefs);
|
||||
List<GraphCommit<Integer>> joinedFullLog = join(compoundLog, permanentGraph.getAllCommits(), currentRefs, allNewRefs);
|
||||
if (joinedFullLog == null) {
|
||||
commitCount *= 5;
|
||||
}
|
||||
else {
|
||||
return DataPack.build(joinedFullLog, new RefsModel(allNewRefs, myHashMap.asIndexGetter()),
|
||||
myHashMap.asIndexGetter(), myHashMap.asHashGetter(), myProviders, true);
|
||||
return DataPack.build(joinedFullLog, allNewRefs, myProviders, myHashMap, true);
|
||||
}
|
||||
}
|
||||
// couldn't join => need to reload everything; if 5000 commits is still not enough, it's worth reporting:
|
||||
LOG.error("Couldn't join " + commitCount + " recent commits to the log (" + permanentGraph.getAllCommits().size() + " commits)",
|
||||
new Attachment("recent_commits", toLogString(myLoadedInfos)));
|
||||
new Attachment("recent_commits", myLoadedInfo.toLogString(myHashMap.asIndexGetter())));
|
||||
}
|
||||
|
||||
Pair<PermanentGraph<Integer>, Map<VirtualFile, Collection<VcsRef>>> fullLogAndRefs = loadFullLog();
|
||||
return DataPack.build(fullLogAndRefs.first, myProviders, new RefsModel(fullLogAndRefs.second, myHashMap.asIndexGetter()), true);
|
||||
return loadFullLog();
|
||||
}
|
||||
catch (Exception e) {
|
||||
myExceptionHandler.consume(e);
|
||||
@@ -305,95 +258,45 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
}
|
||||
|
||||
private String toLogString(Map<VirtualFile, LogAndRefs> infos) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<VirtualFile, LogAndRefs> entry : infos.entrySet()) {
|
||||
sb.append(entry.getKey().getName());
|
||||
sb.append(" LOG:\n");
|
||||
sb.append(StringUtil.join(entry.getValue().log, new Function<GraphCommit<Integer>, String>() {
|
||||
@Override
|
||||
public String fun(GraphCommit<Integer> commit) {
|
||||
return commit.getId() + "<-" + StringUtil.join(commit.getParents(), ",");
|
||||
}
|
||||
}, "\n"));
|
||||
sb.append("\nREFS:\n");
|
||||
sb.append(StringUtil.join(entry.getValue().refs, new Function<VcsRef, String>() {
|
||||
@Override
|
||||
public String fun(VcsRef ref) {
|
||||
return ref.getName() + "(" + myHashMap.getCommitIndex(ref.getCommitHash()) + ")";
|
||||
}
|
||||
}, ","));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<? extends GraphCommit<Integer>> compoundLoadedLogs(@NotNull Collection<LogAndRefs> logsAndRefs) {
|
||||
return compound(ContainerUtil.map(logsAndRefs, new Function<LogAndRefs, List<? extends GraphCommit<Integer>>>() {
|
||||
@Override
|
||||
public List<? extends GraphCommit<Integer>> fun(LogAndRefs refs) {
|
||||
return refs.log;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<VirtualFile, Collection<VcsRef>> getAllNewRefs(@NotNull Map<VirtualFile, LogAndRefs> newInfo,
|
||||
@NotNull Map<VirtualFile, Collection<VcsRef>> previousRefs) {
|
||||
Map<VirtualFile, Collection<VcsRef>> result = ContainerUtil.newHashMap();
|
||||
private Map<VirtualFile, Set<VcsRef>> getAllNewRefs(@NotNull LogInfo newInfo,
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> previousRefs) {
|
||||
Map<VirtualFile, Set<VcsRef>> result = ContainerUtil.newHashMap();
|
||||
for (VirtualFile root : previousRefs.keySet()) {
|
||||
result.put(root, newInfo.containsKey(root) ? newInfo.get(root).refs : previousRefs.get(root));
|
||||
Set<VcsRef> newInfoRefs = newInfo.getRefs(root);
|
||||
result.put(root, newInfoRefs != null ? newInfoRefs : previousRefs.get(root));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void loadLogAndRefs(@NotNull Collection<VirtualFile> roots, @NotNull Map<VirtualFile, Collection<VcsRef>> prevRefs,
|
||||
private void loadLogAndRefs(@NotNull Collection<VirtualFile> roots,
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> prevRefs,
|
||||
int commitCount) throws VcsException {
|
||||
Map<VirtualFile, VcsLogProvider> providers = getProviders(roots);
|
||||
Map<VirtualFile, Collection<VcsRef>> refs = loadRefsFromVcs(providers);
|
||||
Map<VirtualFile, VcsLogProvider.Requirements> requirements = prepareRequirements(roots, commitCount, prevRefs, refs);
|
||||
Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = loadRecentCommitsFromVcs(providers, requirements,
|
||||
myUserRegistry, myTopCommitsDetailsCache,
|
||||
myHashMap);
|
||||
LogInfo logInfo = loadRecentData(prepareRequirements(roots, commitCount, prevRefs));
|
||||
for (VirtualFile root : roots) {
|
||||
myLoadedInfos.put(root, new LogAndRefs(refs.get(root), commits.get(root)));
|
||||
myLoadedInfo.put(root, logInfo.getCommits(root));
|
||||
myLoadedInfo.put(root, logInfo.getRefs(root));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<VirtualFile, VcsLogProvider.Requirements> prepareRequirements(@NotNull Collection<VirtualFile> roots,
|
||||
int commitCount,
|
||||
@NotNull Map<VirtualFile, Collection<VcsRef>> prevRefs,
|
||||
@NotNull Map<VirtualFile, Collection<VcsRef>> newRefs) {
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> prevRefs) {
|
||||
Map<VirtualFile, VcsLogProvider.Requirements> requirements = ContainerUtil.newHashMap();
|
||||
for (VirtualFile root : roots) {
|
||||
requirements.put(root, new RequirementsImpl(commitCount, true, getRefsForRoot(prevRefs, root), getRefsForRoot(newRefs, root)));
|
||||
requirements.put(root, new RequirementsImpl(commitCount, true, ContainerUtil.notNullize(prevRefs.get(root))));
|
||||
}
|
||||
return requirements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<VcsRef> getRefsForRoot(@NotNull Map<VirtualFile, Collection<VcsRef>> map, @NotNull VirtualFile root) {
|
||||
Collection<VcsRef> refs = map.get(root);
|
||||
return refs == null ? Collections.<VcsRef>emptySet() : new HashSet<VcsRef>(refs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<VirtualFile, VcsLogProvider> getProviders(@NotNull Collection<VirtualFile> roots) {
|
||||
Map<VirtualFile, VcsLogProvider> providers = ContainerUtil.newHashMap();
|
||||
for (VirtualFile root : roots) {
|
||||
providers.put(root, myProviders.get(root));
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<GraphCommit<Integer>> join(@NotNull List<? extends GraphCommit<Integer>> recentCommits, @NotNull List<GraphCommit<Integer>> fullLog,
|
||||
@NotNull Map<VirtualFile, Collection<VcsRef>> previousRefs,
|
||||
@NotNull Map<VirtualFile, Collection<VcsRef>> newRefs) {
|
||||
private List<GraphCommit<Integer>> join(@NotNull List<? extends GraphCommit<Integer>> recentCommits,
|
||||
@NotNull List<GraphCommit<Integer>> fullLog,
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> previousRefs,
|
||||
@NotNull Map<VirtualFile, Set<VcsRef>> newRefs) {
|
||||
StopWatch sw = StopWatch.start("joining new commits");
|
||||
Function<VcsRef, Integer> ref2Int = new Function<VcsRef, Integer>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Integer fun(@NotNull VcsRef ref) {
|
||||
return myHashMap.getCommitIndex(ref.getCommitHash());
|
||||
@@ -418,50 +321,44 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Pair<PermanentGraph<Integer>, Map<VirtualFile, Collection<VcsRef>>> loadFullLog() throws VcsException {
|
||||
private DataPack loadFullLog() throws VcsException {
|
||||
StopWatch sw = StopWatch.start("full log reload");
|
||||
Collection<List<? extends GraphCommit<Integer>>> commits = readFullLogFromVcs();
|
||||
List<? extends GraphCommit<Integer>> graphCommits = compound(commits);
|
||||
Map<VirtualFile, Collection<VcsRef>> refMap = loadRefsFromVcs(myProviders);
|
||||
PermanentGraph<Integer> permanentGraph = DataPack.buildPermanentGraph(graphCommits, new RefsModel(refMap, myHashMap.asIndexGetter()),
|
||||
myHashMap.asIndexGetter(),
|
||||
myHashMap.asHashGetter(), myProviders);
|
||||
LogInfo logInfo = readFullLogFromVcs();
|
||||
List<? extends GraphCommit<Integer>> graphCommits = multiRepoJoin(logInfo.getCommits());
|
||||
DataPack dataPack = DataPack.build(graphCommits, logInfo.getRefs(), myProviders, myHashMap, true);
|
||||
sw.report();
|
||||
return Pair.create(permanentGraph, refMap);
|
||||
return dataPack;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<List<? extends GraphCommit<Integer>>> readFullLogFromVcs() throws VcsException {
|
||||
private LogInfo readFullLogFromVcs() throws VcsException {
|
||||
final StopWatch sw = StopWatch.start("read full log from VCS");
|
||||
final Collection<List<? extends GraphCommit<Integer>>> logs = ContainerUtil.newArrayList();
|
||||
final LogInfo logInfo = new LogInfo();
|
||||
new ProviderIterator() {
|
||||
@Override
|
||||
void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
|
||||
final List<GraphCommit<Integer>> graphCommits = ContainerUtil.newArrayList();
|
||||
provider.readAllHashes(root, new Consumer<VcsUser>() {
|
||||
VcsLogProvider.LogData data = provider.readAllHashes(root, new Consumer<TimedVcsCommit>() {
|
||||
@Override
|
||||
public void consume(@NotNull VcsUser user) {
|
||||
myUserRegistry.addUser(user);
|
||||
}
|
||||
}, new Consumer<TimedVcsCommit>() {
|
||||
@Override
|
||||
public void consume(TimedVcsCommit commit) {
|
||||
graphCommits.add(compactCommit(commit, myHashMap));
|
||||
public void consume(@NotNull TimedVcsCommit commit) {
|
||||
graphCommits.add(compactCommit(commit));
|
||||
}
|
||||
});
|
||||
logs.add(graphCommits);
|
||||
logInfo.put(root, graphCommits);
|
||||
logInfo.put(root, data.getRefs());
|
||||
myUserRegistry.addUsers(data.getUsers());
|
||||
sw.rootCompleted(root);
|
||||
}
|
||||
}.iterate(myProviders);
|
||||
myUserRegistry.flush();
|
||||
sw.report();
|
||||
return logs;
|
||||
return logInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RefreshRequest {
|
||||
private static RefreshRequest RELOAD_ALL = new RefreshRequest(Collections.<VirtualFile>emptyList());
|
||||
@NotNull private final Collection<VirtualFile> rootsToRefresh;
|
||||
private static final RefreshRequest RELOAD_ALL = new RefreshRequest(Collections.<VirtualFile>emptyList());
|
||||
private final Collection<VirtualFile> rootsToRefresh;
|
||||
|
||||
RefreshRequest(@NotNull Collection<VirtualFile> rootsToRefresh) {
|
||||
this.rootsToRefresh = rootsToRefresh;
|
||||
@@ -477,4 +374,85 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CommitCountRequirements implements VcsLogProvider.Requirements {
|
||||
private final int myCommitCount;
|
||||
|
||||
public CommitCountRequirements(int commitCount) {
|
||||
myCommitCount = commitCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCommitCount() {
|
||||
return myCommitCount;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Map<VirtualFile, VcsLogProvider.Requirements> asMap(@NotNull Collection<VirtualFile> roots) {
|
||||
return ContainerUtil.map2Map(roots, new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider.Requirements>>() {
|
||||
@Override
|
||||
public Pair<VirtualFile, VcsLogProvider.Requirements> fun(VirtualFile root) {
|
||||
return Pair.<VirtualFile, VcsLogProvider.Requirements>create(root, CommitCountRequirements.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class LogInfo {
|
||||
private final Map<VirtualFile, Set<VcsRef>> myRefs = ContainerUtil.newHashMap();
|
||||
private final Map<VirtualFile, List<GraphCommit<Integer>>> myCommits = ContainerUtil.newHashMap();
|
||||
|
||||
void put(@NotNull VirtualFile root, @NotNull List<GraphCommit<Integer>> commits) {
|
||||
myCommits.put(root, commits);
|
||||
}
|
||||
|
||||
void put(@NotNull VirtualFile root, @NotNull Set<VcsRef> refs) {
|
||||
myRefs.put(root, refs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Collection<List<GraphCommit<Integer>>> getCommits() {
|
||||
return myCommits.values();
|
||||
}
|
||||
|
||||
List<GraphCommit<Integer>> getCommits(@NotNull VirtualFile root) {
|
||||
return myCommits.get(root);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Map<VirtualFile, Set<VcsRef>> getRefs() {
|
||||
return myRefs;
|
||||
}
|
||||
|
||||
public Set<VcsRef> getRefs(@NotNull VirtualFile root) {
|
||||
return myRefs.get(root);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
|
||||
@NotNull
|
||||
public String toLogString(@NotNull final NotNullFunction<Hash, Integer> indexGetter) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" LOG:\n");
|
||||
for (Map.Entry<VirtualFile, List<GraphCommit<Integer>>> entry : myCommits.entrySet()) {
|
||||
sb.append(entry.getKey().getName() + "\n");
|
||||
sb.append(StringUtil.join(entry.getValue(), new Function<GraphCommit<Integer>, String>() {
|
||||
@Override
|
||||
public String fun(@NotNull GraphCommit<Integer> commit) {
|
||||
return commit.getId() + "<-" + StringUtil.join(commit.getParents(), ",");
|
||||
}
|
||||
}, "\n"));
|
||||
}
|
||||
sb.append("\nREFS:\n");
|
||||
for (Map.Entry<VirtualFile, Set<VcsRef>> entry : myRefs.entrySet()) {
|
||||
sb.append(entry.getKey().getName() + "\n");
|
||||
sb.append(StringUtil.join(entry.getValue(), new Function<VcsRef, String>() {
|
||||
@Override
|
||||
public String fun(@NotNull VcsRef ref) {
|
||||
return ref.getName() + "(" + indexGetter.fun(ref.getCommitHash()) + ")";
|
||||
}
|
||||
}, ","));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,12 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
public void addUsers(@NotNull Collection<VcsUser> users) {
|
||||
for (VcsUser user : users) {
|
||||
addUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Set<VcsUser> getUsers() {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 com.intellij.vcs.log.impl;
|
||||
|
||||
import com.intellij.vcs.log.VcsCommitMetadata;
|
||||
import com.intellij.vcs.log.VcsLogProvider;
|
||||
import com.intellij.vcs.log.VcsRef;
|
||||
import com.intellij.vcs.log.VcsUser;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class LogDataImpl implements VcsLogProvider.DetailedLogData, VcsLogProvider.LogData {
|
||||
|
||||
private static final LogDataImpl EMPTY = new LogDataImpl(Collections.<VcsRef>emptySet(),
|
||||
Collections.<VcsUser>emptySet(),
|
||||
Collections.<VcsCommitMetadata>emptyList());
|
||||
|
||||
@NotNull private final List<VcsCommitMetadata> myCommits;
|
||||
@NotNull private final Set<VcsRef> myRefs;
|
||||
@NotNull private final Set<VcsUser> myUsers;
|
||||
|
||||
@NotNull
|
||||
public static LogDataImpl empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
public LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull Set<VcsUser> users) {
|
||||
this(refs, users, Collections.<VcsCommitMetadata>emptyList());
|
||||
}
|
||||
|
||||
public LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull List<VcsCommitMetadata> metadatas) {
|
||||
this(refs, Collections.<VcsUser>emptySet(), metadatas);
|
||||
}
|
||||
|
||||
private LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull Set<VcsUser> users, @NotNull List<VcsCommitMetadata> commits) {
|
||||
myRefs = refs;
|
||||
myUsers = users;
|
||||
myCommits = commits;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<VcsCommitMetadata> getCommits() {
|
||||
return myCommits;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Set<VcsRef> getRefs() {
|
||||
return myRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VcsUser> getUsers() {
|
||||
return myUsers;
|
||||
}
|
||||
}
|
||||
@@ -26,13 +26,11 @@ public class RequirementsImpl implements VcsLogProviderRequirementsEx {
|
||||
private final int myCommitCount;
|
||||
private final boolean myRefresh;
|
||||
@NotNull private final Set<VcsRef> myPreviousRefs;
|
||||
@NotNull private final Set<VcsRef> myCurrentRefs;
|
||||
|
||||
public RequirementsImpl(int count, boolean refresh, @NotNull Set<VcsRef> previousRefs, @NotNull Set<VcsRef> currentRefs) {
|
||||
public RequirementsImpl(int count, boolean refresh, @NotNull Set<VcsRef> previousRefs) {
|
||||
myCommitCount = count;
|
||||
myRefresh = refresh;
|
||||
myPreviousRefs = previousRefs;
|
||||
myCurrentRefs = currentRefs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,10 +48,4 @@ public class RequirementsImpl implements VcsLogProviderRequirementsEx {
|
||||
public Set<VcsRef> getPreviousRefs() {
|
||||
return myPreviousRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VcsRef> getCurrentRefs() {
|
||||
return myCurrentRefs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -59,13 +57,14 @@ public class TestVcsLogProvider implements VcsLogProvider {
|
||||
@NotNull private final ReducibleSemaphore myRefreshSemaphore;
|
||||
private int myReadFirstBlockCounter;
|
||||
|
||||
private final Function<TimedVcsCommit, VcsCommitMetadata> myCommitToMetadataConvertor = new Function<TimedVcsCommit, VcsCommitMetadata>(){
|
||||
@Override
|
||||
public VcsCommitMetadata fun(TimedVcsCommit commit) {
|
||||
return new VcsCommitMetadataImpl(commit.getId(), commit.getParents(), commit.getTimestamp(), myRoot, SAMPLE_SUBJECT, STUB_USER,
|
||||
SAMPLE_SUBJECT, STUB_USER, commit.getTimestamp());
|
||||
}
|
||||
};
|
||||
private final Function<TimedVcsCommit, VcsCommitMetadata> myCommitToMetadataConvertor =
|
||||
new Function<TimedVcsCommit, VcsCommitMetadata>() {
|
||||
@Override
|
||||
public VcsCommitMetadata fun(TimedVcsCommit commit) {
|
||||
return new VcsCommitMetadataImpl(commit.getId(), commit.getParents(), commit.getTimestamp(), myRoot,
|
||||
SAMPLE_SUBJECT, STUB_USER, SAMPLE_SUBJECT, STUB_USER, commit.getTimestamp());
|
||||
}
|
||||
};
|
||||
|
||||
public TestVcsLogProvider(@NotNull VirtualFile root) {
|
||||
myRoot = root;
|
||||
@@ -78,7 +77,8 @@ public class TestVcsLogProvider implements VcsLogProvider {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull final VirtualFile root, @NotNull Requirements requirements)
|
||||
public DetailedLogData readFirstBlock(@NotNull final VirtualFile root,
|
||||
@NotNull Requirements requirements)
|
||||
throws VcsException {
|
||||
if (requirements instanceof VcsLogProviderRequirementsEx && ((VcsLogProviderRequirementsEx)requirements).isRefresh()) {
|
||||
try {
|
||||
@@ -90,12 +90,14 @@ public class TestVcsLogProvider implements VcsLogProvider {
|
||||
}
|
||||
myReadFirstBlockCounter++;
|
||||
assertRoot(root);
|
||||
return ContainerUtil.map(myCommits.subList(0, requirements.getCommitCount()), myCommitToMetadataConvertor);
|
||||
List<VcsCommitMetadata> metadatas = ContainerUtil.map(myCommits.subList(0, requirements.getCommitCount()),
|
||||
myCommitToMetadataConvertor);
|
||||
return new LogDataImpl(Collections.<VcsRef>emptySet(), metadatas);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
|
||||
@NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
public LogData readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
try {
|
||||
myFullLogSemaphore.acquire();
|
||||
}
|
||||
@@ -106,6 +108,7 @@ public class TestVcsLogProvider implements VcsLogProvider {
|
||||
for (TimedVcsCommit commit : myCommits) {
|
||||
commitConsumer.consume(commit);
|
||||
}
|
||||
return new LogDataImpl(myRefs, Collections.<VcsUser>emptySet());
|
||||
}
|
||||
|
||||
private void assertRoot(@NotNull VirtualFile root) {
|
||||
@@ -125,12 +128,6 @@ public class TestVcsLogProvider implements VcsLogProvider {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
|
||||
return myRefs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VcsKey getSupportedVcs() {
|
||||
|
||||
@@ -314,6 +314,9 @@ public class GitBranchUtil {
|
||||
else if (branchName.startsWith(GitBranch.REFS_REMOTES_PREFIX)) {
|
||||
return branchName.substring(GitBranch.REFS_REMOTES_PREFIX.length());
|
||||
}
|
||||
else if (branchName.startsWith(GitTag.REFS_TAGS_PREFIX)) {
|
||||
return branchName.substring(GitTag.REFS_TAGS_PREFIX.length());
|
||||
}
|
||||
return branchName;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.intellij.util.*;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.impl.LogDataImpl;
|
||||
import com.intellij.vcs.log.impl.HashImpl;
|
||||
import com.intellij.vcs.log.util.StopWatch;
|
||||
import git4idea.*;
|
||||
@@ -53,6 +54,7 @@ import git4idea.history.browser.SymbolicRefsI;
|
||||
import git4idea.history.wholeTree.AbstractHash;
|
||||
import git4idea.history.wholeTree.CommitHashPlusParents;
|
||||
import git4idea.history.wholeTree.GitCommitsSequentialIndex;
|
||||
import git4idea.log.GitRefManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -550,21 +552,12 @@ public class GitHistoryUtils {
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<TimedVcsCommit> readCommits(@NotNull final Project project,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull final Consumer<VcsUser> userRegistry,
|
||||
@NotNull List<String> parameters) throws VcsException {
|
||||
List<TimedVcsCommit> collector = ContainerUtil.newArrayList();
|
||||
readCommits(project, root, userRegistry, parameters, new CollectConsumer<TimedVcsCommit>(collector));
|
||||
return collector;
|
||||
}
|
||||
|
||||
public static void readCommits(@NotNull final Project project,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull final Consumer<VcsUser> userRegistry,
|
||||
@NotNull List<String> parameters,
|
||||
@NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
@NotNull final VirtualFile root,
|
||||
@NotNull List<String> parameters,
|
||||
@NotNull final Consumer<VcsUser> userConsumer,
|
||||
@NotNull final Consumer<VcsRef> refConsumer,
|
||||
@NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
|
||||
if (factory == null) {
|
||||
return;
|
||||
@@ -573,11 +566,12 @@ public class GitHistoryUtils {
|
||||
final int COMMIT_BUFFER = 1000;
|
||||
GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
|
||||
final GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.NONE, HASH, PARENTS, COMMIT_TIME,
|
||||
AUTHOR_NAME, AUTHOR_EMAIL);
|
||||
AUTHOR_NAME, AUTHOR_EMAIL, REF_NAMES);
|
||||
h.setStdoutSuppressed(true);
|
||||
h.addParameters(parser.getPretty(), "--encoding=UTF-8");
|
||||
h.addParameters("--full-history");
|
||||
h.addParameters("--date-order");
|
||||
h.addParameters("--decorate=full");
|
||||
h.addParameters(parameters);
|
||||
h.endOptions();
|
||||
|
||||
@@ -603,7 +597,7 @@ public class GitHistoryUtils {
|
||||
afterParseRemainder = line.substring(recordEnd + 1);
|
||||
}
|
||||
if (afterParseRemainder != null && records.incrementAndGet() > COMMIT_BUFFER) { // null means can't parse now
|
||||
List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory);
|
||||
List<TimedVcsCommit> commits = parseCommit(parser, record, userConsumer, refConsumer, factory, root);
|
||||
for (TimedVcsCommit commit : commits) {
|
||||
commitConsumer.consume(commit);
|
||||
}
|
||||
@@ -619,7 +613,7 @@ public class GitHistoryUtils {
|
||||
@Override
|
||||
public void processTerminated(int exitCode) {
|
||||
try {
|
||||
List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory);
|
||||
List<TimedVcsCommit> commits = parseCommit(parser, record, userConsumer, refConsumer, factory, root);
|
||||
for (TimedVcsCommit commit : commits) {
|
||||
commitConsumer.consume(commit);
|
||||
}
|
||||
@@ -641,9 +635,12 @@ public class GitHistoryUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<TimedVcsCommit> parseCommit(@NotNull GitLogParser parser, @NotNull StringBuilder record,
|
||||
private static List<TimedVcsCommit> parseCommit(@NotNull GitLogParser parser,
|
||||
@NotNull StringBuilder record,
|
||||
@NotNull final Consumer<VcsUser> userRegistry,
|
||||
@NotNull final VcsLogObjectsFactory factory) {
|
||||
@NotNull final Consumer<VcsRef> refConsumer,
|
||||
@NotNull final VcsLogObjectsFactory factory,
|
||||
@NotNull final VirtualFile root) {
|
||||
List<GitLogRecord> rec = parser.parse(record.toString());
|
||||
return ContainerUtil.mapNotNull(rec, new Function<GitLogRecord, TimedVcsCommit>() {
|
||||
@Override
|
||||
@@ -651,7 +648,11 @@ public class GitHistoryUtils {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
TimedVcsCommit commit = convert(record, factory);
|
||||
Pair<TimedVcsCommit, Collection<VcsRef>> pair = convert(record, factory, root);
|
||||
TimedVcsCommit commit = pair.first;
|
||||
for (VcsRef ref : pair.second) {
|
||||
refConsumer.consume(ref);
|
||||
}
|
||||
userRegistry.consume(factory.createUser(record.getAuthorName(), record.getAuthorEmail()));
|
||||
return commit;
|
||||
}
|
||||
@@ -659,9 +660,28 @@ public class GitHistoryUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TimedVcsCommit convert(@NotNull GitLogRecord rec, @NotNull VcsLogObjectsFactory factory) {
|
||||
private static Pair<TimedVcsCommit, Collection<VcsRef>> convert(@NotNull GitLogRecord rec,
|
||||
@NotNull VcsLogObjectsFactory factory,
|
||||
@NotNull VirtualFile root) {
|
||||
Hash hash = HashImpl.build(rec.getHash());
|
||||
List<Hash> parents = getParentHashes(factory, rec);
|
||||
return factory.createTimedCommit(HashImpl.build(rec.getHash()), parents, rec.getCommitTime());
|
||||
TimedVcsCommit commit = factory.createTimedCommit(hash, parents, rec.getCommitTime());
|
||||
return Pair.create(commit, parseRefs(rec.getRefs(), hash, factory, root));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<VcsRef> parseRefs(@NotNull Collection<String> refs,
|
||||
@NotNull final Hash hash,
|
||||
@NotNull final VcsLogObjectsFactory factory,
|
||||
@NotNull final VirtualFile root) {
|
||||
return ContainerUtil.mapNotNull(refs, new Function<String, VcsRef>() {
|
||||
@Override
|
||||
public VcsRef fun(String refName) {
|
||||
VcsRefType type = GitRefManager.getRefType(refName);
|
||||
refName = GitBranchUtil.stripRefsPrefix(refName);
|
||||
return factory.createRef(hash, refName, type, root);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -784,23 +804,28 @@ public class GitHistoryUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<VcsCommitMetadata> loadMetadata(@NotNull Project project, @NotNull final VirtualFile root,
|
||||
@NotNull String... parameters) throws VcsException {
|
||||
|
||||
public static VcsLogProvider.DetailedLogData loadMetadata(@NotNull final Project project,
|
||||
@NotNull final VirtualFile root,
|
||||
final boolean withRefs,
|
||||
String... params) throws VcsException {
|
||||
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
|
||||
if (factory == null) {
|
||||
return Collections.emptyList();
|
||||
return LogDataImpl.empty();
|
||||
}
|
||||
return loadDetails(project, root, false, new NullableFunction<GitLogRecord, VcsCommitMetadata>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public VcsCommitMetadata fun(GitLogRecord record) {
|
||||
return factory.createCommitMetadata(factory.createHash(record.getHash()), getParentHashes(factory, record), record.getCommitTime(),
|
||||
root, record.getSubject(), record.getAuthorName(), record.getAuthorEmail(),
|
||||
record.getFullMessage(), record.getCommitterName(), record.getCommitterEmail(),
|
||||
record.getAuthorTimeStamp());
|
||||
}
|
||||
}, parameters);
|
||||
final Set<VcsRef> refs = ContainerUtil.newHashSet();
|
||||
final List<VcsCommitMetadata> commits =
|
||||
loadDetails(project, root, withRefs, false, new NullableFunction<GitLogRecord, VcsCommitMetadata>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public VcsCommitMetadata fun(GitLogRecord record) {
|
||||
GitCommit commit = createCommit(project, root, record, factory);
|
||||
if (withRefs) {
|
||||
refs.addAll(parseRefs(record.getRefs(), commit.getId(), factory, root));
|
||||
}
|
||||
return commit;
|
||||
}
|
||||
}, params);
|
||||
return new LogDataImpl(refs, commits);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -816,33 +841,37 @@ public class GitHistoryUtils {
|
||||
if (factory == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return loadDetails(project, root, true, new NullableFunction<GitLogRecord, GitCommit>() {
|
||||
return loadDetails(project, root, true, true, new NullableFunction<GitLogRecord, GitCommit>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public GitCommit fun(GitLogRecord record) {
|
||||
try {
|
||||
return createCommit(project, root, record, factory);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
return createCommit(project, root, record, factory);
|
||||
}
|
||||
}, parameters);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> List<T> loadDetails(@NotNull final Project project, @NotNull final VirtualFile root, boolean withChanges,
|
||||
@NotNull NullableFunction<GitLogRecord, T> converter, String... parameters)
|
||||
public static <T> List<T> loadDetails(@NotNull final Project project,
|
||||
@NotNull final VirtualFile root,
|
||||
boolean withRefs,
|
||||
boolean withChanges,
|
||||
@NotNull NullableFunction<GitLogRecord, T> converter,
|
||||
String... parameters)
|
||||
throws VcsException {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
|
||||
GitLogParser.NameStatus status = withChanges ? GitLogParser.NameStatus.STATUS : GitLogParser.NameStatus.NONE;
|
||||
GitLogParser parser = new GitLogParser(project, status, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME,
|
||||
AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, PARENTS, SUBJECT, BODY, RAW_BODY);
|
||||
GitLogParser.GitLogOption[] options = { HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL,
|
||||
PARENTS, SUBJECT, BODY, RAW_BODY };
|
||||
if (withRefs) {
|
||||
options = ArrayUtil.append(options, REF_NAMES);
|
||||
}
|
||||
GitLogParser parser = new GitLogParser(project, status, options);
|
||||
h.setStdoutSuppressed(true);
|
||||
h.addParameters(parameters);
|
||||
h.addParameters(parser.getPretty(), "--encoding=UTF-8");
|
||||
h.addParameters("--full-history", "--sparse");
|
||||
if (withRefs) {
|
||||
h.addParameters("--decorate=full");
|
||||
}
|
||||
if (withChanges) {
|
||||
h.addParameters("-M", "--name-status");
|
||||
}
|
||||
@@ -863,7 +892,7 @@ public class GitHistoryUtils {
|
||||
}
|
||||
|
||||
private static GitCommit createCommit(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLogRecord record,
|
||||
@NotNull VcsLogObjectsFactory factory) throws VcsException {
|
||||
@NotNull VcsLogObjectsFactory factory) {
|
||||
List<Hash> parents = getParentHashes(factory, record);
|
||||
return new GitCommit(project, HashImpl.build(record.getHash()), parents, record.getCommitTime(), root, record.getSubject(),
|
||||
factory.createUser(record.getAuthorName(), record.getAuthorEmail()), record.getFullMessage(),
|
||||
|
||||
@@ -15,34 +15,26 @@
|
||||
*/
|
||||
package git4idea.log;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsKey;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.OpenTHashSet;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.data.VcsLogSorter;
|
||||
import com.intellij.vcs.log.impl.LogDataImpl;
|
||||
import com.intellij.vcs.log.impl.HashImpl;
|
||||
import git4idea.GitLocalBranch;
|
||||
import git4idea.GitRemoteBranch;
|
||||
import git4idea.GitUserRegistry;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.*;
|
||||
import git4idea.branch.GitBranchUtil;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitSimpleHandler;
|
||||
import git4idea.history.GitHistoryUtils;
|
||||
import git4idea.history.GitLogParser;
|
||||
import git4idea.repo.GitRepository;
|
||||
import git4idea.repo.GitRepositoryChangeListener;
|
||||
import git4idea.repo.GitRepositoryManager;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -51,6 +43,23 @@ import java.util.*;
|
||||
public class GitLogProvider implements VcsLogProvider {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GitLogProvider.class);
|
||||
public static final Function<VcsRef, String> GET_TAG_NAME = new Function<VcsRef, String>() {
|
||||
@Override
|
||||
public String fun(VcsRef ref) {
|
||||
return ref.getType() == GitRefManager.TAG ? ref.getName() : null;
|
||||
}
|
||||
};
|
||||
private static final TObjectHashingStrategy<VcsRef> REF_ONLY_NAME_STRATEGY = new TObjectHashingStrategy<VcsRef>() {
|
||||
@Override
|
||||
public int computeHashCode(@NotNull VcsRef ref) {
|
||||
return ref.getName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull VcsRef ref1, @NotNull VcsRef ref2) {
|
||||
return ref1.getName().equals(ref2.getName());
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull private final Project myProject;
|
||||
@NotNull private final GitRepositoryManager myRepositoryManager;
|
||||
@@ -69,108 +78,122 @@ public class GitLogProvider implements VcsLogProvider {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
|
||||
public DetailedLogData readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
|
||||
if (!isRepositoryReady(root)) {
|
||||
return Collections.emptyList();
|
||||
return LogDataImpl.empty();
|
||||
}
|
||||
GitRepository repository = ObjectUtils.assertNotNull(myRepositoryManager.getRepositoryForRoot(root));
|
||||
|
||||
// need to query more to sort them manually; this doesn't affect performance: it is equal for -1000 and -2000
|
||||
int commitCount = requirements.getCommitCount() * 2;
|
||||
|
||||
String[] params = new String[]{"HEAD", "--branches", "--remotes", "--max-count=" + commitCount};
|
||||
// NB: not specifying --tags, because it introduces great slowdown if there are many tags,
|
||||
// but makes sense only if there are heads without branch or HEAD labels (rare case). Such cases are partially handles below.
|
||||
List<VcsCommitMetadata> firstBlock = GitHistoryUtils.loadMetadata(myProject, root, params);
|
||||
// but makes sense only if there are heads without branch or HEAD labels (rare case). Such cases are partially handled below.
|
||||
|
||||
if (requirements instanceof VcsLogProviderRequirementsEx) {
|
||||
VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx)requirements;
|
||||
boolean refresh = requirements instanceof VcsLogProviderRequirementsEx && ((VcsLogProviderRequirementsEx)requirements).isRefresh();
|
||||
|
||||
DetailedLogData data = GitHistoryUtils.loadMetadata(myProject, root, refresh, params);
|
||||
|
||||
Set<VcsRef> safeRefs = data.getRefs();
|
||||
Set<VcsRef> allRefs = new OpenTHashSet<VcsRef>(safeRefs, REF_ONLY_NAME_STRATEGY);
|
||||
addNewElements(allRefs, readBranches(repository));
|
||||
|
||||
Collection<VcsCommitMetadata> allDetails;
|
||||
if (!refresh) {
|
||||
allDetails = data.getCommits();
|
||||
}
|
||||
else {
|
||||
// on refresh: get new tags, which point to commits not from the first block; then get history, walking down just from these tags
|
||||
// on init: just ignore such tagged-only branches. The price for speed-up.
|
||||
if (rex.isRefresh()) {
|
||||
Collection<VcsRef> newTags = getNewTags(rex.getCurrentRefs(), rex.getPreviousRefs());
|
||||
if (!newTags.isEmpty()) {
|
||||
final Set<Hash> firstBlockHashes = ContainerUtil.map2Set(firstBlock, new Function<VcsCommitMetadata, Hash>() {
|
||||
@Override
|
||||
public Hash fun(VcsCommitMetadata metadata) {
|
||||
return metadata.getId();
|
||||
}
|
||||
});
|
||||
List<VcsRef> unmatchedHeads = getUnmatchedHeads(firstBlockHashes, newTags);
|
||||
if (!unmatchedHeads.isEmpty()) {
|
||||
List<VcsCommitMetadata> detailsFromTaggedBranches = loadSomeCommitsOnTaggedBranches(root, commitCount, unmatchedHeads);
|
||||
Collection<VcsCommitMetadata> unmatchedCommits = getUnmatchedCommits(firstBlockHashes, detailsFromTaggedBranches);
|
||||
firstBlock.addAll(unmatchedCommits);
|
||||
}
|
||||
}
|
||||
VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx)requirements;
|
||||
|
||||
Set<String> currentTags = readCurrentTagNames(root);
|
||||
addOldStillExistingTags(allRefs, currentTags, rex.getPreviousRefs());
|
||||
|
||||
allDetails = ContainerUtil.newHashSet(data.getCommits());
|
||||
|
||||
Set<String> previousTags = new HashSet<String>(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME));
|
||||
Set<String> safeTags = new HashSet<String>(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME));
|
||||
Set<String> newUnmatchedTags = remove(currentTags, previousTags, safeTags);
|
||||
|
||||
if (!newUnmatchedTags.isEmpty()) {
|
||||
DetailedLogData commitsFromTags = loadSomeCommitsOnTaggedBranches(root, commitCount, newUnmatchedTags);
|
||||
addNewElements(allDetails, commitsFromTags.getCommits());
|
||||
addNewElements(allRefs, commitsFromTags.getRefs());
|
||||
}
|
||||
}
|
||||
|
||||
firstBlock = VcsLogSorter.sortByDateTopoOrder(firstBlock);
|
||||
firstBlock = new ArrayList<VcsCommitMetadata>(firstBlock.subList(0, Math.min(firstBlock.size(), requirements.getCommitCount())));
|
||||
return firstBlock;
|
||||
List<VcsCommitMetadata> sortedCommits = VcsLogSorter.sortByDateTopoOrder(allDetails);
|
||||
sortedCommits = sortedCommits.subList(0, Math.min(sortedCommits.size(), requirements.getCommitCount()));
|
||||
|
||||
return new LogDataImpl(allRefs, sortedCommits);
|
||||
}
|
||||
|
||||
private static void addOldStillExistingTags(@NotNull Set<VcsRef> allRefs,
|
||||
@NotNull Set<String> currentTags,
|
||||
@NotNull Set<VcsRef> previousRefs) {
|
||||
for (VcsRef ref : previousRefs) {
|
||||
if (!allRefs.contains(ref) && currentTags.contains(ref.getName())) {
|
||||
allRefs.add(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<VcsRef> getNewTags(@NotNull Set<VcsRef> currentRefs, @NotNull final Set<VcsRef> previousRefs) {
|
||||
return ContainerUtil.filter(currentRefs, new Condition<VcsRef>() {
|
||||
@Override
|
||||
public boolean value(VcsRef ref) {
|
||||
return !ref.getType().isBranch() && !previousRefs.contains(ref);
|
||||
}
|
||||
});
|
||||
private Set<String> readCurrentTagNames(@NotNull VirtualFile root) throws VcsException {
|
||||
Set<String> tags = ContainerUtil.newHashSet();
|
||||
GitTag.listAsStrings(myProject, root, tags, null);
|
||||
return tags;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<VcsCommitMetadata> loadSomeCommitsOnTaggedBranches(@NotNull VirtualFile root, int commitCount,
|
||||
@NotNull List<VcsRef> unmatchedHeads) throws VcsException {
|
||||
List<String> params = new ArrayList<String>(ContainerUtil.map(unmatchedHeads, new Function<VcsRef, String>() {
|
||||
@Override
|
||||
public String fun(VcsRef ref) {
|
||||
return ref.getCommitHash().asString();
|
||||
private static <T> Set<T> remove(@NotNull Set<T> original, @NotNull Set<T>... toRemove) {
|
||||
Set<T> result = ContainerUtil.newHashSet(original);
|
||||
for (Set<T> set : toRemove) {
|
||||
result.removeAll(set);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> void addNewElements(@NotNull Collection<T> original, @NotNull Collection<T> toAdd) {
|
||||
for (T item : toAdd) {
|
||||
if (!original.contains(item)) {
|
||||
original.add(item);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DetailedLogData loadSomeCommitsOnTaggedBranches(@NotNull VirtualFile root, int commitCount,
|
||||
@NotNull Collection<String> unmatchedTags) throws VcsException {
|
||||
List<String> params = new ArrayList<String>();
|
||||
params.add("--max-count=" + commitCount);
|
||||
return GitHistoryUtils.loadMetadata(myProject, root, ArrayUtil.toStringArray(params));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<VcsRef> getUnmatchedHeads(@NotNull final Set<Hash> firstBlockHashes, @NotNull Collection<VcsRef> refs) {
|
||||
return ContainerUtil.filter(refs, new Condition<VcsRef>() {
|
||||
@Override
|
||||
public boolean value(VcsRef ref) {
|
||||
return !firstBlockHashes.contains(ref.getCommitHash());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<VcsCommitMetadata> getUnmatchedCommits(@NotNull final Set<Hash> firstBlockHashes,
|
||||
@NotNull List<VcsCommitMetadata> detailsFromTaggedBranches) {
|
||||
return ContainerUtil.filter(detailsFromTaggedBranches, new Condition<VcsCommitMetadata>() {
|
||||
@Override
|
||||
public boolean value(VcsCommitMetadata metadata) {
|
||||
return !firstBlockHashes.contains(metadata.getId());
|
||||
}
|
||||
});
|
||||
params.addAll(unmatchedTags);
|
||||
return GitHistoryUtils.loadMetadata(myProject, root, true, ArrayUtil.toStringArray(params));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
|
||||
@NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
@NotNull
|
||||
public LogData readAllHashes(@NotNull VirtualFile root, @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
if (!isRepositoryReady(root)) {
|
||||
return;
|
||||
return LogDataImpl.empty();
|
||||
}
|
||||
|
||||
List<String> parameters = new ArrayList<String>(GitHistoryUtils.LOG_ALL);
|
||||
parameters.add("--sparse");
|
||||
|
||||
final GitBekParentFixer parentFixer = GitBekParentFixer.prepare(root, this);
|
||||
GitHistoryUtils.readCommits(myProject, root, userRegistry, parameters, new Consumer<TimedVcsCommit>() {
|
||||
Set<VcsUser> userRegistry = ContainerUtil.newHashSet();
|
||||
Set<VcsRef> refs = ContainerUtil.newHashSet();
|
||||
GitHistoryUtils.readCommits(myProject, root, parameters, new CollectConsumer<VcsUser>(userRegistry),
|
||||
new CollectConsumer<VcsRef>(refs), new Consumer<TimedVcsCommit>() {
|
||||
@Override
|
||||
public void consume(TimedVcsCommit commit) {
|
||||
commitConsumer.consume(parentFixer.fixCommit(commit));
|
||||
}
|
||||
});
|
||||
return new LogDataImpl(refs, userRegistry);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -187,17 +210,11 @@ public class GitLogProvider implements VcsLogProvider {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
|
||||
if (!isRepositoryReady(root)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
GitRepository repository = getRepository(root);
|
||||
repository.update();
|
||||
private Set<VcsRef> readBranches(@NotNull GitRepository repository) {
|
||||
VirtualFile root = repository.getRoot();
|
||||
Collection<GitLocalBranch> localBranches = repository.getBranches().getLocalBranches();
|
||||
Collection<GitRemoteBranch> remoteBranches = repository.getBranches().getRemoteBranches();
|
||||
Collection<VcsRef> refs = new ArrayList<VcsRef>(localBranches.size() + remoteBranches.size());
|
||||
Set<VcsRef> refs = new HashSet<VcsRef>(localBranches.size() + remoteBranches.size());
|
||||
for (GitLocalBranch localBranch : localBranches) {
|
||||
refs.add(
|
||||
myVcsObjectsFactory.createRef(HashImpl.build(localBranch.getHash()), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root));
|
||||
@@ -210,29 +227,6 @@ public class GitLogProvider implements VcsLogProvider {
|
||||
if (currentRevision != null) { // null => fresh repository
|
||||
refs.add(myVcsObjectsFactory.createRef(HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root));
|
||||
}
|
||||
|
||||
refs.addAll(readTags(root));
|
||||
return refs;
|
||||
}
|
||||
|
||||
// TODO this is to be removed when tags will be supported by the GitRepositoryReader
|
||||
private Collection<? extends VcsRef> readTags(@NotNull VirtualFile root) throws VcsException {
|
||||
GitSimpleHandler tagHandler = new GitSimpleHandler(myProject, root, GitCommand.LOG);
|
||||
tagHandler.setSilent(true);
|
||||
tagHandler.addParameters("--tags", "--no-walk", "--format=%H%d" + GitLogParser.RECORD_START_GIT, "--decorate=full");
|
||||
String out = tagHandler.run();
|
||||
Collection<VcsRef> refs = new ArrayList<VcsRef>();
|
||||
try {
|
||||
for (String record : out.split(GitLogParser.RECORD_START)) {
|
||||
if (!StringUtil.isEmptyOrSpaces(record)) {
|
||||
refs.addAll(new RefParser(myVcsObjectsFactory).parseCommitRefs(record.trim(), root));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Error during tags parsing", new Attachment("stack_trace.txt", ExceptionUtil.getThrowableText(e)),
|
||||
new Attachment("git_output.txt", out));
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
@@ -327,7 +321,10 @@ public class GitLogProvider implements VcsLogProvider {
|
||||
}
|
||||
}
|
||||
|
||||
return GitHistoryUtils.readCommits(myProject, root, Consumer.EMPTY_CONSUMER, filterParameters);
|
||||
List<TimedVcsCommit> commits = ContainerUtil.newArrayList();
|
||||
GitHistoryUtils.readCommits(myProject, root, filterParameters, Consumer.EMPTY_CONSUMER, Consumer.EMPTY_CONSUMER,
|
||||
new CollectConsumer<TimedVcsCommit>(commits));
|
||||
return commits;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.intellij.vcs.log.VcsRefType;
|
||||
import com.intellij.vcs.log.impl.SingletonRefGroup;
|
||||
import git4idea.GitBranch;
|
||||
import git4idea.GitRemoteBranch;
|
||||
import git4idea.GitTag;
|
||||
import git4idea.repo.GitBranchTrackInfo;
|
||||
import git4idea.repo.GitRemote;
|
||||
import git4idea.repo.GitRepository;
|
||||
@@ -38,9 +39,10 @@ public class GitRefManager implements VcsLogRefManager {
|
||||
public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, LOCAL_BRANCH_COLOR);
|
||||
public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, REMOTE_BRANCH_COLOR);
|
||||
public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR);
|
||||
public static final VcsRefType OTHER = new SimpleRefType(false, TAG_COLOR);
|
||||
|
||||
// first has the highest priority
|
||||
private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(HEAD, LOCAL_BRANCH, REMOTE_BRANCH, TAG);
|
||||
private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(HEAD, LOCAL_BRANCH, REMOTE_BRANCH, TAG, OTHER);
|
||||
|
||||
// -1 => higher priority
|
||||
public static final Comparator<VcsRefType> REF_TYPE_COMPARATOR = new Comparator<VcsRefType>() {
|
||||
@@ -243,6 +245,23 @@ public class GitRefManager implements VcsLogRefManager {
|
||||
return grouped;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static VcsRefType getRefType(@NotNull String refName) {
|
||||
if (refName.startsWith(GitBranch.REFS_HEADS_PREFIX)) {
|
||||
return LOCAL_BRANCH;
|
||||
}
|
||||
if (refName.startsWith(GitBranch.REFS_REMOTES_PREFIX)) {
|
||||
return REMOTE_BRANCH;
|
||||
}
|
||||
if (refName.startsWith(GitTag.REFS_TAGS_PREFIX)) {
|
||||
return TAG;
|
||||
}
|
||||
if (refName.startsWith("HEAD")) {
|
||||
return HEAD;
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
|
||||
private static class SimpleRefType implements VcsRefType {
|
||||
private final boolean myIsBranch;
|
||||
@NotNull private final Color myColor;
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package git4idea.log;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.CollectConsumer;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.*;
|
||||
@@ -40,7 +40,8 @@ import static git4idea.test.GitExecutor.*;
|
||||
|
||||
public class GitLogProviderTest extends GitSingleRepoTest {
|
||||
|
||||
@NotNull private GitLogProvider myLogProvider;
|
||||
private GitLogProvider myLogProvider;
|
||||
private VcsLogObjectsFactory myObjectsFactory;
|
||||
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@@ -53,6 +54,7 @@ public class GitLogProviderTest extends GitSingleRepoTest {
|
||||
});
|
||||
assertEquals("Incorrect number of GitLogProviders", 1, providers.size());
|
||||
myLogProvider = (GitLogProvider)providers.get(0);
|
||||
myObjectsFactory = ServiceManager.getService(myProject, VcsLogObjectsFactory.class);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
@@ -64,21 +66,51 @@ public class GitLogProviderTest extends GitSingleRepoTest {
|
||||
List<VcsCommitMetadata> expectedLogWithoutTaggedBranch = log();
|
||||
createTaggedBranch();
|
||||
|
||||
Set<VcsRef> noRefs = Collections.emptySet();
|
||||
List<? extends VcsCommitMetadata> block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, false, noRefs, noRefs));
|
||||
assertOrderedEquals(block, expectedLogWithoutTaggedBranch);
|
||||
VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot,new RequirementsImpl(1000, false, Collections.<VcsRef>emptySet()));
|
||||
assertOrderedEquals(block.getCommits(), expectedLogWithoutTaggedBranch);
|
||||
}
|
||||
|
||||
public void test_refresh_with_new_tagged_branch() throws VcsException {
|
||||
prepareSomeHistory();
|
||||
Set<VcsRef> prevRefs = ContainerUtil.newHashSet(myLogProvider.readAllRefs(myProjectRoot));
|
||||
Set<VcsRef> prevRefs = readAllRefs();
|
||||
createTaggedBranch();
|
||||
Set<VcsRef> newRefs = ContainerUtil.newHashSet(myLogProvider.readAllRefs(myProjectRoot));
|
||||
|
||||
List<VcsCommitMetadata> expectedLog = log();
|
||||
List<? extends VcsCommitMetadata> block = myLogProvider.readFirstBlock(myProjectRoot,
|
||||
new RequirementsImpl(1000, true, prevRefs, newRefs));
|
||||
assertSameElements(block, expectedLog);
|
||||
VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
|
||||
assertSameElements(block.getCommits(), expectedLog);
|
||||
}
|
||||
|
||||
public void test_refresh_when_new_tag_moved() throws VcsException {
|
||||
prepareSomeHistory();
|
||||
Set<VcsRef> prevRefs = readAllRefs();
|
||||
git("tag -f ATAG");
|
||||
|
||||
List<VcsCommitMetadata> expectedLog = log();
|
||||
Set<VcsRef> refs = readAllRefs();
|
||||
VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
|
||||
assertSameElements(block.getCommits(), expectedLog);
|
||||
assertSameElements(block.getRefs(), refs);
|
||||
}
|
||||
|
||||
public void test_new_tag_on_old_commit() throws VcsException {
|
||||
prepareSomeHistory();
|
||||
Set<VcsRef> prevRefs = readAllRefs();
|
||||
List<VcsCommitMetadata> log = log();
|
||||
String firstCommit = log.get(log.size() - 1).getId().asString();
|
||||
git("tag NEW_TAG " + firstCommit);
|
||||
|
||||
Set<VcsRef> refs = readAllRefs();
|
||||
VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
|
||||
assertSameElements(block.getRefs(), refs);
|
||||
}
|
||||
|
||||
private Set<VcsRef> readAllRefs() {
|
||||
String[] refs = StringUtil.splitByLines(git("log --branches --tags --no-walk --format=%H%d --decorate=full"));
|
||||
Set<VcsRef> result = ContainerUtil.newHashSet();
|
||||
for (String ref : refs) {
|
||||
result.addAll(new RefParser(myObjectsFactory).parseCommitRefs(ref, myProjectRoot));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void test_all_log_with_tagged_branch() throws VcsException {
|
||||
@@ -87,7 +119,7 @@ public class GitLogProviderTest extends GitSingleRepoTest {
|
||||
List<VcsCommitMetadata> expectedLog = log();
|
||||
List<TimedVcsCommit> collector = ContainerUtil.newArrayList();
|
||||
//noinspection unchecked
|
||||
myLogProvider.readAllHashes(myProjectRoot, Consumer.EMPTY_CONSUMER, new CollectConsumer<TimedVcsCommit>(collector));
|
||||
myLogProvider.readAllHashes(myProjectRoot, new CollectConsumer<TimedVcsCommit>(collector));
|
||||
assertOrderedEquals(expectedLog, collector);
|
||||
}
|
||||
|
||||
|
||||
+11
-21
@@ -4,7 +4,9 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.vcs.log.Hash;
|
||||
import com.intellij.vcs.log.VcsLogObjectsFactory;
|
||||
import com.intellij.vcs.log.VcsRef;
|
||||
import com.intellij.vcs.log.VcsRefType;
|
||||
import com.intellij.vcs.log.impl.HashImpl;
|
||||
import git4idea.branch.GitBranchUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -12,17 +14,11 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: remove when tags are supported by the {@link git4idea.repo.GitRepositoryReader}.
|
||||
*
|
||||
* @author erokhins
|
||||
*/
|
||||
class RefParser {
|
||||
|
||||
private final VcsLogObjectsFactory myFactory;
|
||||
|
||||
public RefParser(VcsLogObjectsFactory factory) {
|
||||
public RefParser(@NotNull VcsLogObjectsFactory factory) {
|
||||
myFactory = factory;
|
||||
}
|
||||
|
||||
@@ -46,28 +42,22 @@ class RefParser {
|
||||
return refs;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getRefName(@NotNull String longRefPath, @NotNull String startPatch) {
|
||||
@NotNull
|
||||
private static String getRefName(@NotNull String longRefPath) {
|
||||
String tagPrefix = "tag: ";
|
||||
if (longRefPath.startsWith(tagPrefix)) {
|
||||
longRefPath = longRefPath.substring(tagPrefix.length());
|
||||
}
|
||||
if (longRefPath.startsWith(startPatch)) {
|
||||
return longRefPath.substring(startPatch.length());
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
return longRefPath;
|
||||
}
|
||||
|
||||
// example input: fb29c80 refs/tags/92.29
|
||||
@Nullable
|
||||
private VcsRef createRef(@NotNull Hash hash, @NotNull String longRefPath, @NotNull VirtualFile root) {
|
||||
String name = getRefName(longRefPath, "refs/tags/");
|
||||
if (name != null) {
|
||||
return myFactory.createRef(hash, name, GitRefManager.TAG, root);
|
||||
}
|
||||
|
||||
return null;
|
||||
String name = getRefName(longRefPath);
|
||||
VcsRefType type = GitRefManager.getRefType(name);
|
||||
assert type != null;
|
||||
return myFactory.createRef(hash, GitBranchUtil.stripRefsPrefix(name), type, root);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,9 +54,9 @@ public class HgHistoryUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<? extends VcsCommitMetadata> loadMetadata(@NotNull final Project project,
|
||||
@NotNull final VirtualFile root, int limit,
|
||||
@NotNull List<String> parameters) throws VcsException {
|
||||
public static List<VcsCommitMetadata> loadMetadata(@NotNull final Project project,
|
||||
@NotNull final VirtualFile root, int limit,
|
||||
@NotNull List<String> parameters) throws VcsException {
|
||||
|
||||
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
|
||||
if (factory == null) {
|
||||
|
||||
@@ -22,9 +22,11 @@ import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsKey;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.CollectConsumer;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.*;
|
||||
import com.intellij.vcs.log.impl.LogDataImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.zmlx.hg4idea.HgNameWithHashInfo;
|
||||
@@ -59,18 +61,23 @@ public class HgLogProvider implements VcsLogProvider {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root,
|
||||
@NotNull Requirements requirements) throws VcsException {
|
||||
return HgHistoryUtil.loadMetadata(myProject, root, requirements.getCommitCount(), Collections.<String>emptyList());
|
||||
public DetailedLogData readFirstBlock(@NotNull VirtualFile root,
|
||||
@NotNull Requirements requirements) throws VcsException {
|
||||
List<VcsCommitMetadata> commits = HgHistoryUtil.loadMetadata(myProject, root, requirements.getCommitCount(),
|
||||
Collections.<String>emptyList());
|
||||
return new LogDataImpl(readAllRefs(root), commits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
|
||||
@NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
List<TimedVcsCommit> commits = HgHistoryUtil.readAllHashes(myProject, root, userRegistry, Collections.<String>emptyList());
|
||||
@NotNull
|
||||
public LogData readAllHashes(@NotNull VirtualFile root, @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
|
||||
Set<VcsUser> userRegistry = ContainerUtil.newHashSet();
|
||||
List<TimedVcsCommit> commits = HgHistoryUtil.readAllHashes(myProject, root, new CollectConsumer<VcsUser>(userRegistry),
|
||||
Collections.<String>emptyList());
|
||||
for (TimedVcsCommit commit : commits) {
|
||||
commitConsumer.consume(commit);
|
||||
}
|
||||
return new LogDataImpl(readAllRefs(root), userRegistry);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -87,16 +94,15 @@ public class HgLogProvider implements VcsLogProvider {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
|
||||
private Set<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
|
||||
myRepositoryManager.waitUntilInitialized();
|
||||
if (myProject.isDisposed()) {
|
||||
return Collections.emptyList();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
HgRepository repository = myRepositoryManager.getRepositoryForRoot(root);
|
||||
if (repository == null) {
|
||||
LOG.error("Repository not found for root " + root);
|
||||
return Collections.emptyList();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
repository.update();
|
||||
@@ -106,7 +112,7 @@ public class HgLogProvider implements VcsLogProvider {
|
||||
Collection<HgNameWithHashInfo> tags = repository.getTags();
|
||||
Collection<HgNameWithHashInfo> localTags = repository.getLocalTags();
|
||||
|
||||
Collection<VcsRef> refs = new ArrayList<VcsRef>(branches.size() + bookmarks.size());
|
||||
Set<VcsRef> refs = new HashSet<VcsRef>(branches.size() + bookmarks.size());
|
||||
|
||||
for (Map.Entry<String, Set<Hash>> entry : branches.entrySet()) {
|
||||
String branchName = entry.getKey();
|
||||
|
||||
Reference in New Issue
Block a user