blob: a61abba49b773fdc8d6c848026734cd00b6336ed [file] [log] [blame]
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.history.wholeTree;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.Ticket;
import com.intellij.util.continuation.ContinuationContext;
import com.intellij.util.continuation.TaskDescriptor;
import com.intellij.util.continuation.Where;
import git4idea.changes.GitChangeUtils;
import git4idea.history.GitHistoryUtils;
import git4idea.history.browser.*;
import org.jetbrains.annotations.NotNull;
import java.util.*;
/**
* @author irengrig
* Date: 2/1/11
* Time: 6:30 PM
*
* We wouldn't include it into growth controller (not many rows loaded)
*/
public class ByRootLoader extends TaskDescriptor {
private final Project myProject;
private final LoaderAndRefresherImpl.MyRootHolder myRootHolder;
private final LowLevelAccess myLowLevelAccess;
private final Mediator myMediator;
private final DetailsCache myDetailsCache;
private CachedRefs mySymbolicRefs;
private final Ticket myTicket;
private final UsersIndex myUsersIndex;
private final Collection<String> myStartingPoints;
@NotNull
private final GitLogFilters myGitLogFilters;
public ByRootLoader(Project project,
LoaderAndRefresherImpl.MyRootHolder rootHolder,
Mediator mediator,
DetailsCache detailsCache,
Ticket ticket, UsersIndex usersIndex, GitLogFilters gitLogFilters, final Collection<String> startingPoints) {
super("Initial checks", Where.POOLED);
myProject = project;
myRootHolder = rootHolder;
myUsersIndex = usersIndex;
myStartingPoints = startingPoints;
myLowLevelAccess = new LowLevelAccessImpl(myProject, myRootHolder.getRoot());
myMediator = mediator;
myDetailsCache = detailsCache;
myTicket = ticket;
myGitLogFilters = gitLogFilters;
}
@Override
public void run(ContinuationContext context) {
/*progress(pi, "Load stashed");
loadStash();*/
//reportStashHead();
loadByHashesAside(context);
}
private void reportStashHead() {
progress("Getting stash head");
try {
myMediator.acceptStashHead(myTicket, myRootHolder.getRoot(), GitHistoryUtils.getStashTop(myProject, myRootHolder.getRoot()));
}
catch (VcsException e) {
myMediator.acceptException(e);
}
}
private void progress(final String progress) {
final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
if (pi != null) {
pi.checkCanceled();
pi.setText(progress);
}
}
private void loadStash() {
// start is not on a branch
if (myStartingPoints != null && (! myStartingPoints.isEmpty())) return;
final List<GitHeavyCommit> details = new ArrayList<GitHeavyCommit>();
final List<CommitI> commits = new ArrayList<CommitI>();
final Map<AbstractHash, String> stashMap = new HashMap<AbstractHash, String>();
final List<List<AbstractHash>> parents = ! myGitLogFilters.haveDisordering() ? new ArrayList<List<AbstractHash>>() : null;
myGitLogFilters.callConsumer(new Consumer<List<ChangesFilter.Filter>>() {
@Override
public void consume(List<ChangesFilter.Filter> filters) {
ProgressManager.checkCanceled();
try {
final List<String> parameters = new ArrayList<String>();
final List<VirtualFile> paths = new ArrayList<VirtualFile>();
ChangesFilter.filtersToParameters(filters, parameters, paths);
final List<Pair<String,GitHeavyCommit>> stash = GitHistoryUtils.loadStashStackAsCommits(myProject, myRootHolder.getRoot(),
mySymbolicRefs, parameters.toArray(new String[parameters.size()]));
if (stash == null) return;
for (Pair<String, GitHeavyCommit> pair : stash) {
ProgressManager.checkCanceled();
final GitHeavyCommit gitCommit = pair.getSecond();
if (stashMap.containsKey(gitCommit.getShortHash())) continue;
details.add(gitCommit);
if (parents != null) {
parents.add(gitCommit.getConvertedParents());
}
commits.add(createCommitI(gitCommit));
stashMap.put(gitCommit.getShortHash(), pair.getFirst());
}
}
catch (VcsException e) {
myMediator.acceptException(e);
}
}
}, true, myRootHolder.getRoot());
myDetailsCache.putStash(myRootHolder.getRoot(), stashMap);
ProgressManager.checkCanceled();
// does not work
//myDetailsCache.acceptAnswer(details, myRootHolder.getRoot());
myMediator.appendResult(myTicket, commits, parents, myRootHolder.getRoot(), false);
}
// if there're filters -> parents shouldn't be loaded
public void loadByHashesAside(final ContinuationContext context) {
final List<CommitI> result = new ArrayList<CommitI>();
final Set<SHAHash> controlSet = new HashSet<SHAHash>();
final List<String> hashes = myGitLogFilters.getPossibleReferencies();
if (hashes == null) return;
progress("Try to load by reference");
myGitLogFilters.callConsumer(new Consumer<List<ChangesFilter.Filter>>() {
@Override
public void consume(List<ChangesFilter.Filter> filters) {
for (String hash : hashes) {
try {
final SHAHash shaHash = GitChangeUtils.commitExists(myProject, myRootHolder.getRoot(), hash, Collections.<VirtualFile>emptyList());
if (shaHash == null) continue;
if (controlSet.contains(shaHash)) continue;
controlSet.add(shaHash);
if (myStartingPoints != null && (! myStartingPoints.isEmpty())) {
boolean matches = false;
for (String startingPoint : myStartingPoints) {
if(GitChangeUtils.isAnyLevelChild(myProject, myRootHolder.getRoot(), shaHash, startingPoint)) {
matches = true;
break;
}
}
if (! matches) continue;
}
final List<GitHeavyCommit> commits = myLowLevelAccess.getCommitDetails(Collections.singletonList(shaHash.getValue()), mySymbolicRefs);
if (commits.isEmpty()) continue;
assert commits.size() == 1;
final GitHeavyCommit commitDetails = commits.get(0);
boolean isOk = true;
for (ChangesFilter.Filter filter : filters) {
isOk = filter.getMemoryFilter().applyInMemory(commitDetails);
if (! isOk) break;
}
if (! isOk) continue;
myDetailsCache.acceptAnswer(commits, myRootHolder.getRoot());
appendCommits(result, commits);
}
catch (VcsException e1) {
continue;
}
}
}
}, false, myRootHolder.getRoot());
if (! result.isEmpty()) {
final StepType stepType = myMediator.appendResult(myTicket, result, null, myRootHolder.getRoot(), true);
// here we react only on "stop", not on "pause"
if (StepType.STOP.equals(stepType)) {
context.cancelEverything();
}
}
}
private void appendCommits(List<CommitI> result, List<GitHeavyCommit> commits) {
for (GitHeavyCommit commit : commits) {
CommitI commitObj = createCommitI(commit);
result.add(commitObj);
}
}
private CommitI createCommitI(GitHeavyCommit commit) {
CommitI commitObj =
new Commit(commit.getShortHash().getString(), commit.getDate().getTime(), myUsersIndex.put(commit.getAuthor()));
commitObj = myRootHolder.decorateByRoot(commitObj);
return commitObj;
}
public CachedRefs initSymbRefs() {
if (mySymbolicRefs == null) {
try {
mySymbolicRefs = myLowLevelAccess.getRefs();
myMediator.reportSymbolicRefs(myTicket, myRootHolder.getRoot(), mySymbolicRefs);
}
catch (VcsException e) {
myMediator.acceptException(e);
}
}
return mySymbolicRefs;
}
public SymbolicRefsI getSymbolicRefs() {
return mySymbolicRefs;
}
public LoaderAndRefresherImpl.MyRootHolder getRootHolder() {
return myRootHolder;
}
}