blob: 1732072c2f80d28688c20a273cb5ca55eebc437a [file] [log] [blame]
/*
* Copyright (C) 2017 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.internal.tasks;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.ALL;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.MANIFEST;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH;
import static com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH;
import com.android.annotations.NonNull;
import com.android.build.gradle.internal.scope.TaskConfigAction;
import com.android.build.gradle.internal.scope.VariantScope;
import com.google.common.collect.Maps;
import java.io.File;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import org.gradle.api.artifacts.ArtifactCollection;
import org.gradle.api.artifacts.component.ComponentIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.gradle.api.artifacts.component.ProjectComponentIdentifier;
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.component.local.model.OpaqueComponentArtifactIdentifier;
/** Pre build task that does some checks for application variants */
@CacheableTask
public class AppPreBuildTask extends DefaultAndroidTask {
// list of Android only compile and runtime classpath.
private ArtifactCollection compileManifests;
private ArtifactCollection runtimeManifests;
private File fakeOutputDirectory;
@InputFiles
@PathSensitive(PathSensitivity.NAME_ONLY)
public FileCollection getCompileManifests() {
return compileManifests.getArtifactFiles();
}
@InputFiles
@PathSensitive(PathSensitivity.NAME_ONLY)
public FileCollection getRuntimeManifests() {
return runtimeManifests.getArtifactFiles();
}
@OutputDirectory
public File getFakeOutputDirectory() {
return fakeOutputDirectory;
}
@TaskAction
void run() {
Set<ResolvedArtifactResult> compileArtifacts = compileManifests.getArtifacts();
Set<ResolvedArtifactResult> runtimeArtifacts = runtimeManifests.getArtifacts();
// create a map where the key is either the sub-project path, or groupId:artifactId for
// external dependencies.
// For external libraries, the value is the version.
Map<String, String> runtimeIds = Maps.newHashMapWithExpectedSize(runtimeArtifacts.size());
// build a list of the runtime artifacts
for (ResolvedArtifactResult artifact : runtimeArtifacts) {
handleArtifact(artifact.getId().getComponentIdentifier(), runtimeIds::put);
}
// run through the compile ones to check for provided only.
for (ResolvedArtifactResult artifact : compileArtifacts) {
final ComponentIdentifier compileId = artifact.getId().getComponentIdentifier();
handleArtifact(
compileId,
(key, value) -> {
String runtimeVersion = runtimeIds.get(key);
if (runtimeVersion == null) {
String display = compileId.getDisplayName();
throw new RuntimeException(
"Android dependency '"
+ display
+ "' is set to compileOnly/provided which is not supported");
} else if (!runtimeVersion.isEmpty()) {
// compare versions.
if (!runtimeVersion.equals(value)) {
throw new RuntimeException(
String.format(
"Android dependency '%s' has different version for the compile (%s) and runtime (%s) classpath. You should manually set the same version via DependencyResolution",
key, value, runtimeVersion));
}
}
});
}
}
private void handleArtifact(
@NonNull ComponentIdentifier id, @NonNull BiConsumer<String, String> consumer) {
if (id instanceof ProjectComponentIdentifier) {
consumer.accept(((ProjectComponentIdentifier) id).getProjectPath().intern(), "");
} else if (id instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier moduleComponentId = (ModuleComponentIdentifier) id;
consumer.accept(
moduleComponentId.getGroup() + ":" + moduleComponentId.getModule(),
moduleComponentId.getVersion());
} else if (id instanceof OpaqueComponentArtifactIdentifier) {
// skip those for now.
// These are file-based dependencies and it's unlikely to be an AAR.
} else {
getLogger()
.warn(
"Unknown ComponentIdentifier type: "
+ id.getClass().getCanonicalName());
}
}
public static class ConfigAction implements TaskConfigAction<AppPreBuildTask> {
@NonNull private final VariantScope variantScope;
public ConfigAction(@NonNull VariantScope variantScope) {
this.variantScope = variantScope;
}
@NonNull
@Override
public String getName() {
return variantScope.getTaskName("pre", "Build");
}
@NonNull
@Override
public Class<AppPreBuildTask> getType() {
return AppPreBuildTask.class;
}
@Override
public void execute(@NonNull AppPreBuildTask task) {
task.setVariantName(variantScope.getFullVariantName());
task.compileManifests =
variantScope.getArtifactCollection(COMPILE_CLASSPATH, ALL, MANIFEST);
task.runtimeManifests =
variantScope.getArtifactCollection(RUNTIME_CLASSPATH, ALL, MANIFEST);
task.fakeOutputDirectory =
new File(
variantScope.getGlobalScope().getIntermediatesDir(),
"prebuild/" + variantScope.getVariantConfiguration().getDirName());
variantScope.getVariantData().preBuildTask = task;
}
}
}