mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-26492 Quick-fix to install missing requirements via 'pipenv install'
This commit is contained in:
committed by
Andrey Vlasovskikh
parent
5ad19e832e
commit
5fc64675b9
@@ -45,7 +45,7 @@ public abstract class PyPackageManager {
|
||||
|
||||
public abstract void install(@NotNull String requirementString) throws ExecutionException;
|
||||
|
||||
public abstract void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException;
|
||||
public abstract void install(@Nullable List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException;
|
||||
|
||||
public abstract void uninstall(@NotNull List<PyPackage> packages) throws ExecutionException;
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
import com.jetbrains.python.sdk.PySdkExtKt;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.sdk.flavors.PipEnvInstallQuickFix;
|
||||
import com.jetbrains.python.sdk.flavors.PipenvKt;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -111,7 +113,12 @@ public class PyPackageRequirementsInspection extends PyInspection {
|
||||
unsatisfiedNames.add(req.getName() + req.getExtras());
|
||||
}
|
||||
final List<LocalQuickFix> quickFixes = new ArrayList<>();
|
||||
quickFixes.add(new PyInstallRequirementsFix(null, module, sdk, unsatisfied));
|
||||
if (PipenvKt.isPipEnv(sdk)) {
|
||||
quickFixes.add(new PipEnvInstallQuickFix());
|
||||
}
|
||||
else {
|
||||
quickFixes.add(new PyInstallRequirementsFix(null, module, sdk, unsatisfied));
|
||||
}
|
||||
quickFixes.add(new IgnoreRequirementFix(unsatisfiedNames));
|
||||
registerProblem(file, msg,
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null,
|
||||
@@ -402,7 +409,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
|
||||
return;
|
||||
}
|
||||
if (!PyPackageUtil.hasManagement(packages)) {
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new UIListener(myModule) {
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new RunningPackagingTasksListener(myModule) {
|
||||
@Override
|
||||
public void finished(List<ExecutionException> exceptions) {
|
||||
super.finished(exceptions);
|
||||
@@ -419,7 +426,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
|
||||
}
|
||||
|
||||
private void installRequirements(Project project, List<PyRequirement> requirements) {
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new UIListener(myModule));
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new RunningPackagingTasksListener(myModule));
|
||||
ui.install(requirements, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -468,7 +475,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
|
||||
|
||||
private void installAndImportPackage(@NotNull Project project) {
|
||||
if (mySdk == null) return;
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new UIListener(myModule) {
|
||||
final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new RunningPackagingTasksListener(myModule) {
|
||||
@Override
|
||||
public void finished(List<ExecutionException> exceptions) {
|
||||
super.finished(exceptions);
|
||||
@@ -488,10 +495,10 @@ public class PyPackageRequirementsInspection extends PyInspection {
|
||||
}
|
||||
}
|
||||
|
||||
private static class UIListener implements PyPackageManagerUI.Listener {
|
||||
private final Module myModule;
|
||||
public static class RunningPackagingTasksListener implements PyPackageManagerUI.Listener {
|
||||
@NotNull private final Module myModule;
|
||||
|
||||
public UIListener(Module module) {
|
||||
public RunningPackagingTasksListener(@NotNull Module module) {
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,9 @@ public class PyCondaPackageManagerImpl extends PyPackageManagerImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException {
|
||||
public void install(@Nullable List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException {
|
||||
if (useConda) {
|
||||
if (requirements == null) return;
|
||||
final ArrayList<String> arguments = new ArrayList<>();
|
||||
for (PyRequirement requirement : requirements) {
|
||||
arguments.add(requirement.getPresentableText());
|
||||
|
||||
@@ -178,7 +178,8 @@ public class PyPackageManagerImpl extends PyPackageManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException {
|
||||
public void install(@Nullable List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws ExecutionException {
|
||||
if (requirements == null) return;
|
||||
installManagement();
|
||||
final List<String> args = new ArrayList<>();
|
||||
args.add(INSTALL);
|
||||
|
||||
@@ -68,7 +68,7 @@ public class PyPackageManagerUI {
|
||||
ProgressManager.getInstance().run(new InstallManagementTask(myProject, mySdk, myListener));
|
||||
}
|
||||
|
||||
public void install(@NotNull final List<PyRequirement> requirements, @NotNull final List<String> extraArgs) {
|
||||
public void install(@Nullable final List<PyRequirement> requirements, @NotNull final List<String> extraArgs) {
|
||||
ProgressManager.getInstance().run(new InstallTask(myProject, mySdk, requirements, extraArgs, myListener));
|
||||
}
|
||||
|
||||
@@ -225,12 +225,12 @@ public class PyPackageManagerUI {
|
||||
}
|
||||
|
||||
private static class InstallTask extends PackagingTask {
|
||||
@NotNull private final List<PyRequirement> myRequirements;
|
||||
@Nullable private final List<PyRequirement> myRequirements;
|
||||
@NotNull private final List<String> myExtraArgs;
|
||||
|
||||
public InstallTask(@Nullable Project project,
|
||||
@NotNull Sdk sdk,
|
||||
@NotNull List<PyRequirement> requirements,
|
||||
@Nullable List<PyRequirement> requirements,
|
||||
@NotNull List<String> extraArgs,
|
||||
@Nullable Listener listener) {
|
||||
super(project, sdk, "Installing packages", listener);
|
||||
@@ -242,29 +242,44 @@ public class PyPackageManagerUI {
|
||||
@Override
|
||||
protected List<ExecutionException> runTask(@NotNull ProgressIndicator indicator) {
|
||||
final List<ExecutionException> exceptions = new ArrayList<>();
|
||||
final int size = myRequirements.size();
|
||||
final PyPackageManager manager = PyPackageManagers.getInstance().forSdk(mySdk);
|
||||
for (int i = 0; i < size; i++) {
|
||||
final PyRequirement requirement = myRequirements.get(i);
|
||||
indicator.setText(String.format("Installing package '%s'...", requirement.getPresentableText()));
|
||||
if (i == 0) {
|
||||
indicator.setIndeterminate(true);
|
||||
}
|
||||
else {
|
||||
indicator.setIndeterminate(false);
|
||||
indicator.setFraction((double)i / size);
|
||||
}
|
||||
if (myRequirements == null) {
|
||||
indicator.setText("Installing packages...");
|
||||
indicator.setIndeterminate(true);
|
||||
try {
|
||||
manager.install(Collections.singletonList(requirement), myExtraArgs);
|
||||
manager.install(null, myExtraArgs);
|
||||
}
|
||||
catch (RunCanceledByUserException e) {
|
||||
exceptions.add(e);
|
||||
break;
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final int size = myRequirements.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final PyRequirement requirement = myRequirements.get(i);
|
||||
indicator.setText(String.format("Installing package '%s'...", 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();
|
||||
return exceptions;
|
||||
}
|
||||
@@ -278,7 +293,9 @@ public class PyPackageManagerUI {
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getSuccessDescription() {
|
||||
return "Installed packages: " + PyPackageUtil.requirementsToString(myRequirements);
|
||||
return myRequirements != null ?
|
||||
"Installed packages: " + PyPackageUtil.requirementsToString(myRequirements) :
|
||||
"Installed all requirements";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -30,10 +30,11 @@ class PyPipEnvPackageManager(val sdk: Sdk) : PyPackageManager() {
|
||||
install(parseRequirements(requirementString), emptyList())
|
||||
}
|
||||
|
||||
override fun install(requirements: List<PyRequirement>, extraArgs: List<String>) {
|
||||
val args = listOf("install") +
|
||||
requirements.flatMap { it.installOptions } +
|
||||
extraArgs
|
||||
override fun install(requirements: List<PyRequirement>?, extraArgs: List<String>) {
|
||||
val args = listOfNotNull(listOf("install"),
|
||||
requirements?.flatMap { it.installOptions },
|
||||
extraArgs)
|
||||
.flatten()
|
||||
try {
|
||||
runPipEnv(sdk, *args.toTypedArray())
|
||||
}
|
||||
|
||||
@@ -29,10 +29,8 @@ import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.PathUtil
|
||||
import com.jetbrains.python.packaging.PyExecutionException
|
||||
import com.jetbrains.python.packaging.PyPackageManager
|
||||
import com.jetbrains.python.packaging.PyPackageManagers
|
||||
import com.jetbrains.python.packaging.PyRequirement
|
||||
import com.jetbrains.python.inspections.PyPackageRequirementsInspection
|
||||
import com.jetbrains.python.packaging.*
|
||||
import com.jetbrains.python.sdk.*
|
||||
import icons.PythonIcons
|
||||
import org.jetbrains.annotations.SystemDependent
|
||||
@@ -225,9 +223,6 @@ class UsePipEnvQuickFix : LocalQuickFix {
|
||||
fun isApplicable(module: Module): Boolean = module.pipFile != null
|
||||
|
||||
fun setUpPipEnv(project: Project, module: Module) {
|
||||
if (project.isDisposed || module.isDisposed) {
|
||||
return
|
||||
}
|
||||
val sdksModel = ProjectSdksModel().apply {
|
||||
reset(project)
|
||||
}
|
||||
@@ -251,11 +246,34 @@ class UsePipEnvQuickFix : LocalQuickFix {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return
|
||||
// Invoke the setup later to escape the write action of the quick fix in order to show the modal progress dialog
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
if (project.isDisposed || module.isDisposed) return@invokeLater
|
||||
setUpPipEnv(project, module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A quick-fix for installing packages specified in Pipfile.
|
||||
*/
|
||||
class PipEnvInstallQuickFix : LocalQuickFix {
|
||||
companion object {
|
||||
fun pipEnvInstall(project: Project, module: Module) {
|
||||
val sdk = module.pythonSdk ?: return
|
||||
val listener = PyPackageRequirementsInspection.RunningPackagingTasksListener(module)
|
||||
val ui = PyPackageManagerUI(project, sdk, listener)
|
||||
ui.install(null, listOf("--dev"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFamilyName() = "Install requirements from Pipfile"
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val element = descriptor.psiElement ?: return
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return
|
||||
pipEnvInstall(project, module)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Sdk.parsePipFileLock(): PipFileLock? {
|
||||
// TODO: Log errors if Pipfile.lock is not found
|
||||
val file = pipFileLock ?: return null
|
||||
|
||||
Reference in New Issue
Block a user