blob: 324177cd3bf6b934800c90ca327a3e3990b45fba [file] [log] [blame]
/*
* 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.tasks;
import static com.android.build.gradle.internal.cxx.logging.LoggingEnvironmentKt.infoln;
import static com.android.build.gradle.internal.cxx.model.CreateCxxAbiModelKt.createCxxAbiModel;
import static com.android.build.gradle.internal.cxx.model.CreateCxxVariantModelKt.createCxxVariantModel;
import static com.android.build.gradle.internal.cxx.model.CxxAbiModelKt.getJsonFile;
import static com.android.build.gradle.internal.cxx.process.ProcessOutputJunctionKt.createProcessOutputJunction;
import static com.android.build.gradle.internal.cxx.settings.CxxAbiModelCMakeSettingsRewriterKt.rewriteCxxAbiModelWithCMakeSettings;
import com.android.annotations.NonNull;
import com.android.build.gradle.internal.core.Abi;
import com.android.build.gradle.internal.cxx.json.AndroidBuildGradleJsons;
import com.android.build.gradle.internal.cxx.json.NativeBuildConfigValueMini;
import com.android.build.gradle.internal.cxx.json.NativeLibraryValueMini;
import com.android.build.gradle.internal.cxx.logging.IssueReporterLoggingEnvironment;
import com.android.build.gradle.internal.cxx.logging.ThreadLoggingEnvironment;
import com.android.build.gradle.internal.cxx.model.CxxAbiModel;
import com.android.build.gradle.internal.cxx.model.CxxModuleModel;
import com.android.build.gradle.internal.cxx.model.CxxVariantModel;
import com.android.build.gradle.internal.process.GradleProcessExecutor;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.tasks.NonIncrementalTask;
import com.android.build.gradle.internal.tasks.factory.TaskCreationAction;
import com.android.builder.errors.EvalIssueReporter;
import com.android.ide.common.process.ProcessException;
import com.android.ide.common.process.ProcessInfoBuilder;
import com.android.utils.StringHelper;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* Task that takes set of JSON files of type NativeBuildConfigValue and does clean steps with them.
*
* <p>It declares no inputs or outputs, as it's supposed to always run when invoked. Incrementality
* is left to the underlying build system.
*/
public abstract class ExternalNativeCleanTask extends NonIncrementalTask {
private EvalIssueReporter evalIssueReporter;
private CxxVariantModel variant;
private List<CxxAbiModel> abis;
@Override
protected void doTaskAction() throws ProcessException, IOException {
try (ThreadLoggingEnvironment ignore =
new IssueReporterLoggingEnvironment(evalIssueReporter)) {
infoln("starting clean");
infoln("finding existing JSONs");
List<File> existingJsons = Lists.newArrayList();
for (CxxAbiModel abi : abis) {
if (getJsonFile(abi).isFile()) {
existingJsons.add(getJsonFile(abi));
} else {
// This is infoln instead of warnln because clean considers all possible
// ABIs while cleaning
infoln(
"Json file not found so contents couldn't be cleaned %s",
getJsonFile(abi));
}
}
List<NativeBuildConfigValueMini> configValueList =
AndroidBuildGradleJsons.getNativeBuildMiniConfigs(existingJsons, null);
List<String> cleanCommands = Lists.newArrayList();
List<String> targetNames = Lists.newArrayList();
for (NativeBuildConfigValueMini config : configValueList) {
cleanCommands.addAll(config.cleanCommands);
Set<String> targets = Sets.newHashSet();
for (NativeLibraryValueMini library : config.libraries.values()) {
targets.add(String.format("%s %s", library.artifactName, library.abi));
}
targetNames.add(Joiner.on(",").join(targets));
}
infoln("about to execute %s clean commands", cleanCommands.size());
executeProcessBatch(cleanCommands, targetNames);
infoln("clean complete");
}
}
/**
* Given a list of build commands, execute each. If there is a failure, processing is stopped at
* that point.
*/
private void executeProcessBatch(
@NonNull List<String> commands, @NonNull List<String> targetNames)
throws ProcessException, IOException {
for (int commandIndex = 0; commandIndex < commands.size(); ++commandIndex) {
String command = commands.get(commandIndex);
String target = targetNames.get(commandIndex);
getLogger().lifecycle(String.format("Clean %s", target));
List<String> tokens = StringHelper.tokenizeCommandLineToEscaped(command);
ProcessInfoBuilder processBuilder = new ProcessInfoBuilder();
processBuilder.setExecutable(tokens.get(0));
for (int i = 1; i < tokens.size(); ++i) {
processBuilder.addArgs(tokens.get(i));
}
infoln("%s", processBuilder);
createProcessOutputJunction(
variant.getObjFolder(),
"android_gradle_clean_" + commandIndex,
processBuilder,
getLogger(),
new GradleProcessExecutor(getProject()),
"")
.logStderrToInfo()
.logStdoutToInfo()
.execute();
}
}
public static class CreationAction extends TaskCreationAction<ExternalNativeCleanTask> {
@NonNull private final VariantScope variantScope;
@NonNull private final CxxVariantModel variant;
@NonNull private final List<CxxAbiModel> abis = Lists.newArrayList();
public CreationAction(@NonNull CxxModuleModel module, @NonNull VariantScope scope) {
this.variantScope = scope;
this.variant = createCxxVariantModel(module, scope.getVariantData());
// Attempt to clean every possible ABI even those that aren't currently built.
// This covers cases where user has changed abiFilters or platform. We don't want
// to leave stale results hanging around.
for (Abi abi : Abi.values()) {
abis.add(
rewriteCxxAbiModelWithCMakeSettings(
createCxxAbiModel(
variant,
abi,
scope.getGlobalScope(),
scope.getVariantData())));
}
}
@NonNull
@Override
public String getName() {
return variantScope.getTaskName("externalNativeBuildClean");
}
@NonNull
@Override
public Class<ExternalNativeCleanTask> getType() {
return ExternalNativeCleanTask.class;
}
@Override
public void configure(@NonNull ExternalNativeCleanTask task) {
task.setVariantName(variantScope.getFullVariantName());
task.variant = variant;
task.abis = abis;
task.evalIssueReporter = variantScope.getGlobalScope().getErrorHandler();
}
}
}