Java tutorial
/* * Copyright (C) 2016 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.build.gradle.integration.common.fixture; import static com.google.common.truth.Truth.assertThat; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.build.gradle.AndroidGradleOptions; import com.android.build.gradle.internal.incremental.ColdswapMode; import com.android.builder.model.AndroidProject; import com.android.builder.model.OptionalCompilationStep; import com.android.builder.tasks.BooleanLatch; import com.android.ddmlib.IDevice; import com.android.resources.Density; import com.android.sdklib.AndroidVersion; import com.google.common.base.Joiner; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import org.apache.commons.io.output.TeeOutputStream; import org.gradle.tooling.BuildLauncher; import org.gradle.tooling.GradleConnectionException; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.ResultHandler; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; /** * A Gradle tooling api build builder. */ public class RunGradleTasks extends BaseGradleExecutor<RunGradleTasks> { private final boolean isUseJack; private final boolean isMinifyEnabled; private boolean mExpectingFailure = false; private Packaging mPackaging; RunGradleTasks(@NonNull GradleTestProject gradleTestProject, @NonNull ProjectConnection projectConnection) { super(projectConnection, gradleTestProject.getBuildFile(), gradleTestProject.getHeapSize()); isUseJack = gradleTestProject.isUseJack(); isMinifyEnabled = gradleTestProject.isMinifyEnabled(); } /** * Assert that the task called fails. * * The resulting exception is stored in the {@link GradleBuildResult}. */ public RunGradleTasks expectFailure() { mExpectingFailure = true; return this; } /** * Inject the instant run arguments. * * @param apiLevel The device api level. * @param coldswapMode The cold swap strategy to use. * @param flags additional instant run flags, {@see OptionalCompilationStep}. */ public RunGradleTasks withInstantRun(int apiLevel, @NonNull ColdswapMode coldswapMode, @NonNull OptionalCompilationStep... flags) { setInstantRunArgs(new AndroidVersion(apiLevel, null), null /* density */, coldswapMode, flags); return this; } /** * Inject the instant run arguments. * * @param device The connected device. * @param coldswapMode The cold swap strategy to use. * @param flags additional instant run flags, {@see OptionalCompilationStep}. */ public RunGradleTasks withInstantRun(@NonNull IDevice device, @NonNull ColdswapMode coldswapMode, @NonNull OptionalCompilationStep... flags) { setInstantRunArgs(device.getVersion(), Density.getEnum(device.getDensity()), coldswapMode, flags); return this; } /** * Sets the desired packaging implementation. */ public RunGradleTasks withPackaging(@NonNull Packaging packaging) { mPackaging = packaging; return this; } /** * Call connected check. * * Uses deviceCheck in the background to support the device pool. */ public GradleBuildResult executeConnectedCheck() { return run("deviceCheck"); } /** Execute the specified tasks */ public GradleBuildResult run(@NonNull String... tasks) { return run(ImmutableList.copyOf(tasks)); } public GradleBuildResult run(@NonNull List<String> tasksList) { assertThat(tasksList).named("tasks list").isNotEmpty(); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); syncFileSystem(); List<String> args = Lists.newArrayList(); if (enableInfoLogging) { args.add("-i"); // -i, --info Set log level to info. } args.add("-u"); // -u, --no-search-upward Don't search in parent folders for a // settings.gradle file. args.add("-Pcom.android.build.gradle.integratonTest.useJack=" + Boolean.toString(isUseJack)); args.add("-Pcom.android.build.gradle.integratonTest.minifyEnabled=" + Boolean.toString(isMinifyEnabled)); if (mPackaging != null) { args.add(String.format("-P%s=%s", AndroidGradleOptions.PROPERTY_USE_OLD_PACKAGING, mPackaging.mFlagValue)); } args.addAll(mArguments); System.out.println("[GradleTestProject] Executing tasks: gradle " + Joiner.on(' ').join(args) + " " + Joiner.on(' ').join(tasksList)); BuildLauncher launcher = mProjectConnection.newBuild().forTasks(Iterables.toArray(tasksList, String.class)) .withArguments(Iterables.toArray(args, String.class)); setJvmArguments(launcher); launcher.setStandardOutput(new TeeOutputStream(stdout, System.out)); launcher.setStandardError(new TeeOutputStream(stderr, System.err)); WaitingResultHandler handler = new WaitingResultHandler(); launcher.run(handler); GradleConnectionException failure = handler.waitForResult(); if (mExpectingFailure && failure == null) { throw new AssertionError("Expecting build to fail"); } else if (!mExpectingFailure && failure != null) { throw failure; } return new GradleBuildResult(stdout, stderr, failure); } private static class WaitingResultHandler implements ResultHandler<Void> { private final BooleanLatch latch = new BooleanLatch(); private GradleConnectionException failure; @Override public void onComplete(Void aVoid) { latch.signal(); } @Override public void onFailure(GradleConnectionException e) { failure = e; latch.signal(); } /** * Waits for the build to complete. * * @return null if the build passed, the GradleConnectionException if the build failed. */ @Nullable private GradleConnectionException waitForResult() { try { latch.await(); } catch (InterruptedException e) { throw new AssertionError(e); } return failure; } } private static void syncFileSystem() { try { if (System.getProperty("os.name").contains("Linux")) { if (Runtime.getRuntime().exec("/bin/sync").waitFor() != 0) { throw new IOException("Failed to sync file system."); } } } catch (IOException | InterruptedException e) { System.err.println(Throwables.getStackTraceAsString(e)); } } private void setInstantRunArgs(@Nullable AndroidVersion androidVersion, @Nullable Density density, @NonNull ColdswapMode coldswapMode, @NonNull OptionalCompilationStep[] flags) { if (androidVersion != null) { withProperty(AndroidProject.PROPERTY_BUILD_API, androidVersion.getFeatureLevel()); } if (density != null) { withProperty(AndroidProject.PROPERTY_BUILD_DENSITY, density.getResourceValue()); } withProperty(AndroidProject.PROPERTY_SIGNING_COLDSWAP_MODE, coldswapMode.name()); StringBuilder optionalSteps = new StringBuilder().append("-P").append("android.optional.compilation") .append('=').append("INSTANT_DEV"); for (OptionalCompilationStep step : flags) { optionalSteps.append(',').append(step); } mArguments.add(optionalSteps.toString()); } }