Gradle: handle and report errors happened before the gradle invocation, e.g. when the Gradle JDK is invalid (IDEA-181146, IDEA-183962, IDEA-184410)

This commit is contained in:
Vladislav.Soroka
2018-01-09 18:11:54 +03:00
parent c10df50677
commit 3cd1e36de3
9 changed files with 189 additions and 109 deletions
@@ -0,0 +1,78 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.intellij.build;
import com.intellij.build.events.Failure;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.notification.Notification;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Vladislav.Soroka
*/
public class BuildConsoleUtils {
private static final Pattern TAG_PATTERN = Pattern.compile("<[^>]*>");
private static final Pattern A_PATTERN = Pattern.compile("<a ([^>]* )?href=[\"\']([^>]*)[\"\'][^>]*>");
private static final String A_CLOSING = "</a>";
private static final Set<String> NEW_LINES = ContainerUtil.set("<br>", "</br>", "<br/>", "<p>", "</p>", "<p/>", "<pre>", "</pre>");
public static boolean printFailure(ConsoleView consoleView, Failure failure) {
String text = ObjectUtils.chooseNotNull(failure.getDescription(), failure.getMessage());
if (text == null && failure.getError() != null) {
text = failure.getError().getMessage();
}
if (text == null) return false;
String content = StringUtil.convertLineSeparators(text);
while (true) {
Matcher tagMatcher = TAG_PATTERN.matcher(content);
if (!tagMatcher.find()) {
consoleView.print(content, ConsoleViewContentType.ERROR_OUTPUT);
break;
}
String tagStart = tagMatcher.group();
consoleView.print(content.substring(0, tagMatcher.start()), ConsoleViewContentType.ERROR_OUTPUT);
Matcher aMatcher = A_PATTERN.matcher(tagStart);
if (aMatcher.matches()) {
final String href = aMatcher.group(2);
int linkEnd = content.indexOf(A_CLOSING, tagMatcher.end());
if (linkEnd > 0) {
String linkText = content.substring(tagMatcher.end(), linkEnd).replaceAll(TAG_PATTERN.pattern(), "");
consoleView.printHyperlink(linkText, new HyperlinkInfo() {
@Override
public void navigate(Project project) {
Notification notification = failure.getNotification();
if (notification != null && notification.getListener() != null) {
notification.getListener().hyperlinkUpdate(
notification, IJSwingUtilities.createHyperlinkEvent(href, consoleView.getComponent()));
}
}
});
content = content.substring(linkEnd + A_CLOSING.length());
continue;
}
}
if (NEW_LINES.contains(tagStart)) {
consoleView.print("\n", ConsoleViewContentType.SYSTEM_OUTPUT);
}
else {
consoleView.print(content.substring(tagMatcher.start(), tagMatcher.end()), ConsoleViewContentType.ERROR_OUTPUT);
}
content = content.substring(tagMatcher.end());
}
consoleView.print("\n", ConsoleViewContentType.SYSTEM_OUTPUT);
return true;
}
}
@@ -9,7 +9,6 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.icons.AllIcons;
import com.intellij.notification.Notification;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsManager;
@@ -32,7 +31,9 @@ import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns;
import com.intellij.ui.treeStructure.treetable.TreeColumnInfo;
import com.intellij.ui.treeStructure.treetable.TreeTable;
import com.intellij.ui.treeStructure.treetable.TreeTableTree;
import com.intellij.util.*;
import com.intellij.util.Alarm;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.EditSourceOnEnterKeyHandler;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.ColumnInfo;
@@ -57,8 +58,6 @@ import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Vladislav.Soroka
@@ -600,11 +599,6 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
}
private static class DetailsHandler {
private static final Pattern TAG_PATTERN = Pattern.compile("<[^>]*>");
private static final Pattern A_PATTERN = Pattern.compile("<a ([^>]* )?href=[\"\']([^>]*)[\"\'][^>]*>");
private static final String A_CLOSING = "</a>";
private static final Set<String> NEW_LINES = ContainerUtil.set("<br>", "</br>", "<br/>", "<p>", "</p>", "<p/>", "<pre>", "</pre>");
private final ThreeComponentsSplitter mySplitter;
@Nullable
private ExecutionNode myExecutionNode;
@@ -650,12 +644,7 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
boolean hasChanged = false;
for (Iterator<? extends Failure> iterator = failures.iterator(); iterator.hasNext(); ) {
Failure failure = iterator.next();
String text = ObjectUtils.chooseNotNull(failure.getDescription(), failure.getMessage());
if (text == null && failure.getError() != null) {
text = failure.getError().getMessage();
}
if (text == null) continue;
printDetails(failure, text);
if (!printFailure(failure)) continue;
hasChanged = true;
if (iterator.hasNext()) {
myConsole.print("\n\n", ConsoleViewContentType.NORMAL_OUTPUT);
@@ -675,44 +664,8 @@ public class BuildTreeConsoleView implements ConsoleView, DataProvider, BuildCon
return true;
}
public void printDetails(Failure failure, String text) {
String content = StringUtil.convertLineSeparators(text);
while (true) {
Matcher tagMatcher = TAG_PATTERN.matcher(content);
if (!tagMatcher.find()) {
myConsole.print(content, ConsoleViewContentType.ERROR_OUTPUT);
break;
}
String tagStart = tagMatcher.group();
myConsole.print(content.substring(0, tagMatcher.start()), ConsoleViewContentType.ERROR_OUTPUT);
Matcher aMatcher = A_PATTERN.matcher(tagStart);
if (aMatcher.matches()) {
final String href = aMatcher.group(2);
int linkEnd = content.indexOf(A_CLOSING, tagMatcher.end());
if (linkEnd > 0) {
String linkText = content.substring(tagMatcher.end(), linkEnd).replaceAll(TAG_PATTERN.pattern(), "");
myConsole.printHyperlink(linkText, new HyperlinkInfo() {
@Override
public void navigate(Project project) {
Notification notification = failure.getNotification();
if (notification != null && notification.getListener() != null) {
notification.getListener().hyperlinkUpdate(
notification, IJSwingUtilities.createHyperlinkEvent(href, myConsole.getComponent()));
}
}
});
content = content.substring(linkEnd + A_CLOSING.length());
continue;
}
}
if (NEW_LINES.contains(tagStart)) {
myConsole.print("\n", ConsoleViewContentType.SYSTEM_OUTPUT);
}
else {
myConsole.print(content.substring(tagMatcher.start(), tagMatcher.end()), ConsoleViewContentType.ERROR_OUTPUT);
}
content = content.substring(tagMatcher.end());
}
private boolean printFailure(Failure failure) {
return BuildConsoleUtils.printFailure(myConsole, failure);
}
public void setNode(@Nullable DefaultMutableTreeNode node) {
@@ -15,7 +15,7 @@
*/
package com.intellij.openapi.externalSystem.service.execution;
import com.intellij.openapi.externalSystem.model.LocationAwareExternalSystemException;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -23,12 +23,19 @@ import org.jetbrains.annotations.Nullable;
* @author Vladislav.Soroka
* @since 12/12/2014
*/
public class ExternalSystemJdkException extends LocationAwareExternalSystemException {
public class ExternalSystemJdkException extends ExternalSystemException {
@Deprecated
public ExternalSystemJdkException(@Nullable String message,
@Nullable String filePath,
@Nullable Throwable cause,
@NotNull String... quickFixes) {
super(message, cause, filePath, -1, -1, quickFixes);
this(message, cause, quickFixes);
}
public ExternalSystemJdkException(@Nullable String message,
@Nullable Throwable cause,
@NotNull String... quickFixes) {
super(message, cause, quickFixes);
}
}
@@ -5,7 +5,7 @@ package com.intellij.openapi.externalSystem.service.execution;
import com.intellij.build.*;
import com.intellij.build.events.BuildEvent;
import com.intellij.build.events.impl.FailureResultImpl;
import com.intellij.build.events.FailureResult;
import com.intellij.build.events.impl.FinishBuildEventImpl;
import com.intellij.build.events.impl.StartBuildEventImpl;
import com.intellij.build.events.impl.SuccessResultImpl;
@@ -63,7 +63,6 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ExceptionUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.net.NetUtils;
@@ -386,15 +385,13 @@ public class ExternalSystemRunConfiguration extends LocatableConfigurationBase i
@Override
public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) {
FailureResult failureResult =
ExternalSystemUtil.createFailureResult(executionName + " failed", e, id.getProjectSystemId(), myProject);
if (progressListener != null) {
FailureResultImpl failureResult =
ExternalSystemUtil.createFailureResult(executionName + " failed", e, id.getProjectSystemId(), myProject);
progressListener.onEvent(new FinishBuildEventImpl(
id, null, System.currentTimeMillis(), "failed", failureResult));
}
String exceptionMessage = ExceptionUtil.getMessage(e);
String text = exceptionMessage == null ? e.toString() : exceptionMessage;
processHandler.notifyTextAvailable(text + '\n', ProcessOutputTypes.STDERR);
ExternalSystemUtil.printFailure(e, failureResult, consoleView, processHandler);
processHandler.notifyProcessTerminated(1);
}
@@ -20,9 +20,12 @@ import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType;
import com.intellij.openapi.externalSystem.service.ExternalSystemFacadeManager;
import com.intellij.openapi.externalSystem.service.RemoteExternalSystemFacade;
import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager;
import com.intellij.openapi.externalSystem.service.remote.ExternalSystemProgressNotificationManagerImpl;
import com.intellij.openapi.externalSystem.service.remote.RemoteExternalSystemTaskManager;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
@@ -130,26 +133,42 @@ public class ExternalSystemExecuteTaskTask extends AbstractExternalSystemTask {
@SuppressWarnings("unchecked")
@Override
protected void doExecute() throws Exception {
final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
ExternalSystemExecutionSettings settings = ExternalSystemApiUtil.getExecutionSettings(getIdeProject(),
getExternalProjectPath(),
getExternalSystemId());
KeyFMap keyFMap = getUserMap();
for (Key key : keyFMap.getKeys()) {
settings.putUserData(key, keyFMap.get(key));
}
RemoteExternalSystemFacade facade = manager.getFacade(getIdeProject(), getExternalProjectPath(), getExternalSystemId());
RemoteExternalSystemTaskManager taskManager = facade.getTaskManager();
final List<String> vmOptions = parseCmdParameters(myVmOptions);
final List<String> arguments = parseCmdParameters(myArguments);
settings
.withVmOptions(vmOptions)
.withArguments(arguments)
.withEnvironmentVariables(myEnv)
.passParentEnvs(myPassParentEnvs);
ExternalSystemProgressNotificationManagerImpl progressNotificationManager =
(ExternalSystemProgressNotificationManagerImpl)ServiceManager.getService(ExternalSystemProgressNotificationManager.class);
ExternalSystemTaskId id = getId();
String projectPath = getExternalProjectPath();
taskManager.executeTasks(getId(), myTasksToExecute, getExternalProjectPath(), settings, myJvmAgentSetup);
ExternalSystemExecutionSettings settings;
RemoteExternalSystemTaskManager taskManager;
try {
progressNotificationManager.onStart(id, projectPath);
final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
settings = ExternalSystemApiUtil.getExecutionSettings(getIdeProject(),
projectPath,
getExternalSystemId());
KeyFMap keyFMap = getUserMap();
for (Key key : keyFMap.getKeys()) {
settings.putUserData(key, keyFMap.get(key));
}
RemoteExternalSystemFacade facade = manager.getFacade(getIdeProject(), projectPath, getExternalSystemId());
taskManager = facade.getTaskManager();
final List<String> vmOptions = parseCmdParameters(myVmOptions);
final List<String> arguments = parseCmdParameters(myArguments);
settings
.withVmOptions(vmOptions)
.withArguments(arguments)
.withEnvironmentVariables(myEnv)
.passParentEnvs(myPassParentEnvs);
}
catch (Exception e) {
progressNotificationManager.onFailure(id, e);
progressNotificationManager.onEnd(id);
throw e;
}
taskManager.executeTasks(id, myTasksToExecute, projectPath, settings, myJvmAgentSetup);
}
@Override
@@ -3,6 +3,7 @@ package com.intellij.openapi.externalSystem.service.internal;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.internal.InternalExternalProjectInfo;
@@ -68,21 +69,33 @@ public class ExternalSystemResolveProjectTask extends AbstractExternalSystemTask
@SuppressWarnings("unchecked")
protected void doExecute() throws Exception {
final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
Project ideProject = getIdeProject();
RemoteExternalSystemProjectResolver resolver = manager.getFacade(ideProject, myProjectPath, getExternalSystemId()).getResolver();
ExternalSystemExecutionSettings settings = ExternalSystemApiUtil.getExecutionSettings(ideProject, myProjectPath, getExternalSystemId());
if(StringUtil.isNotEmpty(myVmOptions)) {
settings.withVmOptions(ParametersListUtil.parse(myVmOptions));
}
if(StringUtil.isNotEmpty(myArguments)) {
settings.withArguments(ParametersListUtil.parse(myArguments));
}
ExternalSystemProgressNotificationManagerImpl progressNotificationManager =
(ExternalSystemProgressNotificationManagerImpl)ServiceManager.getService(ExternalSystemProgressNotificationManager.class);
ExternalSystemTaskId id = getId();
progressNotificationManager.onStart(id, myProjectPath);
Project ideProject;
RemoteExternalSystemProjectResolver resolver;
ExternalSystemExecutionSettings settings;
try {
progressNotificationManager.onStart(id, myProjectPath);
final ExternalSystemFacadeManager manager = ServiceManager.getService(ExternalSystemFacadeManager.class);
ideProject = getIdeProject();
resolver = manager.getFacade(ideProject, myProjectPath, getExternalSystemId()).getResolver();
settings = ExternalSystemApiUtil.getExecutionSettings(ideProject, myProjectPath, getExternalSystemId());
if (StringUtil.isNotEmpty(myVmOptions)) {
settings.withVmOptions(ParametersListUtil.parse(myVmOptions));
}
if (StringUtil.isNotEmpty(myArguments)) {
settings.withArguments(ParametersListUtil.parse(myArguments));
}
}
catch (Exception e) {
progressNotificationManager.onFailure(id, e);
progressNotificationManager.onEnd(id);
throw e;
}
try {
DataNode<ProjectData> project = resolver.resolveProjectInfo(id, myProjectPath, myIsPreviewMode, settings);
if (project != null) {
@@ -48,7 +48,6 @@ public class ExternalSystemTaskManagerWrapper<S extends ExternalSystemExecutionS
@NotNull String projectPath,
@Nullable S settings,
@Nullable String jvmAgentSetup) throws RemoteException, ExternalSystemException {
myProgressManager.onStart(id, projectPath);
try {
getDelegate().executeTasks(id, taskNames, projectPath, settings, jvmAgentSetup);
myProgressManager.onSuccess(id);
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.externalSystem.util;
import com.intellij.build.BuildConsoleUtils;
import com.intellij.build.BuildContentDescriptor;
import com.intellij.build.DefaultBuildDescriptor;
import com.intellij.build.SyncViewManager;
@@ -36,6 +37,7 @@ import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.rmi.RemoteUtil;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.icons.AllIcons;
import com.intellij.notification.Notification;
@@ -512,13 +514,12 @@ public class ExternalSystemUtil {
public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception e) {
String title = ExternalSystemBundle.message("notification.project.refresh.fail.title",
externalSystemId.getReadableName(), projectName);
FailureResultImpl failureResult = createFailureResult(title, e, externalSystemId, project);
com.intellij.build.events.FailureResult failureResult = createFailureResult(title, e, externalSystemId, project);
String message = isPreviewMode ? "project preview creation failed" : "sync failed";
ServiceManager.getService(project, SyncViewManager.class).onEvent(
new FinishBuildEventImpl(id, null, System.currentTimeMillis(), message, failureResult));
String exceptionMessage = ExceptionUtil.getMessage(e);
String text = exceptionMessage == null ? e.toString() : exceptionMessage;
processHandler.notifyTextAvailable(text + '\n', ProcessOutputTypes.STDERR);
printFailure(e, failureResult, consoleView, processHandler);
processHandler.notifyProcessTerminated(1);
}
@@ -625,11 +626,27 @@ public class ExternalSystemUtil {
}
}
public static void printFailure(@NotNull Exception e,
com.intellij.build.events.FailureResult failureResult,
ExecutionConsole consoleView,
ExternalSystemProcessHandler processHandler) {
if (consoleView instanceof ConsoleView) {
for (com.intellij.build.events.Failure failure : failureResult.getFailures()) {
BuildConsoleUtils.printFailure((ConsoleView)consoleView, failure);
}
}
else {
String exceptionMessage = ExceptionUtil.getMessage(e);
String text = exceptionMessage == null ? e.toString() : exceptionMessage;
processHandler.notifyTextAvailable(text + '\n', ProcessOutputTypes.STDERR);
}
}
@NotNull
public static FailureResultImpl createFailureResult(@NotNull String title,
@NotNull Exception exception,
@NotNull ProjectSystemId externalSystemId,
@NotNull Project project) {
public static com.intellij.build.events.FailureResult createFailureResult(@NotNull String title,
@NotNull Exception exception,
@NotNull ProjectSystemId externalSystemId,
@NotNull Project project) {
ExternalSystemNotificationManager notificationManager = ExternalSystemNotificationManager.getInstance(project);
NotificationData notificationData = notificationManager.createNotification(title, exception, externalSystemId, project);
return createFailureResult(exception, externalSystemId, project, notificationManager, notificationData);
@@ -151,23 +151,20 @@ public class GradleInstallationManager {
catch (ExternalSystemJdkException e) {
throw new ExternalSystemJdkException(
String.format("Invalid Gradle JDK configuration found. <a href='%s'>Open Gradle Settings</a> \n",
OpenExternalSystemSettingsCallback.ID),
linkedProjectPath, e, OpenExternalSystemSettingsCallback.ID);
OpenExternalSystemSettingsCallback.ID), e, OpenExternalSystemSettingsCallback.ID);
}
if (sdk == null && gradleJvm != null) {
throw new ExternalSystemJdkException(
String.format("Invalid Gradle JDK configuration found. <a href='%s'>Open Gradle Settings</a> \n",
OpenExternalSystemSettingsCallback.ID),
linkedProjectPath, null, OpenExternalSystemSettingsCallback.ID);
OpenExternalSystemSettingsCallback.ID), null, OpenExternalSystemSettingsCallback.ID);
}
String sdkHomePath = sdk != null ? sdk.getHomePath() : null;
if (sdkHomePath != null && JdkUtil.checkForJre(sdkHomePath) && !JdkUtil.checkForJdk(sdkHomePath)) {
throw new ExternalSystemJdkException(
String.format("Please, use JDK instead of JRE for Gradle importer. <a href='%s'>Open Gradle Settings</a> \n",
OpenExternalSystemSettingsCallback.ID),
linkedProjectPath, null, OpenExternalSystemSettingsCallback.ID);
OpenExternalSystemSettingsCallback.ID), null, OpenExternalSystemSettingsCallback.ID);
}
return sdk;