mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
git log: correctly do update() for cherry-pick (not allowed for current branch commits, not allowed for merge commits (additional logic required for that)); show stashed commits
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 com.intellij.openapi.vcs;
|
||||
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 2/2/11
|
||||
* Time: 10:11 AM
|
||||
* Cartesian product
|
||||
*/
|
||||
public class CollectionsMultiplier<T> {
|
||||
private List<List<T>> myInner;
|
||||
|
||||
public void add(@Nullable final List<T> list) {
|
||||
if (list == null || list.isEmpty()) return;
|
||||
if (myInner == null) {
|
||||
myInner = Collections.singletonList(list);
|
||||
return;
|
||||
}
|
||||
final List<List<T>> copy = myInner;
|
||||
myInner = new ArrayList<List<T>>();
|
||||
for (T t : list) {
|
||||
for (List<T> existing : copy) {
|
||||
final ArrayList<T> newList = new ArrayList<T>(existing);
|
||||
newList.add(t);
|
||||
myInner.add(newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myInner == null;
|
||||
}
|
||||
|
||||
public void iterateResult(final Consumer<List<T>> consumer) {
|
||||
if (myInner == null) return;
|
||||
for (List<T> list : myInner) {
|
||||
consumer.consume(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
<orderEntry type="library" name="TestNG" level="project" />
|
||||
<orderEntry type="module" module-name="platform-api" />
|
||||
<orderEntry type="library" name="commons-lang" level="project" />
|
||||
<orderEntry type="library" name="Guava" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitSimpleHandler;
|
||||
import git4idea.commands.StringScanner;
|
||||
import git4idea.history.browser.SHAHash;
|
||||
import git4idea.history.wholeTree.CommitI;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -301,10 +300,12 @@ public class GitChangeUtils {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SHAHash commitExists(final Project project, final VirtualFile root, final String anyReference) {
|
||||
public static SHAHash commitExists(final Project project, final VirtualFile root, final String anyReference,
|
||||
final String... parameters) {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
|
||||
h.setNoSSH(true);
|
||||
h.setSilent(true);
|
||||
h.addParameters(parameters);
|
||||
h.addParameters("--max-count=1", "--pretty=%H", "--encoding=UTF-8", "\"" + anyReference + "\"", "--");
|
||||
try {
|
||||
final String output = h.run().trim();
|
||||
@@ -316,6 +317,22 @@ public class GitChangeUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isAnyLevelChild(final Project project, final VirtualFile root, final SHAHash parent,
|
||||
final String anyReferenceChild) {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.MERGE_BASE);
|
||||
h.setNoSSH(true);
|
||||
h.setSilent(true);
|
||||
h.addParameters("\"" + parent.getValue() + "\"","\"" + anyReferenceChild + "\"", "--");
|
||||
try {
|
||||
final String output = h.run().trim();
|
||||
if (StringUtil.isEmptyOrSpaces(output)) return false;
|
||||
return parent.getValue().equals(output.trim());
|
||||
}
|
||||
catch (VcsException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SHAHash commitExistsByComment(final Project project, final VirtualFile root, final String anyReference) {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
|
||||
|
||||
@@ -37,13 +37,17 @@ import com.intellij.util.Consumer;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import git4idea.*;
|
||||
import git4idea.commands.*;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.history.browser.GitCommit;
|
||||
import git4idea.history.browser.SHAHash;
|
||||
import git4idea.history.browser.SymbolicRefs;
|
||||
import git4idea.history.wholeTree.AbstractHash;
|
||||
import git4idea.history.wholeTree.CommitHashPlusParents;
|
||||
import git4idea.ui.GitUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -534,6 +538,36 @@ public class GitHistoryUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static List<Pair<String, GitCommit>> loadStashStackAsCommits(@NotNull Project project, @NotNull VirtualFile root,
|
||||
SymbolicRefs refs, final String... parameters) throws VcsException {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH);
|
||||
GitLogParser parser = new GitLogParser(SHORT_HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, SHORT_PARENTS, REF_NAMES, SHORT_REF_LOG_SELECTOR, SUBJECT, BODY);
|
||||
h.setSilent(true);
|
||||
h.setNoSSH(true);
|
||||
h.addParameters("list");
|
||||
h.addParameters(parameters);
|
||||
h.addParameters(parser.getPretty());
|
||||
parser.parseStatusBeforeName(true);
|
||||
|
||||
String out;
|
||||
try {
|
||||
h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(project, root)));
|
||||
out = h.run();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GitUIUtil.showOperationError(project, e, h.printableCommandLine());
|
||||
return null;
|
||||
}
|
||||
final List<GitLogRecord> gitLogRecords = parser.parse(out);
|
||||
final List<Pair<String, GitCommit>> result = new ArrayList<Pair<String, GitCommit>>();
|
||||
for (GitLogRecord gitLogRecord : gitLogRecords) {
|
||||
final GitCommit gitCommit = createCommit(project, refs, root, gitLogRecord);
|
||||
result.add(new Pair<String, GitCommit>(gitLogRecord.getShortenedRefLog(), gitCommit));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<GitCommit> commitsDetails(Project project,
|
||||
FilePath path, SymbolicRefs refs,
|
||||
final Collection<String> commitsIds) throws VcsException {
|
||||
|
||||
@@ -15,22 +15,9 @@
|
||||
*/
|
||||
package git4idea.history;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.ContentRevision;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import git4idea.GitContentRevision;
|
||||
import git4idea.GitRevisionNumber;
|
||||
import git4idea.history.wholeTree.AbstractHash;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -80,8 +67,8 @@ class GitLogParser {
|
||||
* These are the pieces of information about a commit which we want to get from 'git log'.
|
||||
*/
|
||||
enum GitLogOption {
|
||||
SHORT_HASH("h"), HASH("H"), COMMIT_TIME("ct"), AUTHOR_NAME("an"), AUTHOR_TIME("at"), AUTHOR_EMAIL("ae"), COMMITTER_NAME("cn"), COMMITTER_EMAIL("ce"), SUBJECT("s"), BODY("b"),
|
||||
SHORT_PARENTS("p"), PARENTS("P"), REF_NAMES("d");
|
||||
SHORT_HASH("h"), HASH("H"), COMMIT_TIME("ct"), AUTHOR_NAME("an"), AUTHOR_TIME("at"), AUTHOR_EMAIL("ae"), COMMITTER_NAME("cn"),
|
||||
COMMITTER_EMAIL("ce"), SUBJECT("s"), BODY("b"), SHORT_PARENTS("p"), PARENTS("P"), REF_NAMES("d"), SHORT_REF_LOG_SELECTOR("gd");
|
||||
|
||||
private String myPlaceholder;
|
||||
private GitLogOption(String placeholder) { myPlaceholder = placeholder; }
|
||||
|
||||
@@ -31,12 +31,7 @@ import git4idea.GitUtil;
|
||||
import git4idea.history.wholeTree.AbstractHash;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static git4idea.history.GitLogParser.GitLogOption.*;
|
||||
|
||||
@@ -90,6 +85,7 @@ class GitLogRecord {
|
||||
String getCommitterEmail() { return lookup(COMMITTER_EMAIL); }
|
||||
String getSubject() { return lookup(SUBJECT); }
|
||||
String getBody() { return lookup(BODY); }
|
||||
String getShortenedRefLog() { return lookup(SHORT_REF_LOG_SELECTOR); }
|
||||
|
||||
// access methods with some formatting or conversion
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.changes.FilePathsHelper;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import git4idea.GitUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -31,6 +32,21 @@ import java.util.regex.Pattern;
|
||||
|
||||
public class ChangesFilter {
|
||||
|
||||
public static void filtersToParameters(Collection<Filter> filters, List<String> parameters) {
|
||||
for (Filter filter : filters) {
|
||||
filter.getCommandParametersFilter().applyToCommandLine(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] filtersToParameterArray(Collection<Filter> filters) {
|
||||
if (filters == null || filters.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
final ArrayList<String> strings = new ArrayList<String>();
|
||||
for (Filter filter : filters) {
|
||||
filter.getCommandParametersFilter().applyToCommandLine(strings);
|
||||
}
|
||||
return strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
|
||||
public abstract static class Merger {
|
||||
private final Collection<MemoryFilter> myFilters;
|
||||
private MemoryFilter myResult;
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
package git4idea.history.browser;
|
||||
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import git4idea.history.wholeTree.AbstractHash;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -212,4 +214,13 @@ public class GitCommit {
|
||||
public void setOnTracked(boolean onTracked) {
|
||||
myOnTracked = onTracked;
|
||||
}
|
||||
|
||||
public List<AbstractHash> getConvertedParents() {
|
||||
return ObjectsConvertor.convert(getParentsHashes(), new Convertor<String, AbstractHash>() {
|
||||
@Override
|
||||
public AbstractHash convert(String o) {
|
||||
return AbstractHash.create(o);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,7 @@ public class LowLevelAccessImpl implements LowLevelAccess {
|
||||
final AsynchConsumer<CommitHashPlusParents> consumer,
|
||||
Getter<Boolean> isCanceled, int useMaxCnt) throws VcsException {
|
||||
final List<String> parameters = new ArrayList<String>();
|
||||
for (ChangesFilter.Filter filter : filters) {
|
||||
filter.getCommandParametersFilter().applyToCommandLine(parameters);
|
||||
}
|
||||
ChangesFilter.filtersToParameters(filters, parameters);
|
||||
|
||||
if (! startingPoints.isEmpty()) {
|
||||
for (String startingPoint : startingPoints) {
|
||||
@@ -110,6 +108,13 @@ public class LowLevelAccessImpl implements LowLevelAccess {
|
||||
refs.setTrackedRemote(current.getTrackedRemoteName(myProject, myRoot));
|
||||
}
|
||||
refs.setUsername(GitConfigUtil.getValue(myProject, myRoot, GitConfigUtil.USER_NAME));
|
||||
// todo
|
||||
/*GitStashUtils.loadStashStack(myProject, myRoot, new Consumer<StashInfo>() {
|
||||
@Override
|
||||
public void consume(StashInfo stashInfo) {
|
||||
|
||||
}
|
||||
});*/
|
||||
return refs;
|
||||
}
|
||||
|
||||
@@ -125,10 +130,8 @@ public class LowLevelAccessImpl implements LowLevelAccess {
|
||||
parameters.add("--max-count=" + useMaxCnt);
|
||||
}
|
||||
|
||||
for (ChangesFilter.Filter filter : filters) {
|
||||
filter.getCommandParametersFilter().applyToCommandLine(parameters);
|
||||
}
|
||||
|
||||
ChangesFilter.filtersToParameters(filters, parameters);
|
||||
|
||||
if (! startingPoints.isEmpty()) {
|
||||
for (String startingPoint : startingPoints) {
|
||||
parameters.add(startingPoint);
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.util.Consumer;
|
||||
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 SymbolicRefs mySymbolicRefs;
|
||||
private final Mediator.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,
|
||||
Mediator.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) {
|
||||
final ProgressIndicator pi = ProgressManager.getInstance().getProgressIndicator();
|
||||
progress(pi, "Load branches and tags");
|
||||
initSymbRefs();
|
||||
progress(pi, "Load stashed");
|
||||
loadStash();
|
||||
progress(pi, "Try to load by reference");
|
||||
loadByHashesAside(context);
|
||||
}
|
||||
|
||||
private void progress(final ProgressIndicator pi, final String progress) {
|
||||
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<GitCommit> details = new ArrayList<GitCommit>();
|
||||
final List<CommitI> commits = new ArrayList<CommitI>();
|
||||
final Map<AbstractHash, String> stashMap = new HashMap<AbstractHash, String>();
|
||||
final List<List<AbstractHash>> parents = myGitLogFilters.isEmpty() ? new ArrayList<List<AbstractHash>>() : null;
|
||||
|
||||
myGitLogFilters.callConsumer(new Consumer<List<ChangesFilter.Filter>>() {
|
||||
@Override
|
||||
public void consume(List<ChangesFilter.Filter> filters) {
|
||||
try {
|
||||
final List<Pair<String,GitCommit>> stash = GitHistoryUtils.loadStashStackAsCommits(myProject, myRootHolder.getRoot(),
|
||||
mySymbolicRefs, ChangesFilter.filtersToParameterArray(filters));
|
||||
if (stash == null) return;
|
||||
for (Pair<String, GitCommit> pair : stash) {
|
||||
final GitCommit 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);
|
||||
|
||||
myDetailsCache.putStash(myRootHolder.getRoot(), stashMap);
|
||||
// does not work
|
||||
//myDetailsCache.acceptAnswer(details, myRootHolder.getRoot());
|
||||
myMediator.appendResult(myTicket, commits, parents);
|
||||
}
|
||||
|
||||
// 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;
|
||||
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, ChangesFilter.filtersToParameterArray(filters));
|
||||
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<GitCommit> commits = myLowLevelAccess.getCommitDetails(Collections.singletonList(shaHash.getValue()), mySymbolicRefs);
|
||||
if (commits.isEmpty()) continue;
|
||||
|
||||
myDetailsCache.acceptAnswer(commits, myRootHolder.getRoot());
|
||||
appendCommits(result, commits);
|
||||
}
|
||||
catch (VcsException e1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
if (! result.isEmpty()) {
|
||||
final StepType stepType = myMediator.appendResult(myTicket, result, null);
|
||||
// here we react only on "stop", not on "pause"
|
||||
if (StepType.STOP.equals(stepType)) {
|
||||
context.cancelEverything();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendCommits(List<CommitI> result, List<GitCommit> commits) {
|
||||
for (GitCommit commit : commits) {
|
||||
CommitI commitObj = createCommitI(commit);
|
||||
result.add(commitObj);
|
||||
}
|
||||
}
|
||||
|
||||
private CommitI createCommitI(GitCommit commit) {
|
||||
CommitI commitObj =
|
||||
new Commit(commit.getShortHash().getString(), commit.getDate().getTime(), myUsersIndex.put(commit.getAuthor()));
|
||||
commitObj = myRootHolder.decorateByRoot(commitObj);
|
||||
return commitObj;
|
||||
}
|
||||
|
||||
private void initSymbRefs() {
|
||||
if (mySymbolicRefs == null) {
|
||||
try {
|
||||
mySymbolicRefs = myLowLevelAccess.getRefs();
|
||||
myMediator.reportSymbolicRefs(myTicket, myRootHolder.getRoot(), mySymbolicRefs);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
myMediator.acceptException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SymbolicRefs getSymbolicRefs() {
|
||||
return mySymbolicRefs;
|
||||
}
|
||||
}
|
||||
@@ -20,26 +20,30 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.SLRUMap;
|
||||
import git4idea.history.browser.GitCommit;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
*/
|
||||
public class DetailsCache {
|
||||
private final static int ourSize = 400;
|
||||
private boolean mySomethingIsMissing;
|
||||
private final SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit> myCache;
|
||||
private final SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>> myBranches;
|
||||
private final DetailsLoaderImpl myDetailsLoader;
|
||||
private final ModalityState myModalityState;
|
||||
private AbstractCalledLater myRefresh;
|
||||
private final Map<VirtualFile, Map<AbstractHash, String>> myStash;
|
||||
private final Object myLock;
|
||||
|
||||
public DetailsCache(final Project project, final UIRefresh uiRefresh, final DetailsLoaderImpl detailsLoader, final ModalityState modalityState) {
|
||||
myDetailsLoader = detailsLoader;
|
||||
myModalityState = modalityState;
|
||||
myStash = new HashMap<VirtualFile, Map<AbstractHash,String>>();
|
||||
myRefresh = new AbstractCalledLater(project, myModalityState) {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -47,7 +51,6 @@ public class DetailsCache {
|
||||
}
|
||||
};
|
||||
myLock = new Object();
|
||||
mySomethingIsMissing = false;
|
||||
myCache = new SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit>(ourSize, 50);
|
||||
myBranches = new SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>>(10, 10);
|
||||
}
|
||||
@@ -60,9 +63,6 @@ public class DetailsCache {
|
||||
|
||||
public void acceptQuestion(final MultiMap<VirtualFile,AbstractHash> hashes) {
|
||||
if (hashes.isEmpty()) return;
|
||||
synchronized (myLock) {
|
||||
mySomethingIsMissing = ! hashes.isEmpty();
|
||||
}
|
||||
myDetailsLoader.load(hashes);
|
||||
}
|
||||
|
||||
@@ -71,9 +71,6 @@ public class DetailsCache {
|
||||
for (GitCommit commit : commits) {
|
||||
myCache.put(new Pair<VirtualFile, AbstractHash>(root, commit.getShortHash()), commit);
|
||||
}
|
||||
// if (mySomethingIsMissing) {
|
||||
mySomethingIsMissing = false;
|
||||
// }
|
||||
}
|
||||
myRefresh.callMe();
|
||||
}
|
||||
@@ -94,9 +91,25 @@ public class DetailsCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetBranchesCache() {
|
||||
public void resetAsideCaches() {
|
||||
synchronized (myLock) {
|
||||
myBranches.clear();
|
||||
myStash.clear();
|
||||
myCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void putStash(final VirtualFile root, final Map<AbstractHash, String> stash) {
|
||||
synchronized (myLock) {
|
||||
myStash.put(root, stash);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getStashName(final VirtualFile root, final AbstractHash hash) {
|
||||
synchronized (myLock) {
|
||||
final Map<AbstractHash, String> map = myStash.get(root);
|
||||
return map == null ? null : map.get(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.google.common.collect.Sets;
|
||||
import com.intellij.util.Consumer;
|
||||
import git4idea.history.browser.ChangesFilter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 2/1/11
|
||||
* Time: 7:27 PM
|
||||
*/
|
||||
public class GitLogFilters {
|
||||
@Nullable
|
||||
private final ChangesFilter.Comment myCommentFilter;
|
||||
@Nullable
|
||||
private final Set<ChangesFilter.Filter> myCommitterFilters;
|
||||
@Nullable
|
||||
private final Set<ChangesFilter.Filter> myStructureFilters;
|
||||
@Nullable
|
||||
private final List<String> myPossibleReferencies;
|
||||
|
||||
public GitLogFilters() {
|
||||
this(null, null, null, null);
|
||||
}
|
||||
|
||||
public GitLogFilters(@Nullable ChangesFilter.Comment commentFilter,
|
||||
@Nullable Set<ChangesFilter.Filter> committerFilters,
|
||||
@Nullable Set<ChangesFilter.Filter> structureFilters, @Nullable List<String> possibleReferencies) {
|
||||
myCommentFilter = commentFilter;
|
||||
myCommitterFilters = committerFilters;
|
||||
myStructureFilters = structureFilters;
|
||||
myPossibleReferencies = possibleReferencies;
|
||||
}
|
||||
|
||||
public void callConsumer(final Consumer<List<ChangesFilter.Filter>> consumer, boolean takeComment) {
|
||||
final List<Set<ChangesFilter.Filter>> filters = new ArrayList<Set<ChangesFilter.Filter>>();
|
||||
if (takeComment && myCommentFilter != null) {
|
||||
filters.add(Collections.<ChangesFilter.Filter, ChangesFilter.Filter>singletonMap(myCommentFilter, myCommentFilter).keySet());
|
||||
}
|
||||
if (myCommitterFilters != null) {
|
||||
filters.add(myCommitterFilters);
|
||||
}
|
||||
if (myStructureFilters != null) {
|
||||
filters.add(myStructureFilters);
|
||||
}
|
||||
final Set<List<ChangesFilter.Filter>> cartesian = Sets.cartesianProduct(filters);
|
||||
if (cartesian.isEmpty()) {
|
||||
consumer.consume(Collections.<ChangesFilter.Filter>emptyList());
|
||||
} else {
|
||||
for (List<ChangesFilter.Filter> list : cartesian) {
|
||||
consumer.consume(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ChangesFilter.Comment getCommentFilter() {
|
||||
return myCommentFilter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<ChangesFilter.Filter> getCommitterFilters() {
|
||||
return myCommitterFilters;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<ChangesFilter.Filter> getStructureFilters() {
|
||||
return myStructureFilters;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return myCommentFilter == null && (myCommitterFilters == null || myCommitterFilters.isEmpty()) &&
|
||||
(myStructureFilters == null || myStructureFilters.isEmpty());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getPossibleReferencies() {
|
||||
return myPossibleReferencies;
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,7 @@ public class GitLogUI implements Disposable {
|
||||
if (gitCommit == null) return;
|
||||
final List<String> branches = myDetailsCache.getBranches(root, commit.getHash());
|
||||
if (branches != null) {
|
||||
myDetails.putBranches(gitCommit, branches);
|
||||
myDetails.putBranches(root, gitCommit, branches);
|
||||
}
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
@@ -383,7 +383,7 @@ public class GitLogUI implements Disposable {
|
||||
if (myDetails.isMissingBranchesInfo() && afterRows.length == 1 && afterRows[0] == rows[0]) {
|
||||
final CommitI afterCommit = myTableModel.getCommitAt(rows[0]);
|
||||
if (afterCommit.holdsDecoration() || (! afterCommit.equals(commit))) return;
|
||||
myDetails.putBranches(gitCommit, branches);
|
||||
myDetails.putBranches(root, gitCommit, branches);
|
||||
}
|
||||
}
|
||||
}, ModalityState.NON_MODAL, myProject.getDisposed());
|
||||
@@ -888,22 +888,27 @@ public class GitLogUI implements Disposable {
|
||||
}
|
||||
|
||||
private Color getLogicBackground(final boolean isSelected, final int row) {
|
||||
final Color bkgColor;
|
||||
Color bkgColor;
|
||||
final CommitI commitAt = myTableModel.getCommitAt(row);
|
||||
GitCommit gitCommit = null;
|
||||
VirtualFile root = null;
|
||||
if (commitAt != null & (! commitAt.holdsDecoration())) {
|
||||
gitCommit = myDetailsCache.convert(commitAt.selectRepository(myRootsUnderVcs), commitAt.getHash());
|
||||
root = commitAt.selectRepository(myRootsUnderVcs);
|
||||
gitCommit = myDetailsCache.convert(root, commitAt.getHash());
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
bkgColor = UIUtil.getTableSelectionBackground();
|
||||
} else {
|
||||
if (gitCommit != null && gitCommit.isOnLocal() && gitCommit.isOnTracked()) {
|
||||
bkgColor = Colors.commonThisBranch;
|
||||
} else if (gitCommit != null && gitCommit.isOnLocal()) {
|
||||
bkgColor = Colors.ownThisBranch;
|
||||
} else {
|
||||
bkgColor = UIUtil.getTableBackground();
|
||||
bkgColor = UIUtil.getTableBackground();
|
||||
if (gitCommit != null) {
|
||||
if (myDetailsCache.getStashName(root, gitCommit.getShortHash()) != null) {
|
||||
bkgColor = Colors.stashed;
|
||||
} else if (gitCommit.isOnLocal() && gitCommit.isOnTracked()) {
|
||||
bkgColor = Colors.commonThisBranch;
|
||||
} else if (gitCommit.isOnLocal()) {
|
||||
bkgColor = Colors.ownThisBranch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bkgColor;
|
||||
@@ -986,7 +991,7 @@ public class GitLogUI implements Disposable {
|
||||
private void reloadRequest() {
|
||||
myState = StepType.CONTINUE;
|
||||
final int was = myTableModel.getRowCount();
|
||||
myDetailsCache.resetBranchesCache();
|
||||
myDetailsCache.resetAsideCaches();
|
||||
final Collection<String> startingPoints = mySelectedBranch == null ? Collections.<String>emptyList() : Collections.singletonList(mySelectedBranch);
|
||||
myDescriptionRenderer.resetIcons();
|
||||
final boolean commentFilterEmpty = StringUtil.isEmptyOrSpaces(myPreviousFilter);
|
||||
@@ -995,18 +1000,18 @@ public class GitLogUI implements Disposable {
|
||||
|
||||
if (commentFilterEmpty && (myUserFilterI.myFilter == null)) {
|
||||
myUsersSearchContext.clear();
|
||||
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, Collections.<Collection<ChangesFilter.Filter>>emptyList(), null);
|
||||
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, new GitLogFilters());
|
||||
} else {
|
||||
final List<Collection<ChangesFilter.Filter>> filters = new ArrayList<Collection<ChangesFilter.Filter>>();
|
||||
|
||||
ChangesFilter.Comment comment = null;
|
||||
if (! commentFilterEmpty) {
|
||||
final Pair<String, List<String>> preparse = preparse(myPreviousFilter);
|
||||
final String first = preparse.getFirst();
|
||||
filters.add(Collections.<ChangesFilter.Filter>singletonList(new ChangesFilter.Comment(first)));
|
||||
comment = new ChangesFilter.Comment(first);
|
||||
}
|
||||
Set<ChangesFilter.Filter> userFilters = null;
|
||||
if (myUserFilterI.myFilter != null) {
|
||||
final String[] strings = myUserFilterI.myFilter.split(",");
|
||||
final List<ChangesFilter.Filter> userFilters = new ArrayList<ChangesFilter.Filter>();
|
||||
userFilters = new HashSet<ChangesFilter.Filter>();
|
||||
for (String string : strings) {
|
||||
string = string.trim();
|
||||
if (string.length() == 0) continue;
|
||||
@@ -1014,10 +1019,11 @@ public class GitLogUI implements Disposable {
|
||||
final String regexp = StringUtil.escapeToRegexp(string);
|
||||
userFilters.add(new ChangesFilter.Committer(regexp));
|
||||
}
|
||||
filters.add(userFilters);
|
||||
}
|
||||
|
||||
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, filters, commentFilterEmpty ? null : myPreviousFilter.split("[\\s]"));
|
||||
final List<String> possibleReferencies = commentFilterEmpty ? null : Arrays.asList(myPreviousFilter.split("[\\s]"));
|
||||
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, new GitLogFilters(comment, userFilters, null,
|
||||
possibleReferencies));
|
||||
}
|
||||
updateMoreVisibility();
|
||||
selectionChanged();
|
||||
@@ -1031,6 +1037,7 @@ public class GitLogUI implements Disposable {
|
||||
Color local = new Color(117,238,199);
|
||||
Color ownThisBranch = new Color(198,255,226);
|
||||
Color commonThisBranch = new Color(223,223,255);
|
||||
Color stashed = new Color(225,225,225);
|
||||
}
|
||||
|
||||
private class MySpecificDetails {
|
||||
@@ -1064,9 +1071,9 @@ public class GitLogUI implements Disposable {
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public void putBranches(final GitCommit commit, final List<String> branches) {
|
||||
public void putBranches(VirtualFile root, final GitCommit commit, final List<String> branches) {
|
||||
myMissingBranchesInfo = branches == null;
|
||||
myJEditorPane.setText(parseDetails(commit, branches));
|
||||
myJEditorPane.setText(parseDetails(root, commit, branches));
|
||||
}
|
||||
|
||||
public boolean isMissingBranchesInfo() {
|
||||
@@ -1097,11 +1104,11 @@ public class GitLogUI implements Disposable {
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
myMarksPanel.repaint();
|
||||
myJEditorPane.setText(parseDetails(commit, branches));
|
||||
myJEditorPane.setText(parseDetails(root, commit, branches));
|
||||
}
|
||||
}
|
||||
|
||||
private String parseDetails(final GitCommit c, final List<String> branches) {
|
||||
private String parseDetails(VirtualFile root, final GitCommit c, final List<String> branches) {
|
||||
final String hash = new HtmlHighlighter(c.getHash().getValue()).getResult();
|
||||
final String author = new HtmlHighlighter(c.getAuthor()).getResult();
|
||||
final String committer = new HtmlHighlighter(c.getCommitter()).getResult();
|
||||
@@ -1114,14 +1121,19 @@ public class GitLogUI implements Disposable {
|
||||
});
|
||||
|
||||
final StringBuilder sb = new StringBuilder().append("<html><head>").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()))
|
||||
.append("</head><body><table><tr valign=\"top\"><td><i>Hash:</i></td><td>").append(
|
||||
hash).append("</td></tr>" + "<tr valign=\"top\"><td><i>Author:</i></td><td>")
|
||||
.append("</head><body><table>");
|
||||
final String stashName = myDetailsCache.getStashName(root, c.getShortHash());
|
||||
if (! StringUtil.isEmptyOrSpaces(stashName)) {
|
||||
sb.append("<tr valign=\"top\"><td><b>").append(stashName).append("</b></td><td></td></tr>");
|
||||
}
|
||||
sb.append("<tr valign=\"top\"><td><i>Hash:</i></td><td>").append(
|
||||
hash).append("</td></tr>" + "<tr valign=\"top\"><td><i>Author:</i></td><td>")
|
||||
.append(author).append(" (").append(c.getAuthorEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getAuthorTime()))
|
||||
.append("</td></tr>" + "<tr valign=\"top\"><td><i>Commiter:</i></td><td>")
|
||||
.append(committer).append(" (").append(c.getComitterEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getDate())).append(
|
||||
"</td></tr>" + "<tr valign=\"top\"><td><i>Description:</i></td><td><b>")
|
||||
"</td></tr>" + "<tr valign=\"top\"><td><i>Description:</i></td><td><b>")
|
||||
.append(comment).append("</b></td></tr>");
|
||||
sb.append("<tr valign=\"top\"><td><i>Contained in branches:<i></td><td>");
|
||||
if (branches != null && (! branches.isEmpty())) {
|
||||
@@ -1232,8 +1244,26 @@ public class GitLogUI implements Disposable {
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
final boolean enabled = getSelectedCommitsAndCheck() != null;
|
||||
e.getPresentation().setEnabled(enabled);
|
||||
e.getPresentation().setEnabled(enabled());
|
||||
}
|
||||
|
||||
private boolean enabled() {
|
||||
final MultiMap<VirtualFile, GitCommit> commitsAndCheck = getSelectedCommitsAndCheck();
|
||||
if (commitsAndCheck == null) return false;
|
||||
for (VirtualFile root : commitsAndCheck.keySet()) {
|
||||
final SymbolicRefs refs = myRefs.get(root);
|
||||
final String currentBranch = refs == null ? null : (refs.getCurrent() == null ? null : refs.getCurrent().getName());
|
||||
if (currentBranch == null) continue;
|
||||
final Collection<GitCommit> commits = commitsAndCheck.get(root);
|
||||
for (GitCommit commit : commits) {
|
||||
if (commit.getParentsHashes().size() > 1) return false;
|
||||
final List<String> branches = myDetailsCache.getBranches(root, commit.getShortHash());
|
||||
if (branches != null && branches.contains(currentBranch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ public class LoadAlgorithm {
|
||||
|
||||
private final Project myProject;
|
||||
private final List<LoaderAndRefresher<CommitHashPlusParents>> myLoaders;
|
||||
private final List<String> myAbstractHashs;
|
||||
private final List<ByRootLoader> myShortLoaders;
|
||||
private final Continuation myContinuation;
|
||||
|
||||
public LoadAlgorithm(final Project project, final List<LoaderAndRefresher<CommitHashPlusParents>> loaders, final List<String> abstractHashs) {
|
||||
public LoadAlgorithm(final Project project, final List<LoaderAndRefresher<CommitHashPlusParents>> loaders, final List<ByRootLoader> shortLoaders) {
|
||||
myProject = project;
|
||||
myLoaders = loaders;
|
||||
myAbstractHashs = abstractHashs;
|
||||
myShortLoaders = shortLoaders;
|
||||
myContinuation = new Continuation(myProject, false);
|
||||
}
|
||||
|
||||
@@ -45,14 +45,14 @@ public class LoadAlgorithm {
|
||||
final ContinuationContext.GatheringContinuationContext initContext =
|
||||
new ContinuationContext.GatheringContinuationContext();
|
||||
|
||||
if (myAbstractHashs != null) {
|
||||
initContext.last(new TryHashes());
|
||||
}
|
||||
for (LoaderAndRefresher<CommitHashPlusParents> loader : myLoaders) {
|
||||
final LoaderFactory factory = new LoaderFactory(loader);
|
||||
final State state = new State(factory);
|
||||
state.scheduleSelf(initContext);
|
||||
}
|
||||
for (ByRootLoader shortLoader : myShortLoaders) {
|
||||
initContext.next(shortLoader);
|
||||
}
|
||||
myContinuation.run(initContext.getList());
|
||||
}
|
||||
|
||||
@@ -67,19 +67,6 @@ public class LoadAlgorithm {
|
||||
myContinuation.resume();
|
||||
}
|
||||
|
||||
private class TryHashes extends TaskDescriptor {
|
||||
private TryHashes() {
|
||||
super("Try load by hashes", Where.POOLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
for (LoaderAndRefresher loader : myLoaders) {
|
||||
loader.loadByHashesAside(myAbstractHashs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoadTaskDescriptor extends TaskDescriptor {
|
||||
protected final State myState;
|
||||
private final LoaderAndRefresher<CommitHashPlusParents> myLoader;
|
||||
|
||||
@@ -16,10 +16,13 @@ import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import git4idea.history.NewGitUsersComponent;
|
||||
import git4idea.history.browser.ChangesFilter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
@@ -47,13 +50,13 @@ public class LoadController implements Loader {
|
||||
public void loadSkeleton(final Mediator.Ticket ticket,
|
||||
final RootsHolder rootsHolder,
|
||||
final Collection<String> startingPoints,
|
||||
final Collection<Collection<ChangesFilter.Filter>> filters,
|
||||
String[] possibleHashes,
|
||||
final GitLogFilters filters,
|
||||
final LoadGrowthController loadGrowthController) {
|
||||
if (myPreviousAlgorithm != null) {
|
||||
myPreviousAlgorithm.stop();
|
||||
}
|
||||
final List<LoaderAndRefresher<CommitHashPlusParents>> list = new ArrayList<LoaderAndRefresher<CommitHashPlusParents>>();
|
||||
final List<ByRootLoader> shortLoaders = new ArrayList<ByRootLoader>();
|
||||
final List<VirtualFile> roots = rootsHolder.getRoots();
|
||||
int i = 0;
|
||||
for (VirtualFile root : roots) {
|
||||
@@ -61,49 +64,23 @@ public class LoadController implements Loader {
|
||||
new LoaderAndRefresherImpl.OneRootHolder(root) :
|
||||
new LoaderAndRefresherImpl.ManyCaseHolder(i, rootsHolder);
|
||||
|
||||
if (filters.isEmpty()) {
|
||||
final LoaderAndRefresherImpl loaderAndRefresher =
|
||||
new LoaderAndRefresherImpl(ticket, Collections.<ChangesFilter.Filter>emptyList(), myMediator, startingPoints, myDetailsCache,
|
||||
myProject, rootHolder, myUsersIndex, loadGrowthController.getId());
|
||||
list.add(loaderAndRefresher);
|
||||
} else {
|
||||
Collection<Collection<ChangesFilter.Filter>> reordered = new ArrayList<Collection<ChangesFilter.Filter>>();
|
||||
final Iterator<Collection<ChangesFilter.Filter>> iterator = filters.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
final Collection<ChangesFilter.Filter> first = iterator.next();
|
||||
for (ChangesFilter.Filter filter : first) {
|
||||
final ArrayList<ChangesFilter.Filter> newList = new ArrayList<ChangesFilter.Filter>();
|
||||
newList.add(filter);
|
||||
reordered.add(newList);
|
||||
}
|
||||
}
|
||||
while (iterator.hasNext()) {
|
||||
final Collection<ChangesFilter.Filter> next = iterator.next();
|
||||
final Collection<Collection<ChangesFilter.Filter>> reorderedCopy = reordered;
|
||||
reordered = new ArrayList<Collection<ChangesFilter.Filter>>();
|
||||
for (ChangesFilter.Filter filter : next) {
|
||||
for (Collection<ChangesFilter.Filter> filterCollection : reorderedCopy) {
|
||||
final ArrayList<ChangesFilter.Filter> newList = new ArrayList<ChangesFilter.Filter>(filterCollection);
|
||||
newList.add(filter);
|
||||
reordered.add(newList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Collection<ChangesFilter.Filter> filterCollection : reordered) {
|
||||
filters.callConsumer(new Consumer<List<ChangesFilter.Filter>>() {
|
||||
@Override
|
||||
public void consume(final List<ChangesFilter.Filter> filters) {
|
||||
final LoaderAndRefresherImpl loaderAndRefresher =
|
||||
new LoaderAndRefresherImpl(ticket, filterCollection, myMediator, startingPoints, myDetailsCache, myProject, rootHolder, myUsersIndex,
|
||||
new LoaderAndRefresherImpl(ticket, filters, myMediator, startingPoints, myDetailsCache, myProject, rootHolder, myUsersIndex,
|
||||
loadGrowthController.getId());
|
||||
list.add(loaderAndRefresher);
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
shortLoaders.add(new ByRootLoader(myProject, rootHolder, myMediator, myDetailsCache, ticket, myUsersIndex, filters, startingPoints));
|
||||
++ i;
|
||||
}
|
||||
|
||||
myUsersComponent.acceptUpdate(myUsersIndex.getKeys());
|
||||
|
||||
//final List<String> abstractHashs = possibleHashes == null ? null : filterNumbers(possibleHashes);
|
||||
myPreviousAlgorithm = new LoadAlgorithm(myProject, list, possibleHashes == null ? null : Arrays.asList(possibleHashes));
|
||||
myPreviousAlgorithm = new LoadAlgorithm(myProject, list, shortLoaders);
|
||||
myPreviousAlgorithm.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package git4idea.history.wholeTree;
|
||||
|
||||
import git4idea.history.browser.ChangesFilter;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@@ -26,7 +24,7 @@ public interface Loader {
|
||||
void loadSkeleton(Mediator.Ticket ticket,
|
||||
RootsHolder rootsHolder,
|
||||
final Collection<String> startingPoints,
|
||||
final Collection<Collection<ChangesFilter.Filter>> filters, String[] possibleHashes, LoadGrowthController loadGrowthController);
|
||||
final GitLogFilters filters, LoadGrowthController loadGrowthController);
|
||||
|
||||
void resume();
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class LoaderAndRefresherImpl implements LoaderAndRefresher<CommitHashPlus
|
||||
myProgressAnalog = new Getter<Boolean>() {
|
||||
@Override
|
||||
public Boolean get() {
|
||||
return StepType.STOP.equals(myStepType);
|
||||
return isInterrupted();
|
||||
}
|
||||
};
|
||||
myLowLevelAccess = new LowLevelAccessImpl(myProject, myRootHolder.getRoot());
|
||||
@@ -105,7 +105,7 @@ public class LoaderAndRefresherImpl implements LoaderAndRefresher<CommitHashPlus
|
||||
}
|
||||
}
|
||||
|
||||
StepType stepType = myMediator.appendResult(myTicket, buffer, parents, id);
|
||||
StepType stepType = myMediator.appendResult(myTicket, buffer, parents);
|
||||
if (! StepType.FINISHED.equals(myStepType)) {
|
||||
myStepType = stepType;
|
||||
}
|
||||
@@ -267,7 +267,7 @@ public class LoaderAndRefresherImpl implements LoaderAndRefresher<CommitHashPlus
|
||||
}
|
||||
}
|
||||
if (! result.isEmpty()) {
|
||||
final StepType stepType = myMediator.appendResult(myTicket, result, parents, myId);
|
||||
final StepType stepType = myMediator.appendResult(myTicket, result, parents);
|
||||
// here we react only on "stop", not on "pause"
|
||||
if (StepType.STOP.equals(stepType)) {
|
||||
myStepType = StepType.STOP;
|
||||
|
||||
@@ -14,7 +14,6 @@ package git4idea.history.wholeTree;
|
||||
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.history.browser.ChangesFilter;
|
||||
import git4idea.history.browser.SymbolicRefs;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -27,16 +26,14 @@ import java.util.List;
|
||||
public interface Mediator {
|
||||
void reload(RootsHolder rootsHolder,
|
||||
final Collection<String> startingPoints,
|
||||
final Collection<Collection<ChangesFilter.Filter>> filters,
|
||||
@Nullable String[] possibleHashes);
|
||||
@Nullable final GitLogFilters filters);
|
||||
|
||||
/**
|
||||
* @return false -> ticket already changed
|
||||
*/
|
||||
StepType appendResult(final Ticket ticket,
|
||||
final List<CommitI> result,
|
||||
@Nullable final List<List<AbstractHash>> parents,
|
||||
LoadGrowthController.ID id);
|
||||
@Nullable final List<List<AbstractHash>> parents);
|
||||
|
||||
void reportSymbolicRefs(final Ticket ticket, VirtualFile root, final SymbolicRefs symbolicRefs);
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.intellij.openapi.vcs.CalledInBackground;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.committed.AbstractCalledLater;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import git4idea.history.browser.ChangesFilter;
|
||||
import git4idea.history.browser.SymbolicRefs;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -48,13 +47,12 @@ public class MediatorImpl implements Mediator {
|
||||
|
||||
@CalledInBackground
|
||||
@Override
|
||||
public StepType appendResult(final Ticket ticket, final List<CommitI> result,
|
||||
final @Nullable List<List<AbstractHash>> parents, LoadGrowthController.ID id) {
|
||||
public StepType appendResult(final Ticket ticket, final List<CommitI> result, final @Nullable List<List<AbstractHash>> parents) {
|
||||
if (! myTicket.equals(ticket)) {
|
||||
return StepType.STOP;
|
||||
}
|
||||
|
||||
myTableWrapper.appendResult(ticket, id, result, parents);
|
||||
myTableWrapper.appendResult(ticket, result, parents);
|
||||
if (myTableWrapper.isSuspend()) {
|
||||
return StepType.PAUSE;
|
||||
}
|
||||
@@ -102,12 +100,11 @@ public class MediatorImpl implements Mediator {
|
||||
@Override
|
||||
public void reload(final RootsHolder rootsHolder,
|
||||
final Collection<String> startingPoints,
|
||||
final Collection<Collection<ChangesFilter.Filter>> filters,
|
||||
String[] possibleHashes) {
|
||||
final GitLogFilters filters) {
|
||||
myTicket.increment();
|
||||
myTableWrapper.reset();
|
||||
myController.reset();
|
||||
myLoader.loadSkeleton(myTicket.copy(), rootsHolder, startingPoints, filters, possibleHashes, myController);
|
||||
myLoader.loadSkeleton(myTicket.copy(), rootsHolder, startingPoints, filters, myController);
|
||||
}
|
||||
|
||||
public void setLoader(Loader loader) {
|
||||
@@ -152,14 +149,13 @@ public class MediatorImpl implements Mediator {
|
||||
}
|
||||
|
||||
@CalledInBackground
|
||||
public void appendResult(final Ticket ticket, final LoadGrowthController.ID id, final List<CommitI> result,
|
||||
public void appendResult(final Ticket ticket, final List<CommitI> result,
|
||||
final @Nullable List<List<AbstractHash>> parents) {
|
||||
new AbstractCalledLater(myProject, myState) {
|
||||
@Override
|
||||
public void run() {
|
||||
if (! myTicket.equals(ticket)) return;
|
||||
myTableModel.appendData(result, parents);
|
||||
//myController.registerTime(id, result.get(result.size() - 1).getTime());
|
||||
if (myController.isEmpty()) {
|
||||
myTableModel.restore();
|
||||
mySuspend = false;
|
||||
@@ -173,7 +169,6 @@ public class MediatorImpl implements Mediator {
|
||||
}
|
||||
}
|
||||
}
|
||||
//myUIRefresh.linesReloaded(myTableModel.isCut());
|
||||
myUIRefresh.linesReloaded(mySuspend);
|
||||
if (myController.isEmpty()) {
|
||||
myUIRefresh.finished();
|
||||
|
||||
@@ -22,23 +22,18 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.util.Consumer;
|
||||
import git4idea.GitBranch;
|
||||
import git4idea.GitRevisionNumber;
|
||||
import git4idea.GitVcs;
|
||||
import git4idea.actions.GitShowAllSubmittedFilesAction;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitHandlerUtil;
|
||||
import git4idea.commands.GitLineHandler;
|
||||
import git4idea.commands.GitLineHandlerAdapter;
|
||||
import git4idea.commands.GitSimpleHandler;
|
||||
import git4idea.commands.StringScanner;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.commands.*;
|
||||
import git4idea.config.GitVersionSpecialty;
|
||||
import git4idea.i18n.GitBundle;
|
||||
import git4idea.update.GitStashUtils;
|
||||
import git4idea.validators.GitBranchNameValidator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -48,7 +43,6 @@ import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -164,12 +158,12 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
final StashInfo stash = getSelectedStash();
|
||||
if (Messages.YES == Messages.showYesNoDialog(GitUnstashDialog.this.getContentPane(),
|
||||
GitBundle.message("git.unstash.drop.confirmation.message", stash.myStash, stash.myMessage),
|
||||
GitBundle.message("git.unstash.drop.confirmation.title", stash.myStash), Messages.getQuestionIcon())) {
|
||||
ProgressManager.getInstance().run(new Task.Modal(myProject, "Removing stash " + stash.myStash, false) {
|
||||
GitBundle.message("git.unstash.drop.confirmation.message", stash.getStash(), stash.getMessage()),
|
||||
GitBundle.message("git.unstash.drop.confirmation.title", stash.getStash()), Messages.getQuestionIcon())) {
|
||||
ProgressManager.getInstance().run(new Task.Modal(myProject, "Removing stash " + stash.getStash(), false) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
GitSimpleHandler h = dropHandler(stash.myStash);
|
||||
GitSimpleHandler h = dropHandler(stash.getStash());
|
||||
try {
|
||||
h.run();
|
||||
h.unsilence();
|
||||
@@ -178,7 +172,7 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
try {
|
||||
//noinspection HardCodedStringLiteral
|
||||
if (ex.getMessage().startsWith("fatal: Needed a single revision")) {
|
||||
h = dropHandler(translateStash(stash.myStash));
|
||||
h = dropHandler(translateStash(stash.getStash()));
|
||||
h.run();
|
||||
}
|
||||
else {
|
||||
@@ -209,7 +203,7 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
final VirtualFile root = getGitRoot();
|
||||
String resolvedStash;
|
||||
String selectedStash = getSelectedStash().myStash;
|
||||
String selectedStash = getSelectedStash().getStash();
|
||||
try {
|
||||
resolvedStash = GitRevisionNumber.resolve(myProject, root, selectedStash).asString();
|
||||
}
|
||||
@@ -312,22 +306,12 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
private void refreshStashList() {
|
||||
final DefaultListModel listModel = (DefaultListModel)myStashList.getModel();
|
||||
listModel.clear();
|
||||
GitSimpleHandler h = new GitSimpleHandler(myProject, getGitRoot(), GitCommand.STASH);
|
||||
h.setSilent(true);
|
||||
h.setNoSSH(true);
|
||||
h.addParameters("list");
|
||||
String out;
|
||||
try {
|
||||
h.setCharset(Charset.forName(GitConfigUtil.getLogEncoding(myProject, getGitRoot())));
|
||||
out = h.run();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GitUIUtil.showOperationError(myProject, e, h.printableCommandLine());
|
||||
return;
|
||||
}
|
||||
for (StringScanner s = new StringScanner(out); s.hasMoreData();) {
|
||||
listModel.addElement(new StashInfo(s.boundedToken(':'), s.boundedToken(':'), s.line().trim()));
|
||||
}
|
||||
GitStashUtils.loadStashStack(myProject, getGitRoot(), new Consumer<StashInfo>() {
|
||||
@Override
|
||||
public void consume(StashInfo stashInfo) {
|
||||
listModel.addElement(stashInfo);
|
||||
}
|
||||
});
|
||||
myBranches.clear();
|
||||
try {
|
||||
GitBranch.listAsStrings(myProject, getGitRoot(), false, true, myBranches, null);
|
||||
@@ -361,7 +345,7 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
else {
|
||||
h.addParameters("branch", branch);
|
||||
}
|
||||
String selectedStash = getSelectedStash().myStash;
|
||||
String selectedStash = getSelectedStash().getStash();
|
||||
if (escaped) {
|
||||
selectedStash = translateStash(selectedStash);
|
||||
} else if (GitVersionSpecialty.NEEDS_QUOTES_IN_STASH_NAME.existsIn(myVcs.getVersion())) { // else if, because escaping {} also solves the issue
|
||||
@@ -438,27 +422,4 @@ public class GitUnstashDialog extends DialogWrapper {
|
||||
GitUIUtil.showOperationErrors(project, h.errors(), h.printableCommandLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about one stash.
|
||||
*/
|
||||
private static class StashInfo {
|
||||
private final String myStash; // stash codename (stash@{1})
|
||||
private final String myBranch;
|
||||
private final String myMessage;
|
||||
private final String myText; // The formatted text representation
|
||||
|
||||
public StashInfo(final String stash, final String branch, final String message) {
|
||||
myStash = stash;
|
||||
myBranch = branch;
|
||||
myMessage = message;
|
||||
myText =
|
||||
GitBundle.message("unstash.stashes.item", StringUtil.escapeXml(stash), StringUtil.escapeXml(branch), StringUtil.escapeXml(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.ui;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import git4idea.i18n.GitBundle;
|
||||
|
||||
/**
|
||||
* Information about one stash.
|
||||
*/
|
||||
public class StashInfo {
|
||||
private final String myStash; // stash codename (stash@{1})
|
||||
private final String myBranch;
|
||||
private final String myMessage;
|
||||
private final String myText; // The formatted text representation
|
||||
|
||||
public StashInfo(final String stash, final String branch, final String message) {
|
||||
myStash = stash;
|
||||
myBranch = branch;
|
||||
myMessage = message;
|
||||
myText =
|
||||
GitBundle.message("unstash.stashes.item", StringUtil.escapeXml(stash), StringUtil.escapeXml(branch), StringUtil.escapeXml(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public String getStash() {
|
||||
return myStash;
|
||||
}
|
||||
|
||||
public String getBranch() {
|
||||
return myBranch;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return myMessage;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.intellij.openapi.vcs.changes.shelf.ShelvedChange;
|
||||
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcsUtil.VcsUtil;
|
||||
import git4idea.GitUtil;
|
||||
@@ -35,7 +36,11 @@ import git4idea.GitVcs;
|
||||
import git4idea.commands.GitCommand;
|
||||
import git4idea.commands.GitFileUtils;
|
||||
import git4idea.commands.GitSimpleHandler;
|
||||
import git4idea.commands.StringScanner;
|
||||
import git4idea.config.GitConfigUtil;
|
||||
import git4idea.config.GitVersion;
|
||||
import git4idea.ui.GitUIUtil;
|
||||
import git4idea.ui.StashInfo;
|
||||
import git4idea.vfs.GitVFSListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -43,6 +48,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -74,6 +80,30 @@ public class GitStashUtils {
|
||||
return !output.startsWith("No local changes to save");
|
||||
}
|
||||
|
||||
public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, Consumer<StashInfo> consumer) {
|
||||
loadStashStack(project, root, Charset.forName(GitConfigUtil.getLogEncoding(project, root)), consumer);
|
||||
}
|
||||
|
||||
public static void loadStashStack(@NotNull Project project, @NotNull VirtualFile root, final Charset charset,
|
||||
final Consumer<StashInfo> consumer) {
|
||||
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.STASH);
|
||||
h.setSilent(true);
|
||||
h.setNoSSH(true);
|
||||
h.addParameters("list");
|
||||
String out;
|
||||
try {
|
||||
h.setCharset(charset);
|
||||
out = h.run();
|
||||
}
|
||||
catch (VcsException e) {
|
||||
GitUIUtil.showOperationError(project, e, h.printableCommandLine());
|
||||
return;
|
||||
}
|
||||
for (StringScanner s = new StringScanner(out); s.hasMoreData();) {
|
||||
consumer.consume(new StashInfo(s.boundedToken(':'), s.boundedToken(':'), s.line().trim()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create stash for later use (it ignores exit code 1 [merge conflict])
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user