<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidMavenJarsPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class AndroidMavenJarsPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {
        project.getPluginManager().apply(AndroidSourcesJarPlugin.class);
        project.getPluginManager().apply(AndroidJavadocJarPlugin.class);
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/ci/CiDexPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.ci;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;

public class CiDexPlugin extends AndroidProjectPlugin {

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);
        if(CiUtil.isCi()) {
            extension.getDexOptions().setPreDexLibraries(false);
        }
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/VariantBasedCodeQualityExtension.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.gradle.api.BaseVariant;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Collection;

/**
 * Copy of {@link org.gradle.api.plugins.quality.CodeQualityExtension} which uses {@link BaseVariant variants}
 *
 * @author <NAME>
 * @see org.gradle.api.plugins.quality.CodeQualityExtension
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class VariantBasedCodeQualityExtension extends AndroidCodeQualityExtension {

    private Collection<BaseVariant> variants;

}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/ci/CiPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.ci;

import org.gradle.api.Plugin;
import org.gradle.api.Project;

public class CiPlugin implements Plugin<Project> {

    @Override
    public void apply(Project project) {

        project.getPluginManager().apply(CiDexPlugin.class);
        project.getPluginManager().apply(CiLintPlugin.class);

    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/ci/CiLintPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.ci;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;

public class CiLintPlugin extends AndroidProjectPlugin {

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);
        if (CiUtil.isCi()) {
            extension.getLintOptions().setHtmlReport(false);
            extension.getLintOptions().setXmlReport(false);

            extension.getLintOptions().setTextReport(true);
            extension.getLintOptions().textOutput("stdout");
        }
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/AndroidJavadocPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android;

import com.android.build.gradle.TestedExtension;
import com.android.build.gradle.api.BaseVariant;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.javadoc.Javadoc;
import org.gradle.external.javadoc.StandardJavadocDocletOptions;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import static org.codehaus.groovy.runtime.StringGroovyMethods.capitalize;

public class AndroidJavadocPlugin extends AndroidProjectPlugin {

    private Map<String, TaskProvider<Javadoc>> javadocTasks = new HashMap<>();

    private TaskProvider<Task> allJavadocTask;

    @Override
    public void apply(Project project) {
        super.apply(project);

        allJavadocTask = project.getTasks().register("javadoc", ajdTasks -> {
            ajdTasks.setDescription("Generate Javadoc for all variants");
            ajdTasks.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP);
        });

    }

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);
        getAndroidVariants().all(variant -> {
            TaskProvider<Javadoc> javadocTask = getJavadocTask(getProject(), variant);

            allJavadocTask.configure(t -> t.dependsOn(javadocTask));
        });
    }

    public TaskProvider<Javadoc> getJavadocTask(Project project, BaseVariant variant) {

        if (!javadocTasks.containsKey(variant.getName())) {

            TaskProvider<Javadoc> task = project.getTasks().register("javadoc" + capitalize((CharSequence) variant.getName()), Javadoc.class, javadoc -> {
                javadoc.setDescription("Generate Javadoc for the " + variant.getName() + " variant");
                javadoc.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP);

                javadoc.dependsOn(variant.getJavaCompileProvider());

                JavaCompile javacTask = variant.getJavaCompileProvider().get();

                javadoc.setSource(javacTask.getSource());

                javadoc.setClasspath(project.files(javacTask.getDestinationDirectory()).plus(javacTask.getClasspath()));
                javadoc.getOptions().setSource(javacTask.getSourceCompatibility());

                //javadoc.exclude '**/BuildConfig.java'
                javadoc.exclude("**/R.java");

                javadoc.getOptions().encoding("UTF-8");
                javadoc.getOptions().setBootClasspath(getAndroidExtension().getBootClasspath());

                if (javadoc.getOptions() instanceof StandardJavadocDocletOptions) {
                    StandardJavadocDocletOptions realOptions = (StandardJavadocDocletOptions) javadoc.getOptions();

                    realOptions.docEncoding("UTF-8");
                    realOptions.charSet("UTF-8");

                    String majorVersion = JavaVersion.current().getMajorVersion();
                    if (Integer.parseInt(majorVersion) < 11) {
                        realOptions.links("https://docs.oracle.com/javase/" + majorVersion + "/docs/api/");
                    } else {
                        realOptions.links("https://docs.oracle.com/en/java/javase/" + majorVersion + "/docs/api/");
                    }
                    realOptions.links("https://developer.android.com/reference/");
                }

                javadoc.setFailOnError(false);

                File docsDir;
                if (project.hasProperty("docsDir")) {
                    docsDir = (File) project.property("docsDir");
                } else {
                    docsDir = new File(project.getBuildDir(), "docs");
                }
                File javadocDir = new File(docsDir, "javadoc");
                javadoc.setDestinationDir(new File(javadocDir, variant.getDirName()));
            });

            javadocTasks.put(variant.getName(), task);
        }

        return javadocTasks.get(variant.getName());
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/AndroidPmdPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.api.dsl.AndroidSourceSet;
import org.gradle.api.Incubating;
import org.gradle.api.JavaVersion;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.plugins.quality.Pmd;
import org.gradle.api.plugins.quality.PmdPlugin;
import org.gradle.api.plugins.quality.TargetJdk;
import org.gradle.api.resources.TextResource;
import org.gradle.util.VersionNumber;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * Copy of {@link org.gradle.api.plugins.quality.PmdPlugin} which
 * <ul>
 * <li>extends {@link AbstractAndroidCodeQualityPlugin} instead of {@link org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin}</li>
 * <li>uses {@link AndroidSourceSet AndroidSourceSets} instead of {@link org.gradle.api.tasks.SourceSet JavaSourceSets}</li>
 * </ul>
 *
 * @see org.gradle.api.plugins.quality.PmdPlugin
 * @see AbstractAndroidCodeQualityPlugin
 */
