blob: 939313c8160862138ae22ad8805ac8121bc0be86 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.android.tools.idea.gradle.project;
import com.android.SdkConstants;
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
import com.intellij.openapi.util.Pair;
import org.gradle.tooling.UnsupportedVersionException;
import org.gradle.tooling.model.UnsupportedMethodException;
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.service.project.AbstractProjectImportErrorHandler;
import java.io.File;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import static com.android.SdkConstants.GRADLE_MINIMUM_VERSION;
import static com.android.SdkConstants.GRADLE_LATEST_VERSION;
/**
* Provides better error messages for android projects import failures.
*/
public class ProjectImportErrorHandler extends AbstractProjectImportErrorHandler {
public static final String FAILED_TO_PARSE_SDK_ERROR = "failed to parse SDK";
public static final String INSTALL_ANDROID_SUPPORT_REPO = "Please install the Android Support Repository from the Android SDK Manager.";
public static final String FIX_SDK_DIR_PROPERTY = "Please fix the 'sdk.dir' property in the local.properties file.";
private static final Pattern SDK_NOT_FOUND = Pattern.compile("The SDK directory '(.*?)' does not exist.");
private static final String EMPTY_LINE = "\n\n";
private static final String UNSUPPORTED_GRADLE_VERSION_ERROR = "Gradle version " + GRADLE_MINIMUM_VERSION + " is required";
private static final String SDK_DIR_PROPERTY_MISSING = "No sdk.dir property defined in local.properties file.";
@Override
@Nullable
public ExternalSystemException getUserFriendlyError(@NotNull Throwable error,
@NotNull String projectPath,
@Nullable String buildFilePath) {
if (error instanceof ExternalSystemException) {
// This is already a user-friendly error.
return (ExternalSystemException)error;
}
Pair<Throwable, String> rootCauseAndLocation = getRootCauseAndLocation(error);
Throwable rootCause = rootCauseAndLocation.getFirst();
if (isOldGradleVersion(rootCause)) {
String msg = String.format("You are using an unsupported version of Gradle. Please use version %1$s.", GRADLE_LATEST_VERSION);
msg += ('\n' + FIX_GRADLE_VERSION);
// Location of build.gradle is useless for this error. Omitting it.
return createUserFriendlyError(msg, null);
}
if (rootCause instanceof UnknownHostException) {
return createUserFriendlyError(String.format("Unknown host '%1$s'.", rootCause.getMessage()), null);
}
if (rootCause instanceof IllegalStateException || rootCause instanceof ExternalSystemException) {
// Missing platform in SDK now also comes as a ExternalSystemException. This may be caused by changes in IDEA's "External System
// Import" framework.
String msg = rootCause.getMessage();
if (msg != null) {
if (msg.startsWith("failed to find target android-")) {
// Location of build.gradle is useless for this error. Omitting it.
return createUserFriendlyError(msg, null);
}
if (msg.startsWith("failed to find Build Tools")) {
// Location of build.gradle is useless for this error. Omitting it.
return createUserFriendlyError(msg, null);
}
}
}
if (rootCause instanceof RuntimeException) {
String msg = rootCause.getMessage();
// With this condition we cover 2 similar messages about the same problem.
if (msg != null && msg.contains("Could not find") && msg.contains("com.android.support:")) {
// We keep the original error message and we append a hint about how to fix the missing dependency.
String newMsg = msg + EMPTY_LINE + INSTALL_ANDROID_SUPPORT_REPO;
// Location of build.gradle is useless for this error. Omitting it.
return createUserFriendlyError(newMsg, null);
}
if (msg != null && msg.contains(FAILED_TO_PARSE_SDK_ERROR)) {
String newMsg = msg + EMPTY_LINE + "The Android SDK may be missing the directory 'add-ons'.";
// Location of build.gradle is useless for this error. Omitting it.
return createUserFriendlyError(newMsg, null);
}
if (msg != null && (msg.equals(SDK_DIR_PROPERTY_MISSING) || SDK_NOT_FOUND.matcher(msg).matches())) {
String newMsg = msg;
File buildProperties = new File(projectPath, SdkConstants.FN_LOCAL_PROPERTIES);
if (buildProperties.isFile()) {
newMsg += EMPTY_LINE + FIX_SDK_DIR_PROPERTY;
}
return createUserFriendlyError(newMsg, null);
}
}
// give others GradleProjectResolverExtensions a chance to handle this error
return null;
}
private static boolean isOldGradleVersion(@NotNull Throwable error) {
if (error instanceof UnsupportedVersionException) {
return true;
}
if (error instanceof UnsupportedMethodException) {
String msg = error.getMessage();
if (msg != null && msg.contains("GradleProject.getBuildScript")) {
return true;
}
}
if (error instanceof ClassNotFoundException) {
String msg = error.getMessage();
if (msg != null && msg.contains(ToolingModelBuilderRegistry.class.getName())) {
return true;
}
}
if (error instanceof RuntimeException) {
String msg = error.getMessage();
if (msg != null && msg.startsWith(UNSUPPORTED_GRADLE_VERSION_ERROR)) {
return true;
}
}
return false;
}
}