diff --git a/platform/util/src/com/intellij/openapi/util/ThrowableNotNullFunction.java b/platform/util/src/com/intellij/openapi/util/ThrowableNotNullFunction.java new file mode 100644 index 000000000000..01918b8d115b --- /dev/null +++ b/platform/util/src/com/intellij/openapi/util/ThrowableNotNullFunction.java @@ -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 { + @NotNull + R fun(@NotNull T t) throws E; +} diff --git a/platform/vcs-impl/src/com/intellij/vcsUtil/VcsFileUtil.java b/platform/vcs-impl/src/com/intellij/vcsUtil/VcsFileUtil.java index a9a21547233d..f98646c30aab 100644 --- a/platform/vcs-impl/src/com/intellij/vcsUtil/VcsFileUtil.java +++ b/platform/vcs-impl/src/com/intellij/vcsUtil/VcsFileUtil.java @@ -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 type of result value + * @return list of result values + * @throws VcsException */ - public static List> chunkRelativePaths(List files) { + @NotNull + public static List foreachChunk(@NotNull List arguments, + @NotNull ThrowableNotNullFunction, List, VcsException> processor) + throws VcsException { + List result = ContainerUtil.newArrayList(); + List> chunks = chunkArguments(arguments); + + for (List 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> chunkArguments(@NotNull List arguments) { ArrayList> rc = new ArrayList>(); 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> chunkPaths(VirtualFile root, Collection 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> chunkFiles(@NotNull VirtualFile root, @NotNull Collection files) { - return chunkRelativePaths(toRelativeFiles(root, files)); + return chunkArguments(toRelativeFiles(root, files)); } public static String getRelativeFilePath(VirtualFile file, @NotNull final VirtualFile baseDir) { diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index ed5b9afeea23..a35f3add5162 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -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 readShortDetails(@NotNull VirtualFile root, @NotNull List hashes) + public List readShortDetails(@NotNull final VirtualFile root, @NotNull List hashes) throws VcsException { - List result = ContainerUtil.newArrayList(); - List> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes); - - for (List hashesChunk : hashesChunks) { - result.addAll(GitHistoryUtils.readMiniDetails(myProject, root, hashesChunk)); - } - - return result; + return VcsFileUtil + .foreachChunk(hashes, new ThrowableNotNullFunction, List, VcsException>() { + @NotNull + @Override + public List fun(@NotNull List hashes) throws VcsException { + return GitHistoryUtils.readMiniDetails(myProject, root, hashes); + } + }); } @NotNull @Override - public List readFullDetails(@NotNull VirtualFile root, @NotNull List hashes) throws VcsException { - List result = ContainerUtil.newArrayList(); - List> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes); + public List readFullDetails(@NotNull final VirtualFile root, @NotNull List hashes) + throws VcsException { + return VcsFileUtil + .foreachChunk(hashes, new ThrowableNotNullFunction, List, VcsException>() { + @NotNull + @Override + public List fun(@NotNull List hashes) throws VcsException { + String noWalk = GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(myVcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk"; + List params = new ArrayList(); + params.add(noWalk); + params.addAll(hashes); - for (List hashesChunk : hashesChunks) { - String noWalk = GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(myVcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk"; - List params = new ArrayList(); - 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 diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitTypeCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitTypeCommand.java index 1ddad28a6c4c..ad5078e3492b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitTypeCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitTypeCommand.java @@ -90,7 +90,7 @@ public abstract class HgCommitTypeCommand { return file.getRelativePath(); } }); - List> chunkedCommits = VcsFileUtil.chunkRelativePaths(relativePaths); + List> chunkedCommits = VcsFileUtil.chunkArguments(relativePaths); executeChunked(chunkedCommits); } myRepository.update(); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java index 9fffe1ba397a..9ccdbac32b0b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgRemoveCommand.java @@ -48,7 +48,7 @@ public class HgRemoveCommand { public void execute(@NotNull Collection hgFiles) { for( Map.Entry> entry : HgUtil.getRelativePathsByRepository(hgFiles).entrySet()) { List filePaths = entry.getValue(); - for (List chunkFiles : VcsFileUtil.chunkRelativePaths(filePaths)) { + for (List chunkFiles : VcsFileUtil.chunkArguments(filePaths)) { List parameters = new LinkedList(); parameters.addAll(chunkFiles); parameters.add(0, "--after"); diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java index e8b2084f1ae4..83770418c739 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java @@ -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 history(@NotNull final Project project, - @NotNull final VirtualFile root, - int limit, - @NotNull List hashParameters, - boolean silent) throws VcsException { + @NotNull final VirtualFile root, final int limit, + @NotNull List 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 result = ContainerUtil.newArrayList(); - List> hashesChunks = VcsFileUtil.chunkRelativePaths(hashParameters); - - for (List 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, VcsException>() { + @NotNull + @Override + public List fun(@NotNull List strings) throws VcsException { + HgCommandResult logResult = getLogResult(project, root, version, limit, strings, HgChangesetUtil.makeTemplate(templates)); + return createFullCommitsFromResult(project, root, logResult, version, silent); + } + }); } public static List createFullCommitsFromResult(@NotNull Project project, @@ -244,7 +244,7 @@ public class HgHistoryUtil { } @NotNull - public static List readMiniDetails(@NotNull Project project, + public static List readMiniDetails(@NotNull final Project project, @NotNull final VirtualFile root, @NotNull List 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 templateList = HgBaseLogParser.constructDefaultTemplate(version); templateList.add("{desc}"); - String[] templates = ArrayUtil.toStringArray(templateList); + final String[] templates = ArrayUtil.toStringArray(templateList); - List result = ContainerUtil.newArrayList(); - List> hashesChunks = VcsFileUtil.chunkRelativePaths(hashes); + return VcsFileUtil.foreachChunk(prepareHashes(hashes), + new ThrowableNotNullFunction, List, VcsException>() { + @NotNull + @Override + public List fun(@NotNull List strings) throws VcsException { + HgCommandResult logResult = + getLogResult(project, root, version, -1, strings, HgChangesetUtil.makeTemplate(templates)); - for (List hashesChunk : hashesChunks) { - HgCommandResult logResult = - getLogResult(project, root, version, -1, prepareHashes(hashesChunk), HgChangesetUtil.makeTemplate(templates)); - - result.addAll(getCommitRecords(project, logResult, new HgBaseLogParser() { - @Override - protected VcsShortCommitDetails convertDetails(@NotNull String rev, - @NotNull String changeset, - @NotNull SmartList parents, - @NotNull Date revisionDate, - @NotNull String author, - @NotNull String email, - @NotNull List attributes) { - String message = parseAdditionalStringAttribute(attributes, MESSAGE_INDEX); - String subject = extractSubject(message); - List parentsHash = new SmartList(); - 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() { + @Override + protected VcsShortCommitDetails convertDetails(@NotNull String rev, + @NotNull String changeset, + @NotNull SmartList parents, + @NotNull Date revisionDate, + @NotNull String author, + @NotNull String email, + @NotNull List attributes) { + String message = parseAdditionalStringAttribute(attributes, MESSAGE_INDEX); + String subject = extractSubject(message); + List parentsHash = new SmartList(); + 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