[vcs-log] check for progress indicator being cancelled while processing arguments by chunks

This commit is contained in:
Julia Beliaeva
2016-01-14 19:25:51 +03:00
parent 937ddd2ef6
commit 75425014da
6 changed files with 140 additions and 82 deletions
@@ -0,0 +1,23 @@
/*
* Copyright 2000-2015 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.util;
import org.jetbrains.annotations.NotNull;
public interface ThrowableNotNullFunction<T, R, E extends Throwable> {
@NotNull
R fun(@NotNull T t) throws E;
}
@@ -15,13 +15,17 @@
*/
package com.intellij.vcsUtil;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.ThrowableNotNullFunction;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -41,25 +45,54 @@ public class VcsFileUtil {
public static final int FILE_PATH_LIMIT = 7600;
/**
* Chunk paths on the command line
* Execute function for each chunk of arguments. Check for being cancelled in process.
*
* @param files the paths to chunk
* @return the a list of list of relative paths
* @param arguments the arguments to chunk
* @param processor function to execute on each chunk
* @param <T> type of result value
* @return list of result values
* @throws VcsException
*/
public static List<List<String>> chunkRelativePaths(List<String> files) {
@NotNull
public static <T> List<T> foreachChunk(@NotNull List<String> arguments,
@NotNull ThrowableNotNullFunction<List<String>, List<? extends T>, VcsException> processor)
throws VcsException {
List<T> result = ContainerUtil.newArrayList();
List<List<String>> chunks = chunkArguments(arguments);
for (List<String> chunk : chunks) {
if (ProgressManager.getInstance().getProgressIndicator() != null &&
ProgressManager.getInstance().getProgressIndicator().isCanceled()) {
return result;
}
result.addAll(processor.fun(chunk));
}
return result;
}
/**
* Chunk arguments on the command line
*
* @param arguments the arguments to chunk
* @return a list of lists of arguments
*/
@NotNull
public static List<List<String>> chunkArguments(@NotNull List<String> arguments) {
ArrayList<List<String>> rc = new ArrayList<List<String>>();
int start = 0;
int size = 0;
int i = 0;
for (; i < files.size(); i++) {
String p = files.get(i);
for (; i < arguments.size(); i++) {
String p = arguments.get(i);
if (size + p.length() > FILE_PATH_LIMIT) {
if (start == i) {
rc.add(files.subList(i, i + 1));
rc.add(arguments.subList(i, i + 1));
start = i + 1;
}
else {
rc.add(files.subList(start, i));
rc.add(arguments.subList(start, i));
start = i;
}
size = 0;
@@ -68,8 +101,8 @@ public class VcsFileUtil {
size += p.length();
}
}
if (start != files.size()) {
rc.add(files.subList(start, i));
if (start != arguments.size()) {
rc.add(arguments.subList(start, i));
}
return rc;
}
@@ -82,7 +115,7 @@ public class VcsFileUtil {
* @return chunked relative paths
*/
public static List<List<String>> chunkPaths(VirtualFile root, Collection<FilePath> files) {
return chunkRelativePaths(toRelativePaths(root, files));
return chunkArguments(toRelativePaths(root, files));
}
/**
@@ -93,7 +126,7 @@ public class VcsFileUtil {
* @return chunked relative paths
*/
public static List<List<String>> chunkFiles(@NotNull VirtualFile root, @NotNull Collection<VirtualFile> files) {
return chunkRelativePaths(toRelativeFiles(root, files));
return chunkArguments(toRelativeFiles(root, files));
}
public static String getRelativeFilePath(VirtualFile file, @NotNull final VirtualFile baseDir) {
@@ -18,6 +18,7 @@ package git4idea.log;
import com.intellij.openapi.diagnostic.Attachment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableNotNullFunction;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsKey;
@@ -333,34 +334,35 @@ public class GitLogProvider implements VcsLogProvider {
@NotNull
@Override
public List<? extends VcsShortCommitDetails> readShortDetails(@NotNull VirtualFile root, @NotNull List<String> hashes)
public List<? extends VcsShortCommitDetails> readShortDetails(@NotNull final VirtualFile root, @NotNull List<String> hashes)
throws VcsException {
List<VcsShortCommitDetails> result = ContainerUtil.newArrayList();
List<List<String>> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes);
for (List<String> hashesChunk : hashesChunks) {
result.addAll(GitHistoryUtils.readMiniDetails(myProject, root, hashesChunk));
}
return result;
return VcsFileUtil
.foreachChunk(hashes, new ThrowableNotNullFunction<List<String>, List<? extends VcsShortCommitDetails>, VcsException>() {
@NotNull
@Override
public List<? extends VcsShortCommitDetails> fun(@NotNull List<String> hashes) throws VcsException {
return GitHistoryUtils.readMiniDetails(myProject, root, hashes);
}
});
}
@NotNull
@Override
public List<? extends VcsFullCommitDetails> readFullDetails(@NotNull VirtualFile root, @NotNull List<String> hashes) throws VcsException {
List<VcsFullCommitDetails> result = ContainerUtil.newArrayList();
List<List<String>> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes);
public List<? extends VcsFullCommitDetails> readFullDetails(@NotNull final VirtualFile root, @NotNull List<String> hashes)
throws VcsException {
return VcsFileUtil
.foreachChunk(hashes, new ThrowableNotNullFunction<List<String>, List<? extends VcsFullCommitDetails>, VcsException>() {
@NotNull
@Override
public List<? extends VcsFullCommitDetails> fun(@NotNull List<String> hashes) throws VcsException {
String noWalk = GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(myVcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk";
List<String> params = new ArrayList<String>();
params.add(noWalk);
params.addAll(hashes);
for (List<String> hashesChunk : hashesChunks) {
String noWalk = GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(myVcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk";
List<String> params = new ArrayList<String>();
params.add(noWalk);
params.addAll(hashesChunk);
result.addAll(GitHistoryUtils.history(myProject, root, ArrayUtil.toStringArray(params)));
}
return result;
return GitHistoryUtils.history(myProject, root, ArrayUtil.toStringArray(params));
}
});
}
@NotNull
@@ -90,7 +90,7 @@ public abstract class HgCommitTypeCommand {
return file.getRelativePath();
}
});
List<List<String>> chunkedCommits = VcsFileUtil.chunkRelativePaths(relativePaths);
List<List<String>> chunkedCommits = VcsFileUtil.chunkArguments(relativePaths);
executeChunked(chunkedCommits);
}
myRepository.update();
@@ -48,7 +48,7 @@ public class HgRemoveCommand {
public void execute(@NotNull Collection<HgFile> hgFiles) {
for( Map.Entry<VirtualFile, List<String>> entry : HgUtil.getRelativePathsByRepository(hgFiles).entrySet()) {
List<String> filePaths = entry.getValue();
for (List<String> chunkFiles : VcsFileUtil.chunkRelativePaths(filePaths)) {
for (List<String> chunkFiles : VcsFileUtil.chunkArguments(filePaths)) {
List<String> parameters = new LinkedList<String>();
parameters.addAll(chunkFiles);
parameters.add(0, "--after");
@@ -19,6 +19,7 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.ThrowableNotNullFunction;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
@@ -112,24 +113,23 @@ public class HgHistoryUtil {
*/
@NotNull
public static List<? extends VcsFullCommitDetails> history(@NotNull final Project project,
@NotNull final VirtualFile root,
int limit,
@NotNull List<String> hashParameters,
boolean silent) throws VcsException {
@NotNull final VirtualFile root, final int limit,
@NotNull List<String> hashParameters, final boolean silent)
throws VcsException {
HgVcs hgvcs = HgVcs.getInstance(project);
assert hgvcs != null;
final HgVersion version = hgvcs.getVersion();
String[] templates = HgBaseLogParser.constructFullTemplateArgument(true, version);
final String[] templates = HgBaseLogParser.constructFullTemplateArgument(true, version);
List<VcsFullCommitDetails> result = ContainerUtil.newArrayList();
List<List<String>> hashesChunks = VcsFileUtil.chunkRelativePaths(hashParameters);
for (List<String> hashesChunk : hashesChunks) {
HgCommandResult logResult = getLogResult(project, root, version, limit, hashesChunk, HgChangesetUtil.makeTemplate(templates));
result.addAll(createFullCommitsFromResult(project, root, logResult, version, silent));
}
return result;
return VcsFileUtil
.foreachChunk(hashParameters, new ThrowableNotNullFunction<List<String>, List<? extends VcsFullCommitDetails>, VcsException>() {
@NotNull
@Override
public List<? extends VcsFullCommitDetails> fun(@NotNull List<String> strings) throws VcsException {
HgCommandResult logResult = getLogResult(project, root, version, limit, strings, HgChangesetUtil.makeTemplate(templates));
return createFullCommitsFromResult(project, root, logResult, version, silent);
}
});
}
public static List<? extends VcsFullCommitDetails> createFullCommitsFromResult(@NotNull Project project,
@@ -244,7 +244,7 @@ public class HgHistoryUtil {
}
@NotNull
public static List<? extends VcsShortCommitDetails> readMiniDetails(@NotNull Project project,
public static List<? extends VcsShortCommitDetails> readMiniDetails(@NotNull final Project project,
@NotNull final VirtualFile root,
@NotNull List<String> hashes)
throws VcsException {
@@ -255,41 +255,41 @@ public class HgHistoryUtil {
HgVcs hgvcs = HgVcs.getInstance(project);
assert hgvcs != null;
HgVersion version = hgvcs.getVersion();
final HgVersion version = hgvcs.getVersion();
List<String> templateList = HgBaseLogParser.constructDefaultTemplate(version);
templateList.add("{desc}");
String[] templates = ArrayUtil.toStringArray(templateList);
final String[] templates = ArrayUtil.toStringArray(templateList);
List<VcsShortCommitDetails> result = ContainerUtil.newArrayList();
List<List<String>> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes);
return VcsFileUtil.foreachChunk(prepareHashes(hashes),
new ThrowableNotNullFunction<List<String>, List<? extends VcsShortCommitDetails>, VcsException>() {
@NotNull
@Override
public List<? extends VcsShortCommitDetails> fun(@NotNull List<String> strings) throws VcsException {
HgCommandResult logResult =
getLogResult(project, root, version, -1, strings, HgChangesetUtil.makeTemplate(templates));
for (List<String> hashesChunk : hashesChunks) {
HgCommandResult logResult =
getLogResult(project, root, version, -1, prepareHashes(hashesChunk), HgChangesetUtil.makeTemplate(templates));
result.addAll(getCommitRecords(project, logResult, new HgBaseLogParser<VcsShortCommitDetails>() {
@Override
protected VcsShortCommitDetails convertDetails(@NotNull String rev,
@NotNull String changeset,
@NotNull SmartList<HgRevisionNumber> parents,
@NotNull Date revisionDate,
@NotNull String author,
@NotNull String email,
@NotNull List<String> attributes) {
String message = parseAdditionalStringAttribute(attributes, MESSAGE_INDEX);
String subject = extractSubject(message);
List<Hash> parentsHash = new SmartList<Hash>();
for (HgRevisionNumber parent : parents) {
parentsHash.add(factory.createHash(parent.getChangeset()));
}
return factory
.createShortDetails(factory.createHash(changeset), parentsHash, revisionDate.getTime(), root, subject, author, email, author,
email, revisionDate.getTime());
}
}));
}
return result;
return getCommitRecords(project, logResult, new HgBaseLogParser<VcsShortCommitDetails>() {
@Override
protected VcsShortCommitDetails convertDetails(@NotNull String rev,
@NotNull String changeset,
@NotNull SmartList<HgRevisionNumber> parents,
@NotNull Date revisionDate,
@NotNull String author,
@NotNull String email,
@NotNull List<String> attributes) {
String message = parseAdditionalStringAttribute(attributes, MESSAGE_INDEX);
String subject = extractSubject(message);
List<Hash> parentsHash = new SmartList<Hash>();
for (HgRevisionNumber parent : parents) {
parentsHash.add(factory.createHash(parent.getChangeset()));
}
return factory
.createShortDetails(factory.createHash(changeset), parentsHash, revisionDate.getTime(), root,
subject, author, email, author, email, revisionDate.getTime());
}
});
}
});
}
@NotNull