PY-72070 Introduced PythonPackagesInstallerAsync for performing package installations asynchronously using coroutines. Updated the existing PyPackageManagerUI to utilize this new asynchronous method.

(cherry picked from commit 80c4c17b9ad7a209be747b10dc5bdbd94cff6b9b)

GitOrigin-RevId: e7a89997e694e792794fe604e7c4270be9517b24
This commit is contained in:
Timur Malanin
2024-11-29 14:14:12 +01:00
committed by intellij-monorepo-bot
parent 42c78668df
commit c39507ddb0
2 changed files with 87 additions and 37 deletions

View File

@@ -2,7 +2,6 @@
package com.jetbrains.python.packaging;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.RunCanceledByUserException;
import com.intellij.ide.IdeBundle;
import com.intellij.model.SideEffectGuard;
import com.intellij.notification.Notification;
@@ -260,43 +259,18 @@ public final class PyPackageManagerUI {
@Override
protected @NotNull List<ExecutionException> runTask(@NotNull ProgressIndicator indicator) {
final List<ExecutionException> exceptions = new ArrayList<>();
final PyPackageManager manager = PyPackageManagers.getInstance().forSdk(mySdk);
if (myRequirements == null) {
indicator.setText(PyBundle.message("python.packaging.installing.packages"));
indicator.setIndeterminate(true);
try {
manager.install(null, myExtraArgs);
}
catch (ExecutionException e) {
exceptions.add(e);
}
if (myProject == null) {
return exceptions;
}
else {
final int size = myRequirements.size();
for (int i = 0; i < size; i++) {
final PyRequirement requirement = myRequirements.get(i);
indicator.setText(PyBundle.message("python.packaging.progress.text.installing.specific.package",
requirement.getPresentableText()));
if (i == 0) {
indicator.setIndeterminate(true);
}
else {
indicator.setIndeterminate(false);
indicator.setFraction((double)i / size);
}
try {
manager.install(Collections.singletonList(requirement), myExtraArgs);
}
catch (RunCanceledByUserException e) {
exceptions.add(e);
break;
}
catch (ExecutionException e) {
exceptions.add(e);
}
}
}
manager.refresh();
PythonPackagesInstallerAsync.Companion.installPackages(
myProject,
myRequirements,
myExtraArgs,
indicator
);
return exceptions;
}

View File

@@ -0,0 +1,76 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.python.packaging
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.jetbrains.python.PyBundle
import com.jetbrains.python.packaging.common.PythonPackageSpecification
import com.jetbrains.python.packaging.common.PythonPackageSpecificationBase
import com.jetbrains.python.packaging.common.PythonSimplePackageSpecification
import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class PythonPackagesInstallerAsync {
companion object {
fun installPackages(
project: Project,
requirements: List<PyRequirement>?,
extraArgs: List<String>,
indicator: ProgressIndicator,
) {
val packageService = PyPackagingToolWindowService.getInstance(project)
packageService.serviceScope.launch(Dispatchers.IO) {
if (requirements.isNullOrEmpty()) {
installWithoutRequirements(packageService, extraArgs, indicator)
}
else {
installWithRequirements(packageService, requirements, extraArgs, indicator)
}
}
}
private suspend fun installWithoutRequirements(
packageService: PyPackagingToolWindowService,
extraArgs: List<String>,
indicator: ProgressIndicator,
) {
indicator.text = PyBundle.message("python.packaging.installing.packages")
indicator.isIndeterminate = true
val emptySpecification = PythonPackageSpecificationBase("", null, null, null)
packageService.installPackage(emptySpecification, extraArgs)
}
private suspend fun installWithRequirements(
packageService: PyPackagingToolWindowService,
requirements: List<PyRequirement>,
extraArgs: List<String>,
indicator: ProgressIndicator,
) {
requirements.forEachIndexed { index, requirement ->
indicator.text = PyBundle.message("python.packaging.progress.text.installing.specific.package", requirement.presentableText)
updateProgress(indicator, index, requirements.size)
val specification = createSpecificationForRequirement(requirement)
packageService.installPackage(specification, extraArgs)
}
}
private fun updateProgress(indicator: ProgressIndicator, index: Int, total: Int) {
indicator.isIndeterminate = index == 0
if (total > 0) {
indicator.fraction = index.toDouble() / total
}
}
private fun createSpecificationForRequirement(
requirement: PyRequirement,
): PythonPackageSpecification {
val packageName = requirement.name
return PythonSimplePackageSpecification(packageName, null, null)
}
}
}