blob: bdeab5acbf02f4815cfe92c879b952a463c04e5c [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.binary.instantrun;
import static com.android.tools.idea.gradle.util.GradleUtil.GRADLE_SYSTEM_ID;
import static com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType.EXECUTE_TASK;
import com.android.builder.model.AndroidProject;
import com.android.tools.idea.gradle.invoker.GradleInvocationResult;
import com.android.tools.idea.gradle.invoker.GradleInvoker;
import com.android.tools.idea.gradle.run.GradleTaskRunner;
import com.android.tools.idea.gradle.util.AndroidGradleSettings;
import com.android.tools.idea.gradle.util.BuildMode;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.PrintOutput;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.util.concurrency.Semaphore;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.SwingUtilities;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
class BlazeInstantRunGradleTaskRunner implements GradleTaskRunner {
private final Project project;
private final BlazeContext context;
private final File instantRunGradleBuildFile;
public BlazeInstantRunGradleTaskRunner(
Project project, BlazeContext context, File instantRunGradleBuildFile) {
this.project = project;
this.context = context;
this.instantRunGradleBuildFile = instantRunGradleBuildFile;
}
@Override
public boolean run(
@NotNull List<String> tasks,
@Nullable BuildMode buildMode,
@NotNull List<String> commandLineArguments)
throws InvocationTargetException, InterruptedException {
assert !ApplicationManager.getApplication().isDispatchThread();
final GradleInvoker gradleInvoker = GradleInvoker.getInstance(project);
final AtomicBoolean success = new AtomicBoolean();
final Semaphore done = new Semaphore();
done.down();
final GradleInvoker.AfterGradleInvocationTask afterTask =
new GradleInvoker.AfterGradleInvocationTask() {
@Override
public void execute(@NotNull GradleInvocationResult result) {
success.set(result.isBuildSuccessful());
gradleInvoker.removeAfterGradleInvocationTask(this);
done.up();
}
};
ExternalSystemTaskId taskId =
ExternalSystemTaskId.create(GRADLE_SYSTEM_ID, EXECUTE_TASK, project);
List<String> jvmArguments = ImmutableList.of();
// https://code.google.com/p/android/issues/detail?id=213040 -
// make split apks only available if an env var is set
List<String> args = new ArrayList<>(commandLineArguments);
if (!Boolean.valueOf(System.getenv(GradleTaskRunner.USE_SPLIT_APK))) {
// force multi dex when the env var is not set to true
args.add(
AndroidGradleSettings.createProjectProperty(
AndroidProject.PROPERTY_SIGNING_COLDSWAP_MODE, "MULTIDEX"));
}
// To ensure that the "Run Configuration" waits for the Gradle tasks to be executed,
// we use SwingUtilities.invokeAndWait. I tried
// using Application.invokeAndWait but it never worked.
// IDEA also uses SwingUtilities in this scenario (see CompileStepBeforeRun.)
SwingUtilities.invokeAndWait(
() -> {
gradleInvoker.addAfterGradleInvocationTask(afterTask);
gradleInvoker.executeTasks(
tasks,
jvmArguments,
args,
taskId,
new GradleNotificationListener(),
instantRunGradleBuildFile,
false,
true);
});
done.waitFor();
return success.get();
}
class GradleNotificationListener extends ExternalSystemTaskNotificationListenerAdapter {
@Override
public void onTaskOutput(
@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
super.onTaskOutput(id, text, stdOut);
String toPrint = text.trim();
if (!Strings.isNullOrEmpty(toPrint)) {
context.output(
new PrintOutput(
toPrint, stdOut ? PrintOutput.OutputType.NORMAL : PrintOutput.OutputType.ERROR));
}
}
}
}