blob: 85bd239563c2d1373fdcbed5bc6b8797e9d1fc52 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.android.run;
import com.android.tools.idea.run.ValidationError;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.run.targetfinder.TargetFinder;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.sdkcompat.android.project.AndroidProjectInfoAdapter;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RuntimeConfigurationError;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import java.util.List;
import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.util.AndroidBundle;
/**
* Utility class for validating {@link BlazeAndroidRunConfigurationHandler}s. We collect
* configuration errors rather than throwing to avoid missing fatal errors by exiting early for a
* warning.
*/
public final class BlazeAndroidRunConfigurationValidationUtil {
private static final String SYNC_FAILED_ERR_MSG =
"Project state is invalid. Please sync and try your action again.";
/**
* Finds the top error, as determined by {@link ValidationError#compareTo(Object)}. If it is
* fatal, it is thrown as a {@link RuntimeConfigurationError}; otherwise it is thrown as a {@link
* RuntimeConfigurationWarning}. If no errors exist, nothing is thrown.
*/
public static void throwTopConfigurationError(List<ValidationError> errors)
throws RuntimeConfigurationException {
if (errors.isEmpty()) {
return;
}
// TODO: Do something with the extra error information? Error count?
ValidationError topError = Ordering.natural().max(errors);
if (topError.isFatal()) {
throw new RuntimeConfigurationError(topError.getMessage(), topError.getQuickfix());
}
throw new RuntimeConfigurationWarning(topError.getMessage(), topError.getQuickfix());
}
public static List<ValidationError> validateModule(@Nullable Module module) {
List<ValidationError> errors = Lists.newArrayList();
if (module == null) {
errors.add(
ValidationError.fatal(
"No run configuration module found. Have you successfully synced your project?"));
return errors;
}
final Project project = module.getProject();
if (AndroidProjectInfoAdapter.requiredAndroidModelMissing(project)) {
errors.add(ValidationError.fatal(SYNC_FAILED_ERR_MSG));
}
return errors;
}
public static List<ValidationError> validateFacet(@Nullable AndroidFacet facet, Module module) {
List<ValidationError> errors = Lists.newArrayList();
if (facet == null) {
errors.add(ValidationError.fatal(AndroidBundle.message("no.facet.error", module.getName())));
return errors;
}
if (facet.getConfiguration().getAndroidPlatform() == null) {
errors.add(ValidationError.fatal(AndroidBundle.message("select.platform.error")));
}
return errors;
}
public static List<ValidationError> validateLabel(
@Nullable Label label, Project project, Kind kind) {
List<ValidationError> errors = Lists.newArrayList();
if (label == null) {
errors.add(ValidationError.fatal("No target selected."));
return errors;
}
TargetIdeInfo target = TargetFinder.getInstance().targetForLabel(project, label);
if (target == null) {
errors.add(
ValidationError.fatal(
String.format("No existing %s rule selected.", Blaze.buildSystemName(project))));
} else if (!target.kindIsOneOf(kind)) {
errors.add(
ValidationError.fatal(
String.format(
"Selected %s rule is not %s", Blaze.buildSystemName(project), kind.toString())));
}
return errors;
}
public static void validateExecution(
@Nullable Module module,
@Nullable AndroidFacet facet,
@Nullable ProjectViewSet projectViewSet)
throws ExecutionException {
List<ValidationError> errors = Lists.newArrayList();
errors.addAll(validateModule(module));
if (module != null) {
errors.addAll(validateFacet(facet, module));
}
if (projectViewSet == null) {
errors.add(ValidationError.fatal("Could not load project view. Please resync project"));
}
if (errors.isEmpty()) {
return;
}
ValidationError topError = Ordering.natural().max(errors);
if (topError.isFatal()) {
throw new ExecutionException(topError.getMessage());
}
}
}