Skip to content

Commit

Permalink
Merge pull request #70 from gradle/tt/reduce-duplication-with-oop
Browse files Browse the repository at this point in the history
Refactor to remove duplication
  • Loading branch information
tresat committed May 22, 2024
2 parents e81746c + cf720f4 commit 7cfdf83
Show file tree
Hide file tree
Showing 22 changed files with 598 additions and 595 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package org.gradle.api.experimental.android;

import com.android.build.api.dsl.*;
import org.gradle.api.*;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.experimental.android.extensions.testing.AndroidTestDependencies;
import org.gradle.api.experimental.android.extensions.testing.TestOptions;
import org.gradle.api.experimental.android.extensions.testing.Testing;
import org.gradle.api.experimental.android.nia.NiaSupport;
import org.gradle.api.provider.Property;
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension;

import java.util.Objects;

import static org.gradle.api.experimental.android.extensions.ComposeSupport.configureCompose;

public abstract class AbstractAndroidSoftwarePlugin implements Plugin<Project> {
protected static final int DEFAULT_JDK = 11;
protected static final int DEFAULT_TARGET_ANDROID_SDK = 34;
protected static final int DEFAULT_MIN_ANDROID_SDK = 21;

protected abstract AndroidSoftware getAndroidSoftware();

public void apply(Project project) {
AndroidSoftware dslModel = getAndroidSoftware();

// Setup Android software conventions
dslModel.getJdkVersion().convention(DEFAULT_JDK);
dslModel.getCompileSdk().convention(DEFAULT_TARGET_ANDROID_SDK);
dslModel.getMinSdk().convention(DEFAULT_MIN_ANDROID_SDK); // https://developer.android.com/build/multidex#mdex-gradle

// Setup minify conventions
dslModel.getBuildTypes().getDebug().getMinify().getEnabled().convention(false);
dslModel.getBuildTypes().getRelease().getMinify().getEnabled().convention(false);

// Setup desugaring conventions and desugar automatically when JDK > 8 is targeted
dslModel.getCoreLibraryDesugaring().getEnabled().convention(project.provider(() -> dslModel.getJdkVersion().get() > 8));
dslModel.getCoreLibraryDesugaring().getLibVersion().convention("2.0.4");

// Setup Serialization conventions
dslModel.getKotlinSerialization().getEnabled().convention(false);
dslModel.getKotlinSerialization().getVersion().convention("1.6.3");
dslModel.getKotlinSerialization().getJsonEnabled().convention(false);

// Setup other feature extension conventions
dslModel.getFeature().getEnabled().convention(false);
dslModel.getCompose().getEnabled().convention(false);
dslModel.getHilt().getEnabled().convention(false);

// Setup Test Options conventions
dslModel.getTesting().getTestOptions().getIncludeAndroidResources().convention(false);
dslModel.getTesting().getTestOptions().getReturnDefaultValues().convention(false);
dslModel.getTesting().getJacoco().getEnabled().convention(false);
dslModel.getTesting().getJacoco().getVersion().convention("0.8.7");
}

/**
* Performs common dependency linking actions that do not need to occur within an afterEvaluate block.
*/
@SuppressWarnings("UnstableApiUsage")
protected void linkCommonDependencies(AndroidSoftwareDependencies dependencies, ConfigurationContainer configurations) {
configurations.getByName("implementation").fromDependencyCollector(dependencies.getImplementation());
configurations.getByName("compileOnly").fromDependencyCollector(dependencies.getCompileOnly());
configurations.getByName("runtimeOnly").fromDependencyCollector(dependencies.getRuntimeOnly());
}

/**
* Performs linking actions that must occur within an afterEvaluate block.
*/
protected void linkDslModelToPlugin(Project project, AndroidSoftware dslModel, CommonExtension<?, ?, ?, ?, ?, ?> android) {
KotlinAndroidProjectExtension kotlin = project.getExtensions().getByType(KotlinAndroidProjectExtension.class);
ConfigurationContainer configurations = project.getConfigurations();

// Link common properties
ifPresent(dslModel.getNamespace(), android::setNamespace);
ifPresent(dslModel.getCompileSdk(), android::setCompileSdk);
android.defaultConfig(defaultConfig -> {
ifPresent(dslModel.getMinSdk(), defaultConfig::setMinSdk);
return null;
});
android.compileOptions(compileOptions -> {
// Up to Java 11 APIs are available through desugaring
// https://developer.android.com/studio/write/java11-minimal-support-table
compileOptions.setSourceCompatibility(JavaVersion.toVersion(dslModel.getJdkVersion().get()));
compileOptions.setTargetCompatibility(JavaVersion.toVersion(dslModel.getJdkVersion().get()));
return null;
});
ifPresent(dslModel.getJdkVersion(), jdkVersion -> {
kotlin.jvmToolchain(jdkVersion);
android.getCompileOptions().setSourceCompatibility(JavaVersion.toVersion(jdkVersion));
android.getCompileOptions().setTargetCompatibility(JavaVersion.toVersion(jdkVersion));
});

// Link build types
AndroidSoftwareBuildTypes modelBuildType = dslModel.getBuildTypes();
NamedDomainObjectContainer<? extends BuildType> androidBuildTypes = android.getBuildTypes();
linkBuildType(androidBuildTypes.getByName("debug"), modelBuildType.getDebug(), configurations);
linkBuildType(androidBuildTypes.getByName("release"), modelBuildType.getRelease(), configurations);

configureTesting(project, dslModel, android);

configureKotlinSerialization(project, dslModel);
configureDesugaring(project, dslModel, android);
configureHilt(project, dslModel, android);
configureCompose(project, dslModel, android);
}

protected void configureHilt(Project project, AndroidSoftware dslModel, CommonExtension<?, ?, ?, ?, ?, ?> android) {
if (dslModel.getHilt().getEnabled().get()) {
// Add support for KSP
project.getPlugins().apply("com.google.devtools.ksp");
project.getDependencies().add("ksp", "com.google.dagger:hilt-android-compiler:2.50");

// Add support for Hilt
project.getPlugins().apply("dagger.hilt.android.plugin");
project.getDependencies().add("implementation", "com.google.dagger:hilt-android:2.50");
}
}

protected void configureDesugaring(Project project, AndroidSoftware dslModel, CommonExtension<?, ?, ?, ?, ?, ?> android) {
if (dslModel.getCoreLibraryDesugaring().getEnabled().get()) {
android.compileOptions(compileOptions -> {
compileOptions.setCoreLibraryDesugaringEnabled(dslModel.getCoreLibraryDesugaring().getEnabled().get());
return null;
});

project.getDependencies().addProvider("coreLibraryDesugaring", dslModel.getCoreLibraryDesugaring().getLibVersion().map(version -> "com.android.tools:desugar_jdk_libs:" + version));
}
}

@SuppressWarnings("UnstableApiUsage")
protected void configureTesting(Project project, AndroidSoftware dslModel, CommonExtension<?, ?, ?, ?, ?, ?> android) {
Testing testing = dslModel.getTesting();
AndroidTestDependencies testDependencies = testing.getDependencies();
TestOptions testOptions = testing.getTestOptions();

UnitTestOptions unitTestOptions = android.getTestOptions().getUnitTests();
unitTestOptions.setIncludeAndroidResources(testOptions.getIncludeAndroidResources().get());
unitTestOptions.setReturnDefaultValues(testOptions.getReturnDefaultValues().get());

ConfigurationContainer configurations = project.getConfigurations();
configurations.getByName("testImplementation").fromDependencyCollector(testDependencies.getImplementation());
configurations.getByName("androidTestImplementation").fromDependencyCollector(testDependencies.getAndroidImplementation());
}

@SuppressWarnings("UnstableApiUsage")
protected void configureKotlinSerialization(Project project, AndroidSoftware dslModel) {
if (dslModel.getKotlinSerialization().getEnabled().get()) {
project.getPlugins().apply("org.jetbrains.kotlin.plugin.serialization");
project.getConfigurations().getByName("testImplementation").fromDependencyCollector(dslModel.getKotlinSerialization().getDependencies().getImplementation());

if (dslModel.getKotlinSerialization().getJsonEnabled().get()) {
project.getDependencies().addProvider("implementation", dslModel.getKotlinSerialization().getVersion().map(version -> "org.jetbrains.kotlinx:kotlinx-serialization-json:" + version));
}
}
}

/**
* Links build types from the model to the android extension.
*/
protected void linkBuildType(BuildType buildType, AndroidSoftwareBuildType model, ConfigurationContainer configurations) {
buildType.setMinifyEnabled(model.getMinify().getEnabled().get());
linkBuildTypeDependencies(buildType, model.getDependencies(), configurations);
}

@SuppressWarnings("UnstableApiUsage")
protected void linkBuildTypeDependencies(BuildType buildType, AndroidSoftwareDependencies dependencies, ConfigurationContainer configurations) {
String name = buildType.getName();
configurations.getByName(name + "Implementation").fromDependencyCollector(dependencies.getImplementation());
configurations.getByName(name + "CompileOnly").fromDependencyCollector(dependencies.getCompileOnly());
configurations.getByName(name + "RuntimeOnly").fromDependencyCollector(dependencies.getRuntimeOnly());
}

protected <T> void ifPresent(Property<T> property, Action<T> action) {
if (property.isPresent()) {
action.execute(property.get());
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
import org.gradle.api.experimental.android.application.StandaloneAndroidApplicationPlugin;
import org.gradle.api.experimental.android.library.StandaloneAndroidLibraryPlugin;
import org.gradle.api.initialization.Settings;
import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.internal.plugins.software.RegistersSoftwareTypes;
import org.gradle.plugin.software.internal.SoftwareTypeRegistry;

@SuppressWarnings("UnstableApiUsage")
@RegistersSoftwareTypes({StandaloneAndroidApplicationPlugin.class, StandaloneAndroidLibraryPlugin.class})
public class AndroidEcosystemPlugin implements Plugin<Settings> {

public abstract class AndroidEcosystemPlugin implements Plugin<Settings> {
@Override
public void apply(Settings target) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.gradle.api.experimental.android;

import com.android.build.api.dsl.BaseFlavor;
import com.android.build.api.dsl.CommonExtension;
import org.gradle.api.Action;
import org.gradle.api.experimental.android.extensions.Compose;
import org.gradle.api.experimental.android.extensions.CoreLibraryDesugaring;
import org.gradle.api.experimental.android.extensions.Hilt;
import org.gradle.api.experimental.android.extensions.KotlinSerialization;
import org.gradle.api.experimental.android.extensions.testing.Testing;
import org.gradle.api.experimental.android.nia.Feature;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Nested;
import org.gradle.declarative.dsl.model.annotations.Configuring;
import org.gradle.declarative.dsl.model.annotations.Restricted;

public interface AndroidSoftware {
/**
* @see CommonExtension#getCompileSdk()
*/
@Restricted
Property<Integer> getCompileSdk();

/**
* @see CommonExtension#getNamespace()
*/
@Restricted
Property<String> getNamespace();

/**
* @see BaseFlavor#getMinSdk()
*/
@Restricted
Property<Integer> getMinSdk();

/**
* JDK version to use for compilation.
*/
@Restricted
Property<Integer> getJdkVersion();

@Nested
AndroidSoftwareBuildTypes getBuildTypes();

@Nested
AndroidSoftwareDependencies getDependencies();

/**
* Controls whether or not to set up Kotlin serialization, applying the plugins
* and adding any necessary dependencies.
*/
@Nested
KotlinSerialization getKotlinSerialization();

@Configuring
default void kotlinSerialization(Action<? super KotlinSerialization> action) {
KotlinSerialization kotlinSerialization = getKotlinSerialization();
action.execute(kotlinSerialization);
kotlinSerialization.getEnabled().set(true);
}

@Nested
Compose getCompose();

@Configuring
default void compose(Action<? super Compose> action) {
Compose compose = getCompose();
action.execute(compose);
compose.getEnabled().set(true);
}

@Nested
CoreLibraryDesugaring getCoreLibraryDesugaring();

@Configuring
default void coreLibraryDesugaring(Action<? super CoreLibraryDesugaring> action) {
CoreLibraryDesugaring coreLibraryDesugaring = getCoreLibraryDesugaring();
action.execute(coreLibraryDesugaring);
coreLibraryDesugaring.getEnabled().set(true);
}

@Nested
Hilt getHilt();

@Configuring
default void hilt(Action<? super Hilt> action) {
Hilt hilt = getHilt();
action.execute(hilt);
hilt.getEnabled().set(true);
}

@Nested
Testing getTesting();

@Configuring
default void testing(Action<? super Testing> action) {
action.execute(getTesting());
}

/**
* Support for NiA convention projects defining features.
* TODO: This is a temporary solution until we have a proper feature model.
*/
@Nested
Feature getFeature();

@Configuring
default void feature(Action<? super Feature> action) {
Feature feature = getFeature();
action.execute(feature);
feature.getEnabled().set(true);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gradle.api.experimental.android;

import org.gradle.api.Action;
import org.gradle.api.experimental.android.extensions.Minify;
import org.gradle.api.tasks.Nested;
import org.gradle.declarative.dsl.model.annotations.Configuring;
import org.gradle.declarative.dsl.model.annotations.Restricted;

@Restricted
public interface AndroidSoftwareBuildType {
/**
* Dependencies for this build type.
*/
AndroidSoftwareDependencies getDependencies();

@Nested
Minify getMinify();

@Configuring
default void minify(Action<? super Minify> action) {
action.execute(getMinify());
}
}
Loading

0 comments on commit 7cfdf83

Please sign in to comment.