New package operation failure dialog

This commit is contained in:
Andrey Vlasovskikh
2014-09-30 17:35:47 +04:00
parent f249aa6e8d
commit 004d6cf844
5 changed files with 250 additions and 36 deletions
@@ -20,23 +20,18 @@ import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author vlan
*/
public class PyExecutionException extends ExecutionException {
private static final Pattern WITH_CR_DELIMITER_PATTERN = Pattern.compile("(?<=\r|\n|\r\n)");
@NotNull private String myCommand;
@NotNull private List<String> myArgs;
@NotNull private final String myStdout;
@NotNull private final String myStderr;
private final int myExitCode;
@NotNull private String myMessage;
@NotNull private final List<? extends PyExecutionFix> myFixes;
public PyExecutionException(@NotNull String message, @NotNull String command, @NotNull List<String> args) {
@@ -56,7 +51,6 @@ public class PyExecutionException extends ExecutionException {
myStdout = stdout;
myStderr = stderr;
myExitCode = exitCode;
myMessage = stripLinesWithoutLineFeeds(message);
myFixes = fixes;
}
@@ -84,23 +78,6 @@ public class PyExecutionException extends ExecutionException {
return myArgs;
}
@NotNull
public String getMessage() {
return myMessage;
}
@NotNull
private static String stripLinesWithoutLineFeeds(@NotNull String s) {
final String[] lines = WITH_CR_DELIMITER_PATTERN.split(s);
final List<String> result = new ArrayList<String>();
for (String line : lines) {
if (!line.endsWith("\r")) {
result.add(line);
}
}
return StringUtil.join(result, "");
}
@NotNull
public List<? extends PyExecutionFix> getFixes() {
return myFixes;
@@ -488,15 +488,10 @@ public class PyPackageManagerImpl extends PyPackageManager {
if (result.isCancelled()) {
throw new RunCanceledByUserException();
}
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.";
}
final int exitCode = result.getExitCode();
if (exitCode != 0) {
final String message = StringUtil.isEmptyOrSpaces(result.getStdout()) && StringUtil.isEmptyOrSpaces(result.getStderr()) ?
"Permission denied" : "Non-zero exit code";
throw new PyExecutionException(message, helperPath, args, result);
}
return result;
@@ -33,18 +33,22 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Function;
import com.intellij.webcore.packaging.PackagesNotificationPanel;
import com.jetbrains.python.packaging.ui.PyPackageNotificationDialog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author vlan
*/
public class PyPackageManagerUI {
private static final Logger LOG = Logger.getInstance(PyPackageManagerUI.class);
@NotNull private static final Logger LOG = Logger.getInstance(PyPackageManagerUI.class);
@NotNull private static final Pattern PATTERN_ERROR_LINE = Pattern.compile(".*error:.*", Pattern.CASE_INSENSITIVE);
@Nullable private Listener myListener;
@NotNull private Project myProject;
@NotNull private Sdk mySdk;
@@ -55,6 +59,33 @@ public class PyPackageManagerUI {
void finished(List<ExecutionException> exceptions);
}
public static class ExecutionFailure {
@NotNull private final String myMessage;
@Nullable private final String myCommand;
@Nullable private final String myOutput;
public ExecutionFailure(@NotNull String message, @Nullable String command, @Nullable String output) {
myMessage = message;
myCommand = command;
myOutput = output;
}
@NotNull
public String getMessage() {
return myMessage;
}
@Nullable
public String getCommand() {
return myCommand;
}
@Nullable
public String getOutput() {
return myOutput;
}
}
public PyPackageManagerUI(@NotNull Project project, @NotNull Sdk sdk, @Nullable Listener listener) {
myProject = project;
mySdk = sdk;
@@ -184,8 +215,8 @@ public class PyPackageManagerUI {
NotificationType.INFORMATION));
}
else if (!isCancelled(exceptions)) {
final ExecutionFailure failure = analyzeException(exceptions.get(0));
final String firstLine = getTitle() + ": error occurred.";
final String description = createDescription(exceptions, firstLine);
notificationRef.set(new Notification(PACKAGING_GROUP_ID, getFailureTitle(),
firstLine + " <a href=\"xxx\">Details...</a>",
NotificationType.ERROR,
@@ -194,7 +225,9 @@ public class PyPackageManagerUI {
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
assert myProject != null;
PackagesNotificationPanel.showError(myProject, getFailureTitle(), description);
final String title = StringUtil.capitalizeWords(getFailureTitle(), true);
final PyPackageNotificationDialog dialog = new PyPackageNotificationDialog(title, failure);
dialog.show();
}
}
));
@@ -386,4 +419,28 @@ public class PyPackageManagerUI {
}
return b.toString();
}
@NotNull
private static ExecutionFailure analyzeException(@NotNull ExecutionException e) {
if (e instanceof PyExecutionException) {
final PyExecutionException ee = (PyExecutionException)e;
final String stdoutCause = findErrorCause(ee.getStdout());
final String stderrCause = findErrorCause(ee.getStderr());
final String message = stdoutCause != null ? stdoutCause : stderrCause != null ? stderrCause : ee.getMessage();
return new ExecutionFailure(message, ee.getCommand() + " " + StringUtil.join(ee.getArgs(), " "), ee.getStdout());
}
else {
return new ExecutionFailure(e.getMessage(), null, null);
}
}
@Nullable
private static String findErrorCause(@NotNull String output) {
final Matcher m = PATTERN_ERROR_LINE.matcher(output);
if (m.find()) {
final String result = m.group();
return result != null ? result.trim() : null;
}
return null;
}
}
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.packaging.ui.PyPackageNotificationDialog">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="604" height="929"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<vspacer id="de4c">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="a16a8" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="294" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Error occurred:"/>
</properties>
</component>
<component id="23f72" class="com.intellij.ui.components.JBLabel" binding="myErrorMessage">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/>
</constraints>
<properties>
<foreground color="-4511744"/>
<text value="Unknown error"/>
</properties>
</component>
</children>
</grid>
<grid id="8cad" binding="myCommandOutputPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="4e743" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<labelFor value="6fb53"/>
<text value="Command output:"/>
</properties>
</component>
<scrollpane id="6fb53" class="com.intellij.ui.components.JBScrollPane">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="9" fill="0" indent="2" use-parent-layout="false">
<preferred-size width="700" height="300"/>
<maximum-size width="700" height="300"/>
</grid>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="307b8" class="javax.swing.JTextArea" binding="myCommandOutput">
<constraints/>
<properties>
<editable value="false"/>
<text value="No output"/>
</properties>
</component>
</children>
</scrollpane>
</children>
</grid>
<grid id="4cbff" binding="myCommandPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="2e7d0" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Executed command:"/>
</properties>
</component>
<scrollpane id="c24f2" class="com.intellij.ui.components.JBScrollPane">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="9" fill="0" indent="2" use-parent-layout="false">
<preferred-size width="700" height="60"/>
<maximum-size width="700" height="60"/>
</grid>
</constraints>
<properties>
<verticalScrollBarPolicy value="21"/>
</properties>
<border type="none"/>
<children>
<component id="fb0fa" class="javax.swing.JTextArea" binding="myCommand">
<constraints/>
<properties>
<editable value="false"/>
<text value="None"/>
</properties>
</component>
</children>
</scrollpane>
</children>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,63 @@
/*
* 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.ui;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.components.JBLabel;
import com.jetbrains.python.packaging.PyPackageManagerUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author vlan
*/
public class PyPackageNotificationDialog extends DialogWrapper {
private JPanel myMainPanel;
private JBLabel myErrorMessage;
private JTextArea myCommand;
private JTextArea myCommandOutput;
private JPanel myCommandOutputPanel;
private JPanel myCommandPanel;
public PyPackageNotificationDialog(@NotNull String title, @NotNull PyPackageManagerUI.ExecutionFailure failure) {
super(false);
init();
setResizable(false);
setTitle(title);
final String command = failure.getCommand();
final String output = failure.getOutput();
final String message = failure.getMessage();
myCommandPanel.setVisible(command != null);
myCommandOutputPanel.setVisible(output != null);
myErrorMessage.setText(message);
if (command != null) {
myCommand.setText(command);
}
if (output != null) {
myCommandOutput.setText(output);
}
}
@Nullable
@Override
protected JComponent createCenterPanel() {
return myMainPanel;
}
}