diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyProcessCancelledException.java b/python/openapi/src/com/jetbrains/python/packaging/PyProcessCancelledException.java new file mode 100644 index 000000000000..9721bec0bb86 --- /dev/null +++ b/python/openapi/src/com/jetbrains/python/packaging/PyProcessCancelledException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2014 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.jetbrains.python.packaging; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author vlan + */ +public class PyProcessCancelledException extends PyExternalProcessException { + public PyProcessCancelledException(@NotNull String name, @NotNull List args) { + super(255, name, args, "Process cancelled"); + } +} diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index 9b5f669168f7..b9fc6889f715 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -17,12 +17,15 @@ package com.jetbrains.python.packaging; import com.google.common.collect.Lists; import com.intellij.execution.ExecutionException; +import com.intellij.execution.process.CapturingProcessHandler; import com.intellij.execution.process.ProcessOutput; import com.intellij.execution.util.ExecUtil; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; import com.intellij.openapi.roots.OrderRootType; @@ -35,7 +38,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; -import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.net.HttpConfigurable; @@ -469,36 +471,53 @@ public class PyPackageManagerImpl extends PyPackageManager { LOG.info("Running packaging tool: " + StringUtil.join(cmdline, " ")); final boolean canCreate = FileUtil.ensureCanCreateFile(new File(homePath)); - if (!canCreate && !SystemInfo.isWindows && askForSudo) { //is system site interpreter --> we need sudo privileges - try { - final ProcessOutput result = ExecUtil.sudoAndGetOutput(cmdline, - "Please enter your password to make changes in system packages: ", - workingDir); - String message = result.getStderr(); - if (result.getExitCode() != 0) { - final String stdout = result.getStdout(); - if (StringUtil.isEmptyOrSpaces(message)) { - message = stdout; - } - if (StringUtil.isEmptyOrSpaces(message)) { - message = "Failed to perform action. Permission denied."; - } - throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message); + final boolean useSudo = !canCreate && !SystemInfo.isWindows && askForSudo; + + try { + final Process process; + if (useSudo) { + process = ExecUtil.sudo(cmdline, "Please enter your password to make changes in system packages: ", workingDir, null); + } + else { + process = ExecUtil.exec(cmdline, workingDir, null); + } + final CapturingProcessHandler handler = new CapturingProcessHandler(process); + // Make the progress indicator an explicit parameter? + final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + final ProcessOutput result; + if (indicator != null) { + result = handler.runProcessWithProgressIndicator(indicator); + } + else { + result = handler.runProcess(TIMEOUT); + } + if (result.isCancelled()) { + throw new PyProcessCancelledException(helperPath, args); + } + String message = result.getStderr(); + if (result.getExitCode() != 0) { + final String stdout = result.getStdout(); + if (StringUtil.isEmptyOrSpaces(message)) { + message = stdout; } - if (SystemInfo.isMac && !StringUtil.isEmptyOrSpaces(message)) { - throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message); + if (StringUtil.isEmptyOrSpaces(message)) { + message = "Failed to perform action. Permission denied."; } - return result; + throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message); } - catch (ExecutionException e) { - throw new PyExternalProcessException(ERROR_EXECUTION, helperPath, args, e.getMessage()); - } - catch (IOException e) { - throw new PyExternalProcessException(ERROR_ACCESS_DENIED, helperPath, args, e.getMessage()); + if (SystemInfo.isMac && !StringUtil.isEmptyOrSpaces(message)) { + throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message); } + return result; } - else { - return PySdkUtil.getProcessOutput(workingDir, ArrayUtil.toStringArray(cmdline), TIMEOUT); + catch (PyProcessCancelledException e) { + throw e; + } + catch (ExecutionException e) { + throw new PyExternalProcessException(ERROR_EXECUTION, helperPath, args, e.getMessage()); + } + catch (IOException e) { + throw new PyExternalProcessException(ERROR_ACCESS_DENIED, helperPath, args, e.getMessage()); } } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java index 28dfa6c834a4..c263432680ca 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java @@ -181,7 +181,7 @@ public class PyPackageManagerUI { notificationRef.set(new Notification(PACKAGING_GROUP_ID, getSuccessTitle(), getSuccessDescription(), NotificationType.INFORMATION)); } - else { + else if (!isCancelled(exceptions)) { final String firstLine = getTitle() + ": error occurred."; final String description = createDescription(exceptions, firstLine); notificationRef.set(new Notification(PACKAGING_GROUP_ID, getFailureTitle(), @@ -210,6 +210,15 @@ public class PyPackageManagerUI { } }); } + + private static boolean isCancelled(@NotNull List exceptions) { + for (PyExternalProcessException e : exceptions) { + if (e instanceof PyProcessCancelledException) { + return true; + } + } + return false; + } } private static class InstallTask extends PackagingTask { @@ -241,6 +250,10 @@ public class PyPackageManagerUI { try { manager.install(Arrays.asList(requirement), myExtraArgs); } + catch (PyProcessCancelledException e) { + exceptions.add(e); + break; + } catch (PyExternalProcessException e) { exceptions.add(e); }