diff options
Diffstat (limited to 'platform/vcs-log/impl')
9 files changed, 570 insertions, 205 deletions
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogJoiner.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogJoiner.java index 6ed592f10939..fc51742b5318 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogJoiner.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogJoiner.java @@ -30,9 +30,7 @@ import java.util.*; * @author Kirill Likhodedov */ public class VcsLogJoiner<CommitId, Commit extends GraphCommit<CommitId>> { - private final static int BOUND_SAVED_LOG = 10000; - public final static String NOT_ENOUGH_FIRST_BLOCK = "Not enough first block"; public final static String ILLEGAL_DATA_RELOAD_ALL = "All data is illegal - request reload all"; /** @@ -100,12 +98,10 @@ public class VcsLogJoiner<CommitId, Commit extends GraphCommit<CommitId>> { Commit commit = commits.get(lastIndex); if (searchHashes.size() == 0) return lastIndex; - if (lastIndex > BOUND_SAVED_LOG) - throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); searchHashes.remove(commit.getId()); } if (searchHashes.size() != 0) - throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); + throw new VcsLogRefreshNotEnoughDataException(); return lastIndex; } @@ -157,16 +153,13 @@ public class VcsLogJoiner<CommitId, Commit extends GraphCommit<CommitId>> { private void markRealRedNode(@NotNull CommitId node) { if (!currentRed.remove(node)) - throw new IllegalStateException(NOT_ENOUGH_FIRST_BLOCK); + throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); // never happened allRedCommit.add(node); } private int getFirstSaveIndex() { for (int lastIndex = 0; lastIndex < savedLog.size(); lastIndex++) { Commit commit = savedLog.get(lastIndex); - if (lastIndex > BOUND_SAVED_LOG) - throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); - boolean isGreen = currentGreen.contains(commit.getId()); if (isGreen) { currentRed.remove(commit.getId()); @@ -180,7 +173,7 @@ public class VcsLogJoiner<CommitId, Commit extends GraphCommit<CommitId>> { if (currentRed.isEmpty()) return lastIndex + 1; } - throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); + throw new IllegalStateException(ILLEGAL_DATA_RELOAD_ALL); // see VcsLogJoinerTest#illegalStateExceptionTest } public Set<CommitId> getAllRedCommit() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java index 7006408943a8..072e0e26ace1 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java @@ -1,36 +1,36 @@ package com.intellij.vcs.log.data; import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.TimedVcsCommit; +import com.intellij.vcs.log.graph.GraphCommit; import org.jetbrains.annotations.NotNull; import java.util.*; -public class VcsLogMultiRepoJoiner { +public class VcsLogMultiRepoJoiner<CommitId> { @NotNull - public List<? extends TimedVcsCommit> join(@NotNull Collection<List<? extends TimedVcsCommit>> logsFromRepos) { + public List<? extends GraphCommit<CommitId>> join(@NotNull Collection<List<? extends GraphCommit<CommitId>>> logsFromRepos) { if (logsFromRepos.size() == 1) { return logsFromRepos.iterator().next(); } int size = 0; - for (List<? extends TimedVcsCommit> repo : logsFromRepos) { + for (List<? extends GraphCommit<CommitId>> repo : logsFromRepos) { size += repo.size(); } - List<TimedVcsCommit> result = new ArrayList<TimedVcsCommit>(size); + List<GraphCommit<CommitId>> result = new ArrayList<GraphCommit<CommitId>>(size); - Map<TimedVcsCommit, Iterator<? extends TimedVcsCommit>> nextCommits = ContainerUtil.newHashMap(); - for (List<? extends TimedVcsCommit> log : logsFromRepos) { - Iterator<? extends TimedVcsCommit> iterator = log.iterator(); + Map<GraphCommit<CommitId>, Iterator<? extends GraphCommit<CommitId>>> nextCommits = ContainerUtil.newHashMap(); + for (List<? extends GraphCommit<CommitId>> log : logsFromRepos) { + Iterator<? extends GraphCommit<CommitId>> iterator = log.iterator(); if (iterator.hasNext()) { nextCommits.put(iterator.next(), iterator); } } while (!nextCommits.isEmpty()) { - TimedVcsCommit lastCommit = findLatestCommit(nextCommits.keySet()); - Iterator<? extends TimedVcsCommit> iterator = nextCommits.get(lastCommit); + GraphCommit<CommitId> lastCommit = findLatestCommit(nextCommits.keySet()); + Iterator<? extends GraphCommit<CommitId>> iterator = nextCommits.get(lastCommit); result.add(lastCommit); nextCommits.remove(lastCommit); @@ -43,10 +43,10 @@ public class VcsLogMultiRepoJoiner { } @NotNull - private static TimedVcsCommit findLatestCommit(@NotNull Set<TimedVcsCommit> commits) { + private GraphCommit<CommitId> findLatestCommit(@NotNull Set<GraphCommit<CommitId>> commits) { long maxTimeStamp = Long.MIN_VALUE; - TimedVcsCommit lastCommit = null; - for (TimedVcsCommit commit : commits) { + GraphCommit<CommitId> lastCommit = null; + for (GraphCommit<CommitId> commit : commits) { if (commit.getTimestamp() >= maxTimeStamp) { maxTimeStamp = commit.getTimestamp(); lastCommit = commit; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefreshNotEnoughDataException.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefreshNotEnoughDataException.java new file mode 100644 index 000000000000..9863be8d0304 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefreshNotEnoughDataException.java @@ -0,0 +1,25 @@ +/* + * 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.data; + +public class VcsLogRefreshNotEnoughDataException extends RuntimeException { + + private final static String NOT_ENOUGH_FIRST_BLOCK = "Not enough first block"; + + public VcsLogRefreshNotEnoughDataException() { + super(NOT_ENOUGH_FIRST_BLOCK); + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java index 0c25d7f5709d..12996f91c116 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java @@ -96,11 +96,11 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { Map<VirtualFile, Collection<VcsRef>> refs = loadRefsFromVcs(myProviders); Set<VirtualFile> roots = myProviders.keySet(); Map<VirtualFile, VcsLogProvider.Requirements> requirements = prepareSimpleRequirements(roots, myRecentCommitCount); - Map<VirtualFile, List<? extends TimedVcsCommit>> commits = loadRecentCommitsFromVcs(myProviders, requirements, - myUserRegistry, myTopCommitsDetailsCache); - List<? extends TimedVcsCommit> compoundLog = compound(commits.values()); - List<GraphCommit<Integer>> compactedLog = compactCommits(compoundLog, myHashMap); - DataPack dataPack = DataPack.build(compactedLog, new RefsModel(refs, myHashMap.asIndexGetter()), + 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 return dataPack; @@ -152,19 +152,21 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { } @NotNull - private static Map<VirtualFile, List<? extends TimedVcsCommit>> loadRecentCommitsFromVcs(@NotNull Map<VirtualFile, VcsLogProvider> providers, - @NotNull final Map<VirtualFile, VcsLogProvider.Requirements> requirements, - @NotNull final VcsUserRegistryImpl userRegistry, - @NotNull final Map<Hash, VcsCommitMetadata> topCommitsDetailsCache) - throws VcsException { + 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 TimedVcsCommit>> commits = ContainerUtil.newHashMap(); + 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, metadatas); + commits.put(root, compactCommits(metadatas, hashMap)); sw.rootCompleted(root); } }.iterate(providers); @@ -177,9 +179,9 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { * Compounds logs from different repositories into a single multi-repository log. */ @NotNull - private static List<? extends TimedVcsCommit> compound(@NotNull Collection<List<? extends TimedVcsCommit>> commits) { + private static List<? extends GraphCommit<Integer>> compound(@NotNull Collection<List<? extends GraphCommit<Integer>>> commits) { StopWatch sw = StopWatch.start("multi-repo join"); - List<? extends TimedVcsCommit> joined = new VcsLogMultiRepoJoiner().join(commits); + List<? extends GraphCommit<Integer>> joined = new VcsLogMultiRepoJoiner<Integer>().join(commits); sw.report(); return joined; } @@ -192,8 +194,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { @NotNull @Override public GraphCommit<Integer> fun(@NotNull TimedVcsCommit commit) { - return new GraphCommitImpl<Integer>(hashMap.getCommitIndex(commit.getId()), - ContainerUtil.map(commit.getParents(), hashMap.asIndexGetter()), commit.getTimestamp()); + return compactCommit(commit, hashMap); } }); hashMap.flush(); @@ -201,6 +202,12 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { 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 static void storeUsersAndDetails(@NotNull List<? extends VcsCommitMetadata> metadatas, @NotNull VcsUserRegistryImpl userRegistry, @NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache) { for (VcsCommitMetadata detail : metadatas) { @@ -218,9 +225,9 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { private final Map<VirtualFile, LogAndRefs> myLoadedInfos = ContainerUtil.newHashMap(); private class LogAndRefs { - List<? extends TimedVcsCommit> log; + List<? extends GraphCommit<Integer>> log; Collection<VcsRef> refs; - LogAndRefs(Collection<VcsRef> refs, List<? extends TimedVcsCommit> commits) { + LogAndRefs(Collection<VcsRef> refs, List<? extends GraphCommit<Integer>> commits) { this.refs = refs; this.log = commits; } @@ -266,16 +273,16 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { try { if (permanentGraph != null) { loadLogAndRefs(roots, currentRefs, myRecentCommitCount); - List<? extends TimedVcsCommit> compoundLog = compound(ContainerUtil.map(myLoadedInfos.values(), - new Function<LogAndRefs, List<? extends TimedVcsCommit>>() { + List<? extends GraphCommit<Integer>> compoundLog = compound(ContainerUtil.map(myLoadedInfos.values(), + new Function<LogAndRefs, List<? extends GraphCommit<Integer>>>() { @Override - public List<? extends TimedVcsCommit> fun(LogAndRefs refs) { + public List<? extends GraphCommit<Integer>> fun( + LogAndRefs refs) { return refs.log; } })); - List<GraphCommit<Integer>> preparedLog = compactCommits(compoundLog, myHashMap); Map<VirtualFile, Collection<VcsRef>> allNewRefs = getAllNewRefs(myLoadedInfos, currentRefs); - List<GraphCommit<Integer>> joinedFullLog = join(preparedLog, permanentGraph.getAllCommits(), currentRefs, allNewRefs); + List<GraphCommit<Integer>> joinedFullLog = join(compoundLog, permanentGraph.getAllCommits(), currentRefs, allNewRefs); if (joinedFullLog != null) { return DataPack.build(joinedFullLog, new RefsModel(allNewRefs, myHashMap.asIndexGetter()), myHashMap.asIndexGetter(), myHashMap.asHashGetter(), myProviders, true); @@ -310,8 +317,9 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { 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 TimedVcsCommit>> commits = loadRecentCommitsFromVcs(providers, requirements, - myUserRegistry, myTopCommitsDetailsCache); + Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = loadRecentCommitsFromVcs(providers, requirements, + myUserRegistry, myTopCommitsDetailsCache, + myHashMap); for (VirtualFile root : roots) { myLoadedInfos.put(root, new LogAndRefs(refs.get(root), commits.get(root))); } @@ -345,7 +353,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { } @Nullable - private List<GraphCommit<Integer>> join(@NotNull List<GraphCommit<Integer>> recentCommits, @NotNull List<GraphCommit<Integer>> fullLog, + 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) { StopWatch sw = StopWatch.start("joining new commits"); @@ -365,18 +373,20 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { sw.report(); return commits; } + catch (VcsLogRefreshNotEnoughDataException e) { + LOG.error(e); // collecting information : how often this situation happens, do we need to try to load more or can safely reload all + } catch (IllegalStateException e) { - LOG.info(e); - return null; + LOG.error(e); } + return null; } @NotNull private Pair<PermanentGraph<Integer>, Map<VirtualFile, Collection<VcsRef>>> loadFullLog() throws VcsException { StopWatch sw = StopWatch.start("full log reload"); - Collection<List<? extends TimedVcsCommit>> commits = readFullLogFromVcs(); - List<? extends TimedVcsCommit> compoundLog = compound(commits); - List<GraphCommit<Integer>> graphCommits = compactCommits(compoundLog, myHashMap); + 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(), @@ -386,24 +396,31 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { } @NotNull - private Collection<List<? extends TimedVcsCommit>> readFullLogFromVcs() throws VcsException { + private Collection<List<? extends GraphCommit<Integer>>> readFullLogFromVcs() throws VcsException { final StopWatch sw = StopWatch.start("read full log from VCS"); - final Collection<List<? extends TimedVcsCommit>> commits = ContainerUtil.newArrayList(); + final Collection<List<? extends GraphCommit<Integer>>> logs = ContainerUtil.newArrayList(); new ProviderIterator() { @Override void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException { - commits.add(provider.readAllHashes(root, new Consumer<VcsUser>() { + final List<GraphCommit<Integer>> graphCommits = ContainerUtil.newArrayList(); + provider.readAllHashes(root, new Consumer<VcsUser>() { @Override public void consume(@NotNull VcsUser user) { myUserRegistry.addUser(user); } - })); + }, new Consumer<TimedVcsCommit>() { + @Override + public void consume(TimedVcsCommit commit) { + graphCommits.add(compactCommit(commit, myHashMap)); + } + }); + logs.add(graphCommits); sw.rootCompleted(root); } }.iterate(myProviders); myUserRegistry.flush(); sw.report(); - return commits; + return logs; } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java index ec74038a66e4..4f0e44cbd3d2 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/graph/GraphColorManagerImpl.java @@ -58,7 +58,7 @@ public class GraphColorManagerImpl implements GraphColorManager<Integer> { if (isEmptyRefs(refs, headCommit)) { return DEFAULT_COLOR; } - VcsRef firstRef = ContainerUtil.sorted(refs, getRefManager(refs).getComparator()).get(0); + VcsRef firstRef = Collections.min(refs, getRefManager(refs).getComparator()); // TODO dark variant return firstRef.getName().hashCode(); } @@ -67,7 +67,7 @@ public class GraphColorManagerImpl implements GraphColorManager<Integer> { if (refs.isEmpty()) { if (!myErrorWasReported.containsKey(head)) { myErrorWasReported.put(head, head); - LOG.error("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head)); + LOG.warn("No references found at head " + head + " which corresponds to hash " + myHashGetter.fun(head)); } return true; } diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.java deleted file mode 100644 index 63e54b910bfc..000000000000 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.intellij.vcs.log.data; - -import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.TimedCommitParser; -import com.intellij.vcs.log.TimedVcsCommit; -import com.intellij.vcs.log.impl.HashImpl; -import org.junit.Test; - -import java.util.Collection; -import java.util.List; - -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; - -/** - * @author Kirill Likhodedov - */ -public class VcsLogJoinerTest { - - public void runTest(List<String> initial, List<String> updateBlock, List<String> oldRefs, List<String> newRefs, String expected) { - List<TimedVcsCommit> savedLog = TimedCommitParser.log(ArrayUtil.toStringArray(initial)); - List<? extends TimedVcsCommit> firstBlock = TimedCommitParser.log(ArrayUtil.toStringArray(updateBlock)); - Collection<Hash> vcsOldRefs = ContainerUtil.map(oldRefs, new Function<String, Hash>() { - @Override - public Hash fun(String s) { - return HashImpl.build(s); - } - }); - Collection<Hash> vcsNewRefs = ContainerUtil.map(newRefs, new Function<String, Hash>() { - @Override - public Hash fun(String s) { - return HashImpl.build(s); - } - }); - - List<? extends TimedVcsCommit> result = new VcsLogJoiner<Hash, TimedVcsCommit>().addCommits(savedLog, vcsOldRefs, firstBlock, vcsNewRefs).getFirst(); - assertEquals(expected, toStr(result)); - } - - @Test - public void simpleTest() { - runTest( - asList("4|-a2|-a1", "3|-b1|-a", "2|-a1|-a", "1|-a|-"), - asList("5|-f|-b1", "6|-e|-a2"), - asList("a2", "b1"), - asList("f", "e"), - "e, f, a2, b1, a1, a" - ); - } - - @Test - public void oneNodeTest() { - runTest( - asList("3|-a1|-"), - asList("3|-a1|-"), - asList("a1"), - asList("a1"), - "a1" - ); - } - - @Test - public void oneNodeResetTest() { - runTest( - asList("3|-a1|-a2", "2|-a2|-"), - asList("2|-a2|-"), - asList("a2", "a1"), - asList("a2"), - "a2" - ); - } - - @Test - public void oneNodeReset2Test() { - runTest( - asList("3|-a1|-a2", "2|-a2|-"), - asList("2|-a2|-"), - asList("a1"), - asList("a2"), - "a2" - ); - } - - @Test - public void simpleRemoveCommitsTest() { - runTest( - asList("4|-a2|-a1", "3|-b1|-a", "2|-a1|-a", "1|-a|-"), - asList("5|-f|-b1", "6|-e|-a1"), - asList("a2"), - asList("f", "e"), - "e, f, b1, a1, a" - ); - } - - @Test - public void removeCommitsTest() { - runTest( - asList("5|-a5|-a4", "4|-a4|-a2 a3", "3|-a3|-a1", "2|-a2|-a1", "1|-a1|-"), - asList("6|-a6|-a3"), - asList("a5"), - asList("a6"), - "a6, a3, a1" - ); - } - - @Test - public void removeCommitsTest2() { - runTest( - asList("2|-a2|-a1", "1|-a1|-"), - asList("5|-a5|-a4", "3|-a3|-a2", "4|-a4|-a3"), - asList("a2"), - asList("a5"), - "a5, a4, a3, a2, a1" - ); - } - - @Test - public void removeCommitsTest3() { - runTest( - asList("3|-a3|-a2", "2|-a2|-a1", "1|-a1|-"), - asList("2|-a2|-a1"), - asList("a3"), - asList("a2"), - "a2, a1" - ); - } - - private static String toStr(List<? extends TimedVcsCommit> commits) { - StringBuilder s = new StringBuilder(); - for (TimedVcsCommit commit : commits) { - if (s.length() != 0) { - s.append(", "); - } - s.append(commit.getId().asString()); - } - return s.toString(); - } -} diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.kt b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.kt new file mode 100644 index 000000000000..ed4218473984 --- /dev/null +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogJoinerTest.kt @@ -0,0 +1,468 @@ +/* + * 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.data + +import org.junit.Test +import java.util.ArrayList +import com.intellij.vcs.log.TimedCommitParser +import com.intellij.util.ArrayUtil +import com.intellij.vcs.log.impl.HashImpl +import com.intellij.vcs.log.TimedVcsCommit +import com.intellij.vcs.log.Hash +import org.junit.Assert.* + + +class VcsLogJoinerTest { + + class StringArrayBuilder() { + val result = ArrayList<String>() + + fun String.plus() = result.add(this) + + fun Collection<String>.plus() = result.addAll(this) + } + + class TestRunner() { + private var fullLog: List<String>? = null + private var recentCommits: List<String>? = null + private var oldRefs: List<String>? = null + private var newRefs: List<String>? = null + private var expected: String? = null + + private fun build(f: StringArrayBuilder.() -> Unit): List<String> { + val stringArrayBuilder = StringArrayBuilder() + stringArrayBuilder.f() + return stringArrayBuilder.result + } + + fun fullLog(f: StringArrayBuilder.() -> Unit) {fullLog = build(f)} + + fun recentCommits(f: StringArrayBuilder.() -> Unit) {recentCommits = build(f)} + + fun oldRefs(f: StringArrayBuilder.() -> Unit) {oldRefs = build(f)} + + fun newRefs(f: StringArrayBuilder.() -> Unit) {newRefs = build(f)} + + fun expected(f: StringArrayBuilder.() -> Unit) {expected = build(f).join(separator = "\n")} + + fun run() { + val vcsFullLog = TimedCommitParser.log(fullLog!!) + val vcsRecentCommits = TimedCommitParser.log(recentCommits!!) + val vcsOldRefs = oldRefs!!.map { HashImpl.build(it) } + val vcsNewRefs = newRefs!!.map { HashImpl.build(it) } + + val result = VcsLogJoiner<Hash, TimedVcsCommit>().addCommits(vcsFullLog, vcsOldRefs, vcsRecentCommits, vcsNewRefs).getFirst()!! + val actual = result.map { it.getId().asString() }.join(separator = "\n") + assertEquals(expected, actual) + } + } + + fun runTest(f: TestRunner.() -> Unit) { + val testRunner = TestRunner() + testRunner.f() + testRunner.run() + } + + val BIG_TIME = 100000000 + + Test fun simple() { + runTest { + fullLog { + +"4|-a2|-a1" + +"3|-b1|-a" + +"2|-a1|-a" + +"1|-a|-" + } + recentCommits { + +"5|-f|-b1" + +"6|-e|-a2" + } + oldRefs { + +"a2" + +"b1" + } + newRefs { + +"f" + +"e" + } + expected { + +"e" + +"f" + +"a2" + +"b1" + +"a1" + +"a" + } + } + } + + Test fun oneNode() { + runTest { + fullLog { + +"3|-a1|-" + } + recentCommits { + +"3|-a1|-" + } + oldRefs { + +"a1" + } + newRefs { + +"a1" + } + expected { + +"a1" + } + } + } + + Test fun oneNodeReset() { + runTest { + fullLog { + +"3|-a1|-a2" + +"2|-a2|-" + } + recentCommits { + +"2|-a2|-" + } + oldRefs { + +"a2" + +"a1" + } + newRefs { + +"a2" + } + expected { + +"a2" + } + } + } + + Test fun oneNodeReset2() { + runTest { + fullLog { + +"3|-a1|-a2" + +"2|-a2|-" + } + recentCommits { + +"2|-a2|-" + } + oldRefs { + +"a1" + } + newRefs { + +"a2" + } + expected { + +"a2" + } + } + } + + Test fun simpleRemoveCommits() { + runTest { + fullLog { + +"4|-a2|-a1" + +"3|-b1|-a" + +"2|-a1|-a" + +"1|-a|-" + } + recentCommits { + +"5|-f|-b1" + +"6|-e|-a1" + } + oldRefs { + +"a2" + } + newRefs { + +"f" + +"e" + } + expected { + +"e" + +"f" + +"b1" + +"a1" + +"a" + } + } + } + + Test fun removeCommits() { + runTest { + fullLog { + +"5|-a5|-a4" + +"4|-a4|-a2 a3" + +"3|-a3|-a1" + +"2|-a2|-a1" + +"1|-a1|-" + } + recentCommits { + +"6|-a6|-a3" + } + oldRefs { + +"a5" + } + newRefs { + +"a6" + } + expected { + +"a6" + +"a3" + +"a1" + } + } + } + + Test fun removeCommits2() { + runTest { + fullLog { + +"2|-a2|-a1" + +"1|-a1|-" + } + recentCommits { + +"5|-a5|-a4" + +"3|-a3|-a2" + +"4|-a4|-a3" + } + oldRefs { + +"a2" + } + newRefs { + +"a5" + } + expected { + +"a5" + +"a4" + +"a3" + +"a2" + +"a1" + } + } + } + + Test fun removeCommits3() { + runTest { + fullLog { + +"3|-a3|-a2" + +"2|-a2|-a1" + +"1|-a1|-" + } + recentCommits { + +"2|-a2|-a1" + } + oldRefs { + +"a3" + } + newRefs { + +"a2" + } + expected { + +"a2" + +"a1" + } + } + } + + Test fun removeOldBranch() { + runTest { + fullLog { + +"100|-e1|-e10" + +(10..100000).map { "${BIG_TIME - it}|-e${it}|-e${it + 1}" } + +"5|-e100001|-a1" + +"4|-b2|-b1" + +"3|-b1|-a1" + +"1|-a1|-" + } + recentCommits { + +"100|-e1|-e10" + } + oldRefs { + +"e1" + +"b2" + } + newRefs { + "e1" + } + expected { + +"e1" + +(10..100000).map { "e$it" } + +"e100001" + +"a1" + } + } + } + + Test fun addToOldBranch() { + runTest { + fullLog { + +"100|-e1|-e10" + +(10..100000).map { "${BIG_TIME - it}|-e${it}|-e${it + 1}" } + +"5|-e100001|-a1" + +"4|-b2|-b1" + +"3|-b1|-a1" + +"1|-a1|-" + } + recentCommits { + +"50|-b4|-b3" + +"49|-b3|-b2" + } + oldRefs { + +"e1" + +"b2" + } + newRefs { + +"e1" + +"b4" + } + expected { + +"e1" + +(10..100000).map { "e$it" } + +"b4" + +"b3" + +"e100001" + +"b2" + +"b1" + +"a1" + } + } + } + + Test fun removeLongBranch() { + runTest { + fullLog { + +"100|-e1|-e10" + +(10..100000).map { "${BIG_TIME - it}|-e${it}|-e${it + 1}" } + +"5|-e100001|-a1" + +"4|-b2|-b1" + +"3|-b1|-a1" + +"1|-a1|-" + } + recentCommits { + +"50|-b4|-b3" + +"49|-b3|-b2" + } + oldRefs { + +"e1" + +"b2" + } + newRefs { + +"b4" + } + expected { + +"b4" + +"b3" + +"b2" + +"b1" + +"a1" + } + } + } + + Test fun notEnoughDataExceptionTest() { + try { + runTest { + fullLog { + +"1|-a1|-" + } + recentCommits { + +"3|-a3|-a2" + } + oldRefs { + +"a1" + } + newRefs { + +"a3" + } + } + } catch (e: VcsLogRefreshNotEnoughDataException) { + return + } + fail() + } + + Test fun illegalStateExceptionTest() { + try { + runTest { + fullLog { + +"1|-a1|-" + } + recentCommits { + +"1|-a1|-" + } + oldRefs { + +"a1" + +"a2" + } + newRefs { + +"a1" + } + } + } catch (e: IllegalStateException) { + return + } + fail() + } + + Test fun removeParallelBranch() { + runTest { + fullLog { + +"4|-a4|-a1" + +"3|-a3|-a2" + +"2|-a2|-" + +"1|-a1|-" + } + recentCommits { + + } + oldRefs { + +"a4" + +"a3" + } + newRefs { + +"a3" + } + expected { + +"a3" + +"a2" + } + } + } + + Test fun removeAll() { + runTest { + fullLog { + +"4|-a4|-a1" + +"3|-a3|-a2" + +"2|-a2|-" + +"1|-a1|-" + } + recentCommits { + + } + oldRefs { + +"a4" + +"a3" + } + newRefs { + + } + expected { + + } + } + } +} diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java index d3709b2d8f55..850478b048dc 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java @@ -93,9 +93,9 @@ public class TestVcsLogProvider implements VcsLogProvider { return ContainerUtil.map(myCommits.subList(0, requirements.getCommitCount()), myCommitToMetadataConvertor); } - @NotNull @Override - public List<TimedVcsCommit> readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry) throws VcsException { + public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry, + @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException { try { myFullLogSemaphore.acquire(); } @@ -103,7 +103,9 @@ public class TestVcsLogProvider implements VcsLogProvider { throw new RuntimeException(e); } assertRoot(root); - return myCommits; + for (TimedVcsCommit commit : myCommits) { + commitConsumer.consume(commit); + } } private void assertRoot(@NotNull VirtualFile root) { diff --git a/platform/vcs-log/impl/vcs-log-impl.iml b/platform/vcs-log/impl/vcs-log-impl.iml index 5668888806ac..304affc03123 100644 --- a/platform/vcs-log/impl/vcs-log-impl.iml +++ b/platform/vcs-log/impl/vcs-log-impl.iml @@ -21,6 +21,7 @@ <orderEntry type="module" module-name="spellchecker" /> <orderEntry type="module" module-name="vcs-log-graph-api" /> <orderEntry type="module" module-name="testFramework" scope="TEST" /> + <orderEntry type="library" scope="TEST" name="KotlinJavaRuntime" level="project" /> </component> </module> |