@Incubating
public class AndroidPmdPlugin extends SourceSetBasedCodeQualityPlugin<Pmd> {

    private AndroidPmdExtension extension;

    @Override
    protected String getToolName() {
        return "PMD";
    }

    @Override
    protected Class<Pmd> getTaskType() {
        return Pmd.class;
    }

    @Override
    protected SourceSetBasedCodeQualityExtension createExtension() {
        extension = project.getExtensions().create("pmd", AndroidPmdExtension.class, project);
        extension.setToolVersion(PmdPlugin.DEFAULT_PMD_VERSION);
        extension.setRuleSets(new ArrayList<String>(Arrays.asList("category/java/errorprone.xml")));
        extension.setRuleSetFiles(project.getLayout().files());
        conventionMappingOf(extension).map("targetJdk", () ->
                getDefaultTargetJdk(getJavaPluginExtension().getSourceCompatibility()));
        return extension;
    }

    public TargetJdk getDefaultTargetJdk(JavaVersion javaVersion) {
        try {
            return TargetJdk.toVersion(javaVersion.toString());
        } catch (IllegalArgumentException ignored) {
            // TargetJDK does not include 1.1, 1.2 and 1.8;
            // Use same fallback as PMD
            return TargetJdk.VERSION_1_4;
        }
    }

    @Override
    protected void configureConfiguration(Configuration configuration) {
        configureDefaultDependencies(configuration);
    }

    @Override
    protected void configureTaskDefaults(Pmd task, String baseName) {
        Configuration configuration = project.getConfigurations().getAt(getConfigurationName());
        configureTaskConventionMapping(configuration, task);
        configureReportsConventionMapping(task, baseName);
    }

    private void configureDefaultDependencies(Configuration configuration) {
        configuration.defaultDependencies(dependencies -> {
            VersionNumber version = VersionNumber.parse(extension.getToolVersion());
            String dependency = calculateDefaultDependencyNotation(version);
            dependencies.add(project.getDependencies().create(dependency));
        });
    }

    private void configureTaskConventionMapping(Configuration configuration, Pmd task) {
        ConventionMapping taskMapping = task.getConventionMapping();
        taskMapping.map("pmdClasspath", () -> configuration);
        taskMapping.map("ruleSets", (Callable<List<String>>) () -> extension.getRuleSets());
        taskMapping.map("ruleSetConfig", (Callable<TextResource>) () -> extension.getRuleSetConfig());
        taskMapping.map("ruleSetFiles", (Callable<FileCollection>) () -> extension.getRuleSetFiles());
        taskMapping.map("ignoreFailures", (Callable<Boolean>) () -> extension.isIgnoreFailures());
        taskMapping.map("rulePriority", (Callable<Integer>) () -> extension.getRulePriority());
        taskMapping.map("consoleOutput", (Callable<Boolean>) () -> extension.isConsoleOutput());
        taskMapping.map("targetJdk", (Callable<TargetJdk>) () -> extension.getTargetJdk());

        task.getMaxFailures().convention(extension.getMaxFailures());
        task.getIncrementalAnalysis().convention(extension.getIncrementalAnalysis());
    }

    private void configureReportsConventionMapping(Pmd task, final String baseName) {
        task.getReports().all(report -> {
            report.getRequired().convention(true);
            report.getOutputLocation().convention(project.getLayout().getProjectDirectory().file(project.provider(() -> new File(extension.getReportsDir(), baseName + "." + report.getName()).getAbsolutePath())));
        });
    }

    private String calculateDefaultDependencyNotation(VersionNumber toolVersion) {
        if (toolVersion.compareTo(VersionNumber.version(5)) < 0) {
            return "pmd:pmd:" + extension.getToolVersion();
        } else if (toolVersion.compareTo(VersionNumber.parse("5.2.0")) < 0) {
            return "net.sourceforge.pmd:pmd:" + extension.getToolVersion();
        }
        return "net.sourceforge.pmd:pmd-java:" + extension.getToolVersion();
    }

