mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
download libraries in parallel (IDEA-88561)
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.intellij.util.download.impl;
|
||||
|
||||
import com.google.common.util.concurrent.AtomicDouble;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
@@ -27,6 +29,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.AbstractProgressIndicatorBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
@@ -34,6 +37,8 @@ import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import com.intellij.util.download.DownloadableFileDescription;
|
||||
import com.intellij.util.download.FileDownloader;
|
||||
import com.intellij.util.io.UrlConnectionUtil;
|
||||
@@ -49,6 +54,7 @@ import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
@@ -147,49 +153,60 @@ public class FileDownloaderImpl implements FileDownloader {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Pair<File, DownloadableFileDescription>> download(@NotNull File targetDir) throws IOException {
|
||||
public List<Pair<File, DownloadableFileDescription>> download(@NotNull final File targetDir) throws IOException {
|
||||
final List<Pair<File, DownloadableFileDescription>> downloadedFiles = new ArrayList<Pair<File, DownloadableFileDescription>>();
|
||||
final List<Pair<File, DownloadableFileDescription>> existingFiles = new ArrayList<Pair<File, DownloadableFileDescription>>();
|
||||
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (indicator == null) {
|
||||
indicator = new EmptyProgressIndicator();
|
||||
}
|
||||
final ProgressIndicator parentIndicator = getProgressIndicator();
|
||||
try {
|
||||
for (int i = 0; i < myFileDescriptions.size(); i++) {
|
||||
DownloadableFileDescription description = myFileDescriptions.get(i);
|
||||
indicator.checkCanceled();
|
||||
indicator.setText(IdeBundle.message("progress.downloading.0.of.1.file.text", i + 1, myFileDescriptions.size()));
|
||||
final AtomicReference<IOException> ioException = new AtomicReference<IOException>();
|
||||
final ConcurrentTasksProgressManager progressManager = new ConcurrentTasksProgressManager(parentIndicator, myFileDescriptions.size());
|
||||
parentIndicator.setText(IdeBundle.message("progress.downloading.0.files.text", myFileDescriptions.size()));
|
||||
boolean finished = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(myFileDescriptions, parentIndicator, false, false, new Processor<DownloadableFileDescription>() {
|
||||
@Override
|
||||
public boolean process(DownloadableFileDescription description) {
|
||||
SubTaskProgressIndicator indicator = progressManager.createSubTaskIndicator();
|
||||
indicator.checkCanceled();
|
||||
|
||||
final File existing = new File(targetDir, description.getDefaultFileName());
|
||||
final String url = description.getDownloadUrl();
|
||||
if (url.startsWith(LIB_SCHEMA)) {
|
||||
indicator.setText2(IdeBundle.message("progress.locate.file.text", description.getPresentableFileName()));
|
||||
final String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LIB_SCHEMA));
|
||||
final File file = PathManager.findFileInLibDirectory(path);
|
||||
existingFiles.add(Pair.create(file, description));
|
||||
}
|
||||
else if (url.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) {
|
||||
String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LocalFileSystem.PROTOCOL_PREFIX));
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
final File existing = new File(targetDir, description.getDefaultFileName());
|
||||
final String url = description.getDownloadUrl();
|
||||
if (url.startsWith(LIB_SCHEMA)) {
|
||||
final String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LIB_SCHEMA));
|
||||
final File file = PathManager.findFileInLibDirectory(path);
|
||||
existingFiles.add(Pair.create(file, description));
|
||||
}
|
||||
}
|
||||
else {
|
||||
File downloaded;
|
||||
try {
|
||||
downloaded = downloadFile(description, existing, indicator);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IOException(IdeBundle.message("error.file.download.failed", description.getDownloadUrl(), e.getMessage()), e);
|
||||
}
|
||||
if (FileUtil.filesEqual(downloaded, existing)) {
|
||||
existingFiles.add(Pair.create(existing, description));
|
||||
else if (url.startsWith(LocalFileSystem.PROTOCOL_PREFIX)) {
|
||||
String path = FileUtil.toSystemDependentName(StringUtil.trimStart(url, LocalFileSystem.PROTOCOL_PREFIX));
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
existingFiles.add(Pair.create(file, description));
|
||||
}
|
||||
}
|
||||
else {
|
||||
downloadedFiles.add(Pair.create(downloaded, description));
|
||||
File downloaded;
|
||||
try {
|
||||
downloaded = downloadFile(description, existing, indicator);
|
||||
}
|
||||
catch (IOException e) {
|
||||
ioException.compareAndSet(null, new IOException(IdeBundle.message("error.file.download.failed", description.getDownloadUrl(),
|
||||
e.getMessage()), e));
|
||||
return false;
|
||||
}
|
||||
if (FileUtil.filesEqual(downloaded, existing)) {
|
||||
existingFiles.add(Pair.create(existing, description));
|
||||
}
|
||||
else {
|
||||
downloadedFiles.add(Pair.create(downloaded, description));
|
||||
}
|
||||
}
|
||||
indicator.finished();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!finished) {
|
||||
if (ioException.get() != null) {
|
||||
throw ioException.get();
|
||||
}
|
||||
throw new ProcessCanceledException();
|
||||
}
|
||||
List<Pair<File, DownloadableFileDescription>> localFiles = new ArrayList<Pair<File, DownloadableFileDescription>>();
|
||||
localFiles.addAll(moveToDir(downloadedFiles, targetDir));
|
||||
@@ -206,6 +223,12 @@ public class FileDownloaderImpl implements FileDownloader {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ProgressIndicator getProgressIndicator() {
|
||||
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
return indicator == null ? new EmptyProgressIndicator() : indicator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile chooseDirectoryForFiles(Project project, JComponent parentComponent) {
|
||||
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
|
||||
@@ -330,4 +353,82 @@ public class FileDownloaderImpl implements FileDownloader {
|
||||
public List<Pair<VirtualFile, DownloadableFileDescription>> downloadAndReturnWithDescriptions() {
|
||||
return downloadWithProgress(myDirectoryForDownloadedFilesPath, myProject, myParentComponent);
|
||||
}
|
||||
|
||||
private static class ConcurrentTasksProgressManager {
|
||||
private final ProgressIndicator myParent;
|
||||
private final int myTasksCount;
|
||||
private final AtomicDouble myTotalFraction;
|
||||
private LinkedHashMap<SubTaskProgressIndicator, String> myText2Stack = new LinkedHashMap<SubTaskProgressIndicator, String>();
|
||||
|
||||
private ConcurrentTasksProgressManager(ProgressIndicator parent, int tasksCount) {
|
||||
myParent = parent;
|
||||
myTasksCount = tasksCount;
|
||||
myTotalFraction = new AtomicDouble();
|
||||
}
|
||||
|
||||
public void updateFraction(double delta) {
|
||||
myTotalFraction.addAndGet(delta / myTasksCount);
|
||||
myParent.setFraction(myTotalFraction.get());
|
||||
}
|
||||
|
||||
public SubTaskProgressIndicator createSubTaskIndicator() {
|
||||
return new SubTaskProgressIndicator(this);
|
||||
}
|
||||
|
||||
public void setText2(@NotNull SubTaskProgressIndicator subTask, @Nullable String text) {
|
||||
if (text != null) {
|
||||
myText2Stack.put(subTask, text);
|
||||
myParent.setText2(text);
|
||||
}
|
||||
else {
|
||||
myText2Stack.remove(subTask);
|
||||
String prev = myText2Stack.getLastAddedValue();
|
||||
if (prev != null) {
|
||||
myParent.setText2(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubTaskProgressIndicator extends AbstractProgressIndicatorBase {
|
||||
private final AtomicDouble myFraction;
|
||||
private final ConcurrentTasksProgressManager myProgressManager;
|
||||
|
||||
private SubTaskProgressIndicator(ConcurrentTasksProgressManager progressManager) {
|
||||
myProgressManager = progressManager;
|
||||
myFraction = new AtomicDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFraction(double newValue) {
|
||||
double oldValue = myFraction.getAndSet(newValue);
|
||||
myProgressManager.updateFraction(newValue - oldValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndeterminate(boolean indeterminate) {
|
||||
if (myProgressManager.myTasksCount > 1) return;
|
||||
super.setIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText2(String text) {
|
||||
myProgressManager.setText2(this, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFraction() {
|
||||
return myFraction.get();
|
||||
}
|
||||
|
||||
public void finished() {
|
||||
setFraction(1);
|
||||
myProgressManager.setText2(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
return super.isCanceled() || myProgressManager.myParent.isCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,7 +987,7 @@ progress.download.0.title=Downloading {0}
|
||||
progress.download.file.text=Downloading ''{0}'' from ''{1}''...
|
||||
progress.connecting.to.download.file.text=Connecting to ''{0}''...
|
||||
progress.locate.file.text=Locating ''{0}''...
|
||||
progress.downloading.0.of.1.file.text=Downloading {0} of {1} {1, choice, 1#file|2#files}...
|
||||
progress.downloading.0.files.text=Downloading {0} {0, choice, 1#file|2#files}...
|
||||
dialog.directory.for.downloaded.files.title=Downloaded files will be copied to selected directory
|
||||
error.file.download.failed=Failed to download ''{0}'': {1}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user