    @Override
    protected void configureForSourceSet(final AndroidSourceSet sourceSet, final Pmd task) {
        task.setDescription("Run PMD analysis for " + sourceSet.getName() + " classes");
        task.setSource(getAllJava(sourceSet));
        ConventionMapping taskMapping = task.getConventionMapping();
        taskMapping.map("classpath", () -> getOutput(sourceSet).plus(getCompileClasspath(sourceSet)));
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/AndroidProjectPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android;

import com.android.build.gradle.*;
import com.android.build.gradle.api.BaseVariant;
import com.android.build.gradle.api.TestVariant;
import com.android.build.gradle.api.UnitTestVariant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.internal.jvm.ClassDirectoryBinaryNamingScheme;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.compile.AbstractCompile;
import org.gradle.api.tasks.compile.JavaCompile;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static lombok.AccessLevel.PRIVATE;

/**
 * Abstract base class for all android related {@link Plugin plugins}.
 * Provides type-safe access to the {@link BaseExtension android}-extension
 * and the {@link BaseVariant variant} collection.
 */
@Getter
public abstract class AndroidProjectPlugin implements Plugin<Project> {

    @Nullable
    private TestedExtension androidExtension;

    @Nullable
    private ProjectType projectType;

    private Project project;

    @Getter(PRIVATE)
    private boolean withAndroidCalled = false;

    @Getter(PRIVATE)
    private boolean applyCalled = false;

    @Override
    public void apply(@Nonnull Project project) {
        this.project = project;
        applyCalled = true;

        project.getPlugins().withType(AppPlugin.class, appPlugin -> {
            androidExtension = project.getExtensions().getByType(AppExtension.class);
            projectType = ProjectType.APP;

            withAndroid(androidExtension);
            if (!isWithAndroidCalled()) {
                throw new RuntimeException("call super() in withAndroid()");
            }
        });

        project.getPlugins().withType(LibraryPlugin.class, libraryPlugin -> {
            androidExtension = project.getExtensions().getByType(LibraryExtension.class);
            projectType = ProjectType.LIBRARY;

            withAndroid(androidExtension);
            if (!isWithAndroidCalled()) {
                throw new RuntimeException("call super() in withAndroid()");
            }
        });

        project.afterEvaluate(project1 -> {
            if (androidExtension == null || projectType == null)
                project1.getLogger().warn("No android plugin found on project {}", project);
        });
    }

    protected void withAndroid(TestedExtension extension) {
        withAndroidCalled = true;
    }

    @SuppressWarnings("WeakerAccess")
    public TestedExtension getAndroidExtension() {
        if (androidExtension == null || projectType == null) {
            if (isApplyCalled()) {
                throw new IllegalStateException("No android plugin found");
            }
            else {
                throw new IllegalArgumentException("super.apply() not called");
            }
        }

        return androidExtension;
    }

    @SuppressWarnings("WeakerAccess")
    public DomainObjectSet<? extends BaseVariant> getAndroidVariants() {
        if (androidExtension == null || projectType == null) {
            throw new IllegalStateException("No android plugin found");
        }

        switch (projectType) {
            case APP:
                return ((AppExtension) androidExtension).getApplicationVariants();
            case LIBRARY:
                return ((LibraryExtension) androidExtension).getLibraryVariants();
            default:
                throw new IllegalStateException("Unexpected project type: " + projectType);
        }
    }

    @Nonnull
    public DomainObjectSet<TestVariant> getTestVariants() {
        if (androidExtension == null || projectType == null) {
            throw new IllegalStateException("No android plugin found");
        }

        return androidExtension.getTestVariants();
    }

    @Nonnull
    public DomainObjectSet<UnitTestVariant> getUnitTestVariants() {
        if (androidExtension == null || projectType == null) {
            throw new IllegalStateException("No android plugin found");
        }

        return androidExtension.getUnitTestVariants();
    }

    protected boolean publishVariant(BaseVariant variant) {
        if (variant instanceof TestVariant || variant instanceof UnitTestVariant) {
            return false;
        }

        return getAndroidExtension().getDefaultPublishConfig().equals(variant.getName());
    }

    /**
     * Returns the name of a task for this source set.
     *
     * @param verb   The action, may be null.
     * @param target The target, may be null
     * @return The task name, generally of the form ${verb}${name}${noun}
     * @see SourceSet#getTaskName(String, String)
     */
    protected static String getTaskName(BaseVariant variant, String verb, String target) {
        return new ClassDirectoryBinaryNamingScheme(variant.getName()).getTaskName(verb, target);
    }

    /**
     * Returns the classpath used to compile this source.
     *
     * @return The classpath. Never returns null.
     * @see SourceSet#getCompileClasspath()
     */
    protected Provider<FileCollection> getCompileClasspath(BaseVariant variant) {
        return variant.getJavaCompileProvider().map(JavaCompile::getClasspath);
    }

    /**
     * All Java source files for this source set. This includes, for example, source which is directly compiled, and
     * source which is indirectly compiled through joint compilation.
     *
     * @return the Java source. Never returns null.
     * @see SourceSet#getAllJava()
     */
    protected static Provider<FileTree> getAllJava(BaseVariant androidSourceSet) {
        return androidSourceSet.getJavaCompileProvider().map(JavaCompile::getSource);
    }

    /**
     * @see SourceSet#getOutput()
     */
    protected Provider<FileTree> getOutput(BaseVariant androidSourceSet) {
        return androidSourceSet.getJavaCompileProvider()
                .map(AbstractCompile::getDestinationDirectory)
                .map(dir -> getProject().fileTree(dir));
    }

    @Getter
    @AllArgsConstructor
    public enum ProjectType {
        APP(AppPlugin.class, AppExtension.class),
        LIBRARY(LibraryPlugin.class, LibraryExtension.class);

        private Class<? extends Plugin<Project>> pluginClass;
        private Class<? extends TestedExtension> extensionClass;
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidSourcesJarPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;
import lombok.Getter;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.compile.JavaCompile;

import java.util.HashMap;
import java.util.Map;

import static org.codehaus.groovy.runtime.StringGroovyMethods.capitalize;

public class AndroidSourcesJarPlugin extends AndroidProjectPlugin {

    private TaskProvider<Task> allSourcesJarTask;

    @Getter
    private Map<String, TaskProvider<Jar>> variantSourcesJarTasks = new HashMap<>();

    @Override
    public void apply(Project project) {
        super.apply(project);

        allSourcesJarTask = project.getTasks().register("sourcesJar", asjTask -> {
            asjTask.setDescription("Generate the sources jar for all variants");
            asjTask.setGroup("jar");
        });
    }

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);

        getAndroidVariants().all(variant -> {
            TaskProvider<Jar> sourcesJarTask = getProject().getTasks().register("sources" + capitalize((CharSequence) variant.getName()) + "Jar", Jar.class, jar -> {
                jar.setDescription("Generate the sources jar for the " + variant.getName() + " variant");
                jar.setGroup("jar");

                jar.getArchiveClassifier().set("sources");
                jar.getArchiveAppendix().set(variant.getName());
                jar.from(variant.getJavaCompileProvider().map(JavaCompile::getSource));
            });

            variantSourcesJarTasks.put(variant.getName(), sourcesJarTask);

            allSourcesJarTask.configure(t -> t.dependsOn(sourcesJarTask));

            if (publishVariant(variant)) {
                getProject().getArtifacts().add(Dependency.ARCHIVES_CONFIGURATION, sourcesJarTask);
            }
        });
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/SourceSetBasedCodeQualityExtension.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.api.dsl.AndroidSourceSet;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Collection;

/**
 * Copy of {@link org.gradle.api.plugins.quality.CodeQualityExtension} which uses {@link AndroidSourceSet AndroidSourceSets}
 *
 * @author <NAME>
 * @see org.gradle.api.plugins.quality.CodeQualityExtension
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class SourceSetBasedCodeQualityExtension extends AndroidCodeQualityExtension {

    private Collection<AndroidSourceSet> sourceSets;

}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidMavenPublishAllVariantsPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;
import org.gradle.api.Project;
import org.gradle.api.publish.maven.MavenPublication;

public class AndroidMavenPublishAllVariantsPlugin extends AndroidProjectPlugin {
    private AndroidMavenPublishBasePlugin mavenPublishBasePlugin;

    @Override
    public void apply(Project project) {
        mavenPublishBasePlugin = project.getPlugins().apply(AndroidMavenPublishBasePlugin.class);
        super.apply(project);
    }

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);

        getAndroidVariants().all(variant -> {
            MavenPublication mavenPublication = mavenPublishBasePlugin.createMavenPublication(variant);

            mavenPublication.setArtifactId(mavenPublication.getArtifactId() + "-" + variant.getName());
        });
    }
}


<|start_filename|>examples/lombok/src/main/java/io/freefair/example/Dummy.java<|end_filename|>
package io.freefair.example;

import lombok.Data;

@Data
public class Dummy {

    private int foo;
    private String bar;
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidJavadocJarPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidJavadocPlugin;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;
import lombok.Getter;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.javadoc.Javadoc;
import org.gradle.api.tasks.bundling.Jar;

import java.util.HashMap;
import java.util.Map;

import static org.codehaus.groovy.runtime.StringGroovyMethods.capitalize;

public class AndroidJavadocJarPlugin extends AndroidProjectPlugin {

    private TaskProvider<Task> allJavadocJarTask;

    @Getter
    private Map<String, TaskProvider<Jar>> variantJavadocJarTasks = new HashMap<>();

    @Override
    public void apply(Project project) {
        super.apply(project);

        project.getPluginManager().apply(AndroidJavadocPlugin.class);

        allJavadocJarTask = project.getTasks().register("javadocJar", ajdjTask -> {
            ajdjTask.setDescription("Generate the javadoc jar for all variants");
            ajdjTask.setGroup("jar");
        });

    }

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);

        getAndroidVariants().all(variant -> {

            AndroidJavadocPlugin androidJavadocPlugin = getProject().getPlugins().findPlugin(AndroidJavadocPlugin.class);
            TaskProvider<Javadoc> javadocTask = androidJavadocPlugin.getJavadocTask(getProject(), variant);

            TaskProvider<Jar> javadocJarTask = getProject().getTasks().register("javadoc" + capitalize((CharSequence) variant.getName()) + "Jar", Jar.class, jar -> {
                jar.dependsOn(javadocTask);

                jar.setDescription("Generate the javadoc jar for the " + variant.getName() + " variant");
                jar.setGroup("jar");

                jar.getArchiveAppendix().set(variant.getName());
                jar.getArchiveClassifier().set("javadoc");
                jar.from(javadocTask.get().getDestinationDir());
            });

            variantJavadocJarTasks.put(variant.getName(), javadocJarTask);

            allJavadocJarTask.configure(t -> t.dependsOn(javadocJarTask));

            if (publishVariant(variant)) {
                getProject().getArtifacts().add(Dependency.ARCHIVES_CONFIGURATION, javadocJarTask);
            }
        });
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/VariantBasedCodeQualityPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.gradle.TestedExtension;
import com.android.build.gradle.api.BaseVariant;
import org.gradle.api.DomainObjectSet;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaBasePlugin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
 * @author <NAME>
 * @see org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin
 */
public abstract class VariantBasedCodeQualityPlugin<T extends Task> extends AbstractAndroidCodeQualityPlugin<T, VariantBasedCodeQualityExtension> {

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);
        configureVariantRule();
        configureCheckTask();
    }

    @Override
    protected String getExtensionElementsName() {
        return "variants";
    }

    @Override
    protected Callable<Collection<?>> getExtensionElementsCallable() {
        return () -> {
            ArrayList<BaseVariant> objects = new ArrayList<>();
            objects.addAll(getAndroidVariants());
            objects.addAll(getTestVariants());
            objects.addAll(getUnitTestVariants());
            return objects;
        };
    }

    private void configureVariantRule() {
        configureForVariants(getAndroidVariants());
        configureForVariants(getTestVariants());
        configureForVariants(getUnitTestVariants());
    }

    private void configureForVariants(DomainObjectSet<? extends BaseVariant> variants) {
        variants.all(sourceSet -> {
            T task = project.getTasks().create(getTaskName(sourceSet, getTaskBaseName(), null), getCastedTaskType());
            task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
            configureForVariant(sourceSet, task);
        });
    }

    private void configureCheckTask() {
        withBasePlugin(plugin -> configureCheckTaskDependents());
    }

    private void configureCheckTaskDependents() {
        final String taskBaseName = getTaskBaseName();
        project.getTasks().getByName("check").dependsOn((Callable<Iterable<String>>) () -> {
            return extension.getVariants().stream()
                    .map(variant -> getTaskName(variant, taskBaseName, null))
                    .collect(Collectors.toList());
        });
    }

    protected abstract void configureForVariant(BaseVariant sourceSet, T task);
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/AndroidCheckstylePlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.api.dsl.AndroidSourceSet;
import org.gradle.api.Action;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.plugins.quality.Checkstyle;
import org.gradle.api.reporting.SingleFileReport;
import org.gradle.api.resources.TextResource;

import java.io.File;
import java.util.Map;
import java.util.concurrent.Callable;

import static org.gradle.api.plugins.quality.CheckstylePlugin.DEFAULT_CHECKSTYLE_VERSION;

/**
 * Copy of {@link org.gradle.api.plugins.quality.CheckstylePlugin} which
 * <ul>
 * <li>extends {@link AbstractAndroidCodeQualityPlugin} instead of {@link org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin}</li>
 * <li>uses {@link AndroidSourceSet AndroidSourceSets} instead of {@link org.gradle.api.tasks.SourceSet JavaSourceSets}</li>
 * </ul>
 *
 * @see org.gradle.api.plugins.quality.CheckstylePlugin
 * @see AbstractAndroidCodeQualityPlugin
 */
public class AndroidCheckstylePlugin extends SourceSetBasedCodeQualityPlugin<Checkstyle> {

    private static final String CONFIG_DIR_NAME = "config/checkstyle";
    private AndroidCheckstyleExtension extension;

    @Override
    protected String getToolName() {
        return "Checkstyle";
    }

    @Override
    protected Class<Checkstyle> getTaskType() {
        return Checkstyle.class;
    }

    @Override
    protected SourceSetBasedCodeQualityExtension createExtension() {
        extension = project.getExtensions().create("checkstyle", AndroidCheckstyleExtension.class, project);
        extension.setToolVersion(DEFAULT_CHECKSTYLE_VERSION);
        extension.getConfigDirectory().convention(project.getRootProject().getLayout().getProjectDirectory().dir(CONFIG_DIR_NAME));
        extension.setConfig(project.getResources().getText().fromFile(extension.getConfigDirectory().file("checkstyle.xml")));
        return extension;
    }

    @Override
    protected void configureConfiguration(Configuration configuration) {
        configureDefaultDependencies(configuration);
    }

    @Override
    protected void configureTaskDefaults(Checkstyle task, final String baseName) {
        Configuration configuration = project.getConfigurations().getAt(getConfigurationName());
        configureTaskConventionMapping(configuration, task);
        configureReportsConventionMapping(task, baseName);
    }

    private void configureDefaultDependencies(Configuration configuration) {
        configuration.defaultDependencies(new Action<DependencySet>() {
            @Override
            public void execute(DependencySet dependencies) {
                dependencies.add(project.getDependencies().create("com.puppycrawl.tools:checkstyle:" + extension.getToolVersion()));
            }
        });
    }

    private void configureTaskConventionMapping(Configuration configuration, Checkstyle task) {
        ConventionMapping taskMapping = task.getConventionMapping();
        taskMapping.map("checkstyleClasspath", () -> configuration);
        taskMapping.map("config", (Callable<TextResource>) () -> extension.getConfig());
        taskMapping.map("configProperties", (Callable<Map<String, Object>>) () -> extension.getConfigProperties());
        taskMapping.map("ignoreFailures", (Callable<Boolean>) () -> extension.isIgnoreFailures());
        taskMapping.map("showViolations", (Callable<Boolean>) () -> extension.isShowViolations());
        taskMapping.map("maxErrors", (Callable<Integer>) () -> extension.getMaxErrors());
        taskMapping.map("maxWarnings", (Callable<Integer>) () -> extension.getMaxWarnings());

        task.getConfigDirectory().convention(extension.getConfigDirectory());
    }

    private void configureReportsConventionMapping(Checkstyle task, final String baseName) {
        task.getReports().all(new Action<SingleFileReport>() {
            @Override
            public void execute(final SingleFileReport report) {
                report.getRequired().convention(true);
                report.getOutputLocation().convention(project.getLayout().getProjectDirectory().file(project.provider(() -> new File(extension.getReportsDir(), baseName + "." + report.getName()).getAbsolutePath())));
            }
        });
    }

    @Override
    protected void configureForSourceSet(final AndroidSourceSet sourceSet, Checkstyle task) {
        task.setDescription("Run Checkstyle analysis for " + sourceSet.getName() + " classes");
        task.setClasspath(getOutput(sourceSet).plus(getCompileClasspath(sourceSet)));
        task.setSource(getAllJava(sourceSet));
    }
}



<|start_filename|>src/test/java/io/freefair/gradle/plugins/android/AbstractGradlePluginTest.java<|end_filename|>
package io.freefair.gradle.plugins.android;

import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

public class AbstractGradlePluginTest {

    @Rule
    public final TemporaryFolder testProjectDir = new TemporaryFolder();
    protected File buildFile;
    private File srcMain;

    @Before
    public void setup() throws IOException {
        buildFile = testProjectDir.newFile("build.gradle");
        srcMain = testProjectDir.newFolder("src", "main");

    }

    protected void setPackageName(String packageName) throws FileNotFoundException, UnsupportedEncodingException {
        File androidManifestXml = new File(srcMain, "AndroidManifest.xml");

        try (PrintWriter writer = new PrintWriter(androidManifestXml, "UTF-8")) {
            writer.printf("<manifest package=\"%s\"></manifest>", packageName);
            writer.println();
        }
    }

    protected void loadBuildFileFromClasspath(String name) throws IOException {
        InputStream resourceAsStream = AbstractGradlePluginTest.class.getResourceAsStream(name);
        Files.copy(resourceAsStream, buildFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/aspectj/internal/AndroidWeavingSourceSet.java<|end_filename|>
package io.freefair.gradle.plugins.android.aspectj.internal;

import com.android.build.api.dsl.AndroidSourceSet;
import io.freefair.gradle.plugins.aspectj.WeavingSourceSet;
import lombok.Data;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.jvm.ClassDirectoryBinaryNamingScheme;
import org.gradle.api.reflect.HasPublicType;
import org.gradle.api.reflect.TypeOf;

/**
 * {@link WeavingSourceSet} implementation based on {@link AndroidSourceSet}.
 *
 * @author <NAME>
 */
@Data
public class AndroidWeavingSourceSet implements WeavingSourceSet, HasPublicType {

    private final String aspectConfigurationName;
    private FileCollection aspectPath;

    private final String inpathConfigurationName;
    private FileCollection inPath;

    public AndroidWeavingSourceSet(AndroidSourceSet androidSourceSet) {
        ClassDirectoryBinaryNamingScheme namingScheme = new ClassDirectoryBinaryNamingScheme(androidSourceSet.getName());

        aspectConfigurationName = namingScheme.getTaskName("", "aspect");
        inpathConfigurationName = namingScheme.getTaskName("", "inpath");
    }

    @Override
    public TypeOf<?> getPublicType() {
        return TypeOf.typeOf(WeavingSourceSet.class);
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidMavenPublishPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import com.android.build.gradle.TestedExtension;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;
import org.gradle.api.Project;

public class AndroidMavenPublishPlugin extends AndroidProjectPlugin {

    private AndroidMavenPublishBasePlugin mavenPublishBasePlugin;

    @Override
    public void apply(Project project) {
        mavenPublishBasePlugin = project.getPlugins().apply(AndroidMavenPublishBasePlugin.class);
        super.apply(project);
    }

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);

        getAndroidVariants().all(variant -> {
            if (publishVariant(variant)) {
                mavenPublishBasePlugin.createMavenPublication(variant);
            }
        });
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/maven/AndroidMavenPublishBasePlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.maven;

import com.android.build.gradle.api.ApplicationVariant;
import com.android.build.gradle.api.BaseVariant;
import com.android.build.gradle.api.FeatureVariant;
import com.android.build.gradle.api.LibraryVariant;
import io.freefair.gradle.plugins.android.AndroidProjectPlugin;
import org.gradle.api.Project;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.Jar;

import javax.annotation.Nonnull;

public class AndroidMavenPublishBasePlugin extends AndroidProjectPlugin {

    @Override
    public void apply(@Nonnull Project project) {
        project.getPlugins().apply(MavenPublishPlugin.class);
        super.apply(project);
    }

    public MavenPublication createMavenPublication(BaseVariant variant) {

        PublishingExtension publishing = getProject().getExtensions().getByType(PublishingExtension.class);

        MavenPublication mavenPublication;

        if (variant instanceof LibraryVariant) {
            mavenPublication = publishing.getPublications().create(variant.getName() + "AndroidLibrary", MavenPublication.class, publication -> {
                publication.getPom().setPackaging("aar");
            });
        }
        else if (variant instanceof ApplicationVariant) {
            mavenPublication = publishing.getPublications().create(variant.getName() + "AndroidApplication", MavenPublication.class, publication -> {
                publication.getPom().setPackaging("apk");
            });
        }
        else if (variant instanceof FeatureVariant) {
            mavenPublication = publishing.getPublications().create(variant.getName() + "AndroidFeature", MavenPublication.class, publication -> {
                publication.getPom().setPackaging("apk");
            });
        }
        else {
            throw new IllegalStateException(variant.getClass().getName());
        }

        getProject().afterEvaluate(p -> {
            mavenPublication.from(p.getComponents().getByName(variant.getName()));
        });

        getProject().getPlugins().withType(AndroidJavadocJarPlugin.class, androidJavadocJarPlugin -> {
            TaskProvider<Jar> javadocJarTask = androidJavadocJarPlugin.getVariantJavadocJarTasks().get(variant.getName());
            mavenPublication.artifact(javadocJarTask.get(), mavenArtifact -> mavenArtifact.setClassifier("javadoc"));
        });

        getProject().getPlugins().withType(AndroidSourcesJarPlugin.class, androidJavadocJarPlugin -> {
            TaskProvider<Jar> sourcesJarTask = androidJavadocJarPlugin.getVariantSourcesJarTasks().get(variant.getName());
            mavenPublication.artifact(sourcesJarTask.get(), mavenArtifact -> mavenArtifact.setClassifier("sources"));
        });

        return mavenPublication;
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/SourceSetBasedCodeQualityPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.api.dsl.AndroidSourceSet;
import com.android.build.gradle.TestedExtension;
import com.android.build.gradle.api.AndroidSourceDirectorySet;
import com.android.build.gradle.api.BaseVariant;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Task;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.internal.file.FileTreeInternal;
import org.gradle.api.internal.file.UnionFileTree;
import org.gradle.api.internal.jvm.ClassDirectoryBinaryNamingScheme;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.SourceSet;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author <NAME>
 * @see org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin
 */
public abstract class SourceSetBasedCodeQualityPlugin<T extends Task> extends AbstractAndroidCodeQualityPlugin<T, SourceSetBasedCodeQualityExtension> {

    @Override
    protected void withAndroid(TestedExtension extension) {
        super.withAndroid(extension);
        configureSourceSetRule();
        configureCheckTask();
    }

    @Override
    protected String getExtensionElementsName() {
        return "sourceSets";
    }

    @Override
    protected Callable<Collection<?>> getExtensionElementsCallable() {
        return () -> getAndroidExtension().getSourceSets();
    }

    private void configureSourceSetRule() {
        configureForSourceSets(getAndroidExtension().getSourceSets());
    }

    private void configureForSourceSets(NamedDomainObjectContainer<? extends AndroidSourceSet> sourceSets) {
        sourceSets.all(sourceSet -> {
            T task = project.getTasks().create(getTaskName(sourceSet, getTaskBaseName(), null), getCastedTaskType());
            task.setGroup(JavaBasePlugin.VERIFICATION_GROUP);
            configureForSourceSet(sourceSet, task);
        });
    }

    private void configureCheckTask() {
        withBasePlugin(plugin -> configureCheckTaskDependents());
    }

    private void configureCheckTaskDependents() {
        final String taskBaseName = getTaskBaseName();
        project.getTasks().getByName("check").dependsOn((Callable) () -> {
            return extension.getSourceSets()
                    .stream()
                    .map(sourceSet -> getTaskName(sourceSet, taskBaseName, null))
                    .collect(Collectors.toList());
        });
    }

    protected abstract void configureForSourceSet(AndroidSourceSet sourceSet, T task);

    /**
     * Returns the name of a task for this source set.
     *
     * @param verb The action, may be null.
     * @param target The target, may be null
     * @return The task name, generally of the form ${verb}${name}${noun}
     * @see SourceSet#getTaskName(String, String)
     */
    protected static String getTaskName(AndroidSourceSet sourceSet, String verb, String target) {
        return new ClassDirectoryBinaryNamingScheme(sourceSet.getName()).getTaskName(verb, target);
    }

    /**
     * Returns the classpath used to compile this source.
     *
     * @return The classpath. Never returns null.
     * @see SourceSet#getCompileClasspath()
     */
    protected FileCollection getCompileClasspath(AndroidSourceSet androidSourceSet) {
        ConfigurableFileCollection compileClasspath = project.files();

        getAllVariants(androidSourceSet)
                .map(variant -> variant.getJavaCompileProvider().get().getClasspath())
                .forEach(compileClasspath::from);

        return compileClasspath;
    }

    /**
     * All Java source files for this source set. This includes, for example, source which is directly compiled, and
     * source which is indirectly compiled through joint compilation.
     *
     * @return the Java source. Never returns null.
     * @see SourceSet#getAllJava()
     */
    protected static FileTree getAllJava(AndroidSourceSet androidSourceSet) {
        return ((AndroidSourceDirectorySet)androidSourceSet.getJava()).getSourceFiles();
    }

    /**
     * @see SourceSet#getOutput()
     */
    protected FileCollection getOutput(AndroidSourceSet androidSourceSet) {
        List<FileTreeInternal> sourceTrees = getAllVariants(androidSourceSet)
                .map(baseVariant -> baseVariant.getJavaCompileProvider().get().getDestinationDirectory())
                .map(destinationDir -> (FileTreeInternal) getProject().fileTree(destinationDir))
                .collect(Collectors.toList());
        return new UnionFileTree(androidSourceSet.getName() + " output", sourceTrees);
    }

    protected Stream<BaseVariant> getAllVariants(AndroidSourceSet androidSourceSet) {
        Stream<BaseVariant> testVariants = Stream.concat(getTestVariants().stream(), getUnitTestVariants().stream());
        Stream<BaseVariant> variants = Stream.concat(getAndroidVariants().stream(), testVariants);

        //noinspection SuspiciousMethodCalls
        return variants.filter(variant -> variant.getSourceSets().contains(androidSourceSet));
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/AndroidCodeQualityExtension.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import lombok.Data;

import java.io.File;

/**
 * Copy of {@link org.gradle.api.plugins.quality.CodeQualityExtension} without source sets.
 *
 * @author <NAME>
 * @see org.gradle.api.plugins.quality.CodeQualityExtension
 */
@Data
public class AndroidCodeQualityExtension {

    private String toolVersion;
    private boolean ignoreFailures;
    private File reportsDir;

    /**
     * The version of the code quality tool to be used.
     */
    public String getToolVersion() {
        return toolVersion;
    }

    /**
     * The version of the code quality tool to be used.
     */
    public void setToolVersion(String toolVersion) {
        this.toolVersion = toolVersion;
    }

    /**
     * Whether to allow the build to continue if there are warnings.
     *
     * Example: ignoreFailures = true
     */
    public boolean isIgnoreFailures() {
        return ignoreFailures;
    }

    /**
     * Whether to allow the build to continue if there are warnings.
     *
     * Example: ignoreFailures = true
     */
    public void setIgnoreFailures(boolean ignoreFailures) {
        this.ignoreFailures = ignoreFailures;
    }

    /**
     * The directory where reports will be generated.
     */
    public File getReportsDir() {
        return reportsDir;
    }

    /**
     * The directory where reports will be generated.
     */
    public void setReportsDir(File reportsDir) {
        this.reportsDir = reportsDir;
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/ci/CiUtil.java<|end_filename|>
package io.freefair.gradle.plugins.android.ci;

class CiUtil {

    static boolean isCi() {
        return "true".equals(System.getenv("CI")) ||
                "true".equals(System.getenv("TRAVIS")) ||
                "true".equals(System.getenv("CIRCLECI"));
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/AbstractAndroidCodeQualityPlugin.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import com.android.build.api.dsl.AndroidSourceSet;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.plugins.ReportingBasePlugin;
import org.gradle.api.reporting.ReportingExtension;

import java.util.*;
import java.util.concurrent.Callable;

/**
 * Copy of {@link org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin} which
 * uses {@link AndroidSourceSet AndroidSourceSets} instead of {@link org.gradle.api.tasks.SourceSet JavaSourceSets}
 *
 * @see org.gradle.api.plugins.quality.internal.AbstractCodeQualityPlugin
 */
public abstract class AbstractAndroidCodeQualityPlugin<T extends Task, E extends AndroidCodeQualityExtension> extends AndroidCodeQualityHelper {

    protected static ConventionMapping conventionMappingOf(Object object) {
        return ((IConventionAware) object).getConventionMapping();
    }

    protected Project project;
    protected E extension;

    @Override
    public final void apply(Project project) {
        this.project = project;
        beforeApply();

        super.apply(project);

        project.getPluginManager().apply(ReportingBasePlugin.class);
        createConfigurations();
        extension = createExtension();
        configureExtensionRule();
        configureTaskRule();
    }

    protected abstract String getToolName();

    protected abstract Class<T> getTaskType();

    Class<T> getCastedTaskType() {
        return getTaskType();
    }

    protected String getTaskBaseName() {
        return getToolName().toLowerCase();
    }

    protected String getConfigurationName() {
        return getToolName().toLowerCase();
    }

    protected String getReportName() {
        return getToolName().toLowerCase();
    }

    protected Class<? extends Plugin<? extends Project>> getBasePlugin() {
        return JavaBasePlugin.class;
    }

    protected void beforeApply() {
    }

    protected void createConfigurations() {
        Configuration configuration = project.getConfigurations().create(getConfigurationName());
        configuration.setVisible(false);
        configuration.setTransitive(true);
        configuration.setDescription("The " + getToolName() + " libraries to be used for this project.");
        // Don't need these things, they're provided by the runtime
        configuration.exclude(excludeProperties("ant", "ant"));
        configuration.exclude(excludeProperties("org.apache.ant", "ant"));
        configuration.exclude(excludeProperties("org.apache.ant", "ant-launcher"));
        configuration.exclude(excludeProperties("org.slf4j", "slf4j-api"));
        configuration.exclude(excludeProperties("org.slf4j", "jcl-over-slf4j"));
        configuration.exclude(excludeProperties("org.slf4j", "log4j-over-slf4j"));
        configuration.exclude(excludeProperties("commons-logging", "commons-logging"));
        configuration.exclude(excludeProperties("log4j", "log4j"));
        configureConfiguration(configuration);
    }

    protected abstract void configureConfiguration(Configuration configuration);

    private Map<String, String> excludeProperties(String group, String module) {
        return Map.of("group", group, "module", module);
    }

    protected abstract E createExtension();

    private void configureExtensionRule() {
        final ConventionMapping extensionMapping = conventionMappingOf(extension);

        String sourceSets = getExtensionElementsName();
        Callable<Collection<?>> ssCallable = getExtensionElementsCallable();

        extensionMapping.map(sourceSets, ArrayList::new);
        extensionMapping.map("reportsDir", () -> project.getExtensions().getByType(ReportingExtension.class).file(getReportName()));
        withBasePlugin(plugin -> extensionMapping.map(sourceSets, ssCallable));
    }

    protected abstract String getExtensionElementsName();
    protected abstract Callable<Collection<?>> getExtensionElementsCallable();

    private void configureTaskRule() {
        project.getTasks().withType(getCastedTaskType(), task -> {
            String prunedName = task.getName().replaceFirst(getTaskBaseName(), "");
            if (prunedName.isEmpty()) {
                prunedName = task.getName();
            }
            prunedName = ("" + prunedName.charAt(0)).toLowerCase() + prunedName.substring(1);
            configureTaskDefaults(task, prunedName);
        });
    }

    protected abstract void configureTaskDefaults(T task, String baseName);

    protected void withBasePlugin(Action<Plugin<?>> action) {
        project.getPlugins().withType(getBasePlugin(), action);
    }

    @Deprecated
    protected JavaPluginConvention getJavaPluginConvention() {
        return project.getConvention().getPlugin(JavaPluginConvention.class);
    }

    protected JavaPluginExtension getJavaPluginExtension() {
        return project.getExtensions().getByType(JavaPluginExtension.class);
    }
}


<|start_filename|>src/main/java/io/freefair/gradle/plugins/android/quality/AndroidCodeQualityHelper.java<|end_filename|>
package io.freefair.gradle.plugins.android.quality;

import io.freefair.gradle.plugins.android.AndroidProjectPlugin;

public abstract class AndroidCodeQualityHelper extends AndroidProjectPlugin {


}
