Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from convention to extension #577

Merged
merged 6 commits into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableList
import groovy.transform.CompileStatic
import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Named
Expand Down Expand Up @@ -65,7 +66,6 @@ import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskAction
import org.gradle.util.ConfigureUtil

import javax.annotation.Nullable
import javax.inject.Inject
Expand Down Expand Up @@ -463,9 +463,9 @@ public abstract class GenerateProtoTask extends DefaultTask {
* Configures the protoc builtins in a closure, which will be manipulating a
* NamedDomainObjectContainer<PluginOptions>.
*/
public void builtins(Closure configureClosure) {
public void builtins(Action<NamedDomainObjectContainer<PluginOptions>> configureAction) {
checkCanConfig()
ConfigureUtil.configure(configureClosure, builtins)
configureAction.execute(this.builtins)
}

/**
Expand All @@ -481,9 +481,9 @@ public abstract class GenerateProtoTask extends DefaultTask {
* Configures the protoc plugins in a closure, which will be maniuplating a
* NamedDomainObjectContainer<PluginOptions>.
*/
public void plugins(Closure configureClosure) {
public void plugins(Action<NamedDomainObjectContainer<PluginOptions>> configureAction) {
checkCanConfig()
ConfigureUtil.configure(configureClosure, plugins)
configureAction.execute(this.plugins)
}

/**
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,44 +29,57 @@
package com.google.protobuf.gradle

import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.transform.TypeChecked
import groovy.transform.TypeCheckingMode
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.tasks.TaskCollection
import org.gradle.util.ConfigureUtil

/**
* The main configuration block exposed as {@code protobuf} in the build script.
* Adds the protobuf {} block as a property of the project.
*/
@CompileStatic
public class ProtobufConfigurator {
// gradle require abstract modificator on extensions
@SuppressWarnings(["AbstractClassWithoutAbstractMethod", "AbstractClassWithPublicConstructor"])
abstract class ProtobufExtension {
private final Project project
private final GenerateProtoTaskCollection tasks
private final ToolsLocator tools
private final ArrayList<Closure> taskConfigClosures
private final ArrayList<Action<GenerateProtoTaskCollection>> taskConfigActions

/**
* The base directory of generated files. The default is
* "${project.buildDir}/generated/source/proto".
*/
String generatedFilesBaseDir
private String generatedFilesBaseDir

public ProtobufConfigurator(Project project, FileResolver fileResolver) {
public ProtobufExtension(final Project project) {
this.project = project
if (Utils.isAndroidProject(project)) {
tasks = new AndroidGenerateProtoTaskCollection()
} else {
tasks = new JavaGenerateProtoTaskCollection()
}
tools = new ToolsLocator(project)
taskConfigClosures = []
generatedFilesBaseDir = "${project.buildDir}/generated/source/proto"
this.tasks = new GenerateProtoTaskCollection(project)
this.tools = new ToolsLocator(project)
this.taskConfigActions = []
this.generatedFilesBaseDir = "${project.buildDir}/generated/source/proto"
}

@PackageScope
ToolsLocator getTools() {
return tools
}

void runTaskConfigClosures() {
taskConfigClosures.each { closure ->
ConfigureUtil.configure(closure, tasks)
String getGeneratedFilesBaseDir() {
return generatedFilesBaseDir
}

void setGeneratedFilesBaseDir(String generatedFilesBaseDir) {
this.generatedFilesBaseDir = generatedFilesBaseDir
}

@PackageScope
void configureTasks() {
this.taskConfigActions.each { action ->
action.execute(tasks)
}
}

Expand All @@ -78,16 +91,16 @@ public class ProtobufConfigurator {
* Locates the protoc executable. The closure will be manipulating an
* ExecutableLocator.
*/
public void protoc(Closure configureClosure) {
ConfigureUtil.configure(configureClosure, tools.protoc)
public void protoc(Action<ExecutableLocator> configureAction) {
configureAction.execute(tools.protoc)
}

/**
* Locate the codegen plugin executables. The closure will be manipulating a
* NamedDomainObjectContainer<ExecutableLocator>.
*/
public void plugins(Closure configureClosure) {
ConfigureUtil.configure(configureClosure, tools.plugins)
public void plugins(Action<NamedDomainObjectContainer<ExecutableLocator>> configureAction) {
configureAction.execute(tools.plugins)
}

/**
Expand All @@ -101,8 +114,8 @@ public class ProtobufConfigurator {
* change the task in your own afterEvaluate closure, as the change may not
* be picked up correctly by the wired javaCompile task.
*/
public void generateProtoTasks(Closure configureClosure) {
taskConfigClosures.add(configureClosure)
public void generateProtoTasks(Action<GenerateProtoTaskCollection> configureAction) {
taskConfigActions.add(configureAction)
}

/**
Expand All @@ -118,50 +131,50 @@ public class ProtobufConfigurator {
}

public class GenerateProtoTaskCollection {
private final Project project

GenerateProtoTaskCollection(final Project project) {
this.project = project
}

public TaskCollection<GenerateProtoTask> all() {
return project.tasks.withType(GenerateProtoTask)
}
}

public class AndroidGenerateProtoTaskCollection
extends GenerateProtoTaskCollection {
public TaskCollection<GenerateProtoTask> ofSourceSet(String sourceSet) {
return all().matching { GenerateProtoTask task ->
!Utils.isAndroidProject(project) && task.sourceSet.name == sourceSet
}
}

public TaskCollection<GenerateProtoTask> ofFlavor(String flavor) {
return all().matching { GenerateProtoTask task ->
task.flavors.contains(flavor)
Utils.isAndroidProject(project) && task.flavors.contains(flavor)
}
}

public TaskCollection<GenerateProtoTask> ofBuildType(String buildType) {
return all().matching { GenerateProtoTask task ->
task.buildType == buildType
Utils.isAndroidProject(project) && task.buildType == buildType
}
}

@TypeChecked(TypeCheckingMode.SKIP) // Don't depend on AGP
public TaskCollection<GenerateProtoTask> ofVariant(String variant) {
return all().matching { GenerateProtoTask task ->
task.variant.name == variant
Utils.isAndroidProject(project) && task.variant.name == variant
}
}

public TaskCollection<GenerateProtoTask> ofNonTest() {
return all().matching { GenerateProtoTask task ->
!task.isTestVariant
Utils.isAndroidProject(project) && !task.isTestVariant
}
}

public TaskCollection<GenerateProtoTask> ofTest() {
return all().matching { GenerateProtoTask task ->
task.isTestVariant
}
}
}

public class JavaGenerateProtoTaskCollection
extends GenerateProtoTaskCollection {
public TaskCollection<GenerateProtoTask> ofSourceSet(String sourceSet) {
return all().matching { GenerateProtoTask task ->
task.sourceSet.name == sourceSet
Utils.isAndroidProject(project) && task.isTestVariant
}
}
}
Expand Down
31 changes: 15 additions & 16 deletions src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class ProtobufPlugin implements Plugin<Project> {

private final FileResolver fileResolver
private Project project
private ProtobufExtension protobufExtension
private boolean wasApplied = false

@Inject
Expand All @@ -85,7 +86,9 @@ class ProtobufPlugin implements Plugin<Project> {
"Gradle version is ${project.gradle.gradleVersion}. Minimum supported version is 5.6")
}

this.project = project
this.protobufExtension = project.extensions.create("protobuf", ProtobufExtension, project)

this.project = project
// At least one of the prerequisite plugins must by applied before this plugin can be applied, so
// we will use the PluginManager.withPlugin() callback mechanism to delay applying this plugin until
// after that has been achieved. If project evaluation completes before one of the prerequisite plugins
Expand Down Expand Up @@ -123,8 +126,6 @@ class ProtobufPlugin implements Plugin<Project> {
// Provides the osdetector extension
project.apply([plugin:com.google.gradle.osdetector.OsDetectorPlugin])

project.convention.plugins.protobuf = new ProtobufConvention(project, fileResolver)

addSourceSetExtensions()
getSourceSets().all { sourceSet ->
createProtobufConfiguration(sourceSet.name)
Expand All @@ -143,17 +144,17 @@ class ProtobufPlugin implements Plugin<Project> {
}
}
addProtoTasks()
project.protobuf.runTaskConfigClosures()
this.protobufExtension.configureTasks()
// Disallow user configuration outside the config closures, because
// next in linkGenerateProtoTasksToSourceCompile() we add generated,
// outputs to the inputs of javaCompile tasks, and any new codegen
// plugin output added after this point won't be added to javaCompile
// tasks.
project.protobuf.generateProtoTasks.all()*.doneConfig()
this.protobufExtension.generateProtoTasks.all()*.doneConfig()
linkGenerateProtoTasksToSourceCompile()
// protoc and codegen plugin configuration may change through the protobuf{}
// block. Only at this point the configuration has been finalized.
project.protobuf.tools.registerTaskDependencies(project.protobuf.getGenerateProtoTasks().all())
this.protobufExtension.tools.registerTaskDependencies(this.protobufExtension.getGenerateProtoTasks().all())

// Register proto and generated sources with IDE
addSourcesToIde()
Expand Down Expand Up @@ -290,7 +291,7 @@ class ProtobufPlugin implements Plugin<Project> {
/**
* Creates Protobuf tasks for a variant in an Android project.
*/
private void addTasksForVariant(final Object variant, boolean isTestVariant) {
private void addTasksForVariant(final Object variant, final boolean isTestVariant) {
// GenerateProto task, one per variant (compilation unit).
Task generateProtoTask = addGenerateProtoTask(variant.name, variant.sourceSets)
generateProtoTask.setVariant(variant, isTestVariant)
Expand Down Expand Up @@ -351,17 +352,16 @@ class ProtobufPlugin implements Plugin<Project> {
Utils.getSourceSetSubstringForTaskNames(sourceSetOrVariantName) + 'Proto'
return project.tasks.create(generateProtoTaskName, GenerateProtoTask) {
description = "Compiles Proto source for '${sourceSetOrVariantName}'"
outputBaseDir = "${project.protobuf.generatedFilesBaseDir}/${sourceSetOrVariantName}"
outputBaseDir = "${this.protobufExtension.generatedFilesBaseDir}/${sourceSetOrVariantName}"
it.fileResolver = this.fileResolver
sourceSets.each { sourceSet ->
addSourceFiles(sourceSet.proto)
SourceDirectorySet protoSrcDirSet = sourceSet.proto
addIncludeDir(protoSrcDirSet.sourceDirectories)
}
ProtobufConfigurator extension = project.protobuf
protocLocator.set(project.providers.provider { extension.tools.protoc })
protocLocator.set(project.providers.provider { this.protobufExtension.tools.protoc })
pluginsExecutableLocators.set(project.providers.provider {
((NamedDomainObjectContainer<ExecutableLocator>) extension.tools.plugins).asMap
((NamedDomainObjectContainer<ExecutableLocator>) this.protobufExtension.tools.plugins).asMap
})
}
}
Expand All @@ -374,8 +374,7 @@ class ProtobufPlugin implements Plugin<Project> {
* variant may have multiple sourceSets, each of these sourceSets will have
* its own extraction task.
*/
private Task setupExtractProtosTask(
GenerateProtoTask generateProtoTask, String sourceSetName) {
private Task setupExtractProtosTask(final GenerateProtoTask generateProtoTask, final String sourceSetName) {
String extractProtosTaskName = 'extract' +
Utils.getSourceSetSubstringForTaskNames(sourceSetName) + 'Proto'
Task task = project.tasks.findByName(extractProtosTaskName)
Expand Down Expand Up @@ -466,7 +465,7 @@ class ProtobufPlugin implements Plugin<Project> {
private void linkGenerateProtoTasksToSourceCompile() {
if (Utils.isAndroidProject(project)) {
(getNonTestVariants() + project.android.testVariants).each { variant ->
project.protobuf.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
this.protobufExtension.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
SourceDirectorySet generatedSources = genProtoTask.getOutputSourceDirectorySet()
// This cannot be called once task execution has started.
variant.registerJavaGeneratingTask(genProtoTask, generatedSources.source)
Expand All @@ -476,7 +475,7 @@ class ProtobufPlugin implements Plugin<Project> {
}

project.android.unitTestVariants.each { variant ->
project.protobuf.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
this.protobufExtension.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
// unit test variants do not implement registerJavaGeneratingTask
Task javaCompileTask = variant.javaCompileProvider.get()
if (javaCompileTask != null) {
Expand All @@ -490,7 +489,7 @@ class ProtobufPlugin implements Plugin<Project> {
}
} else {
project.sourceSets.each { SourceSet sourceSet ->
project.protobuf.generateProtoTasks.ofSourceSet(sourceSet.name).each { GenerateProtoTask genProtoTask ->
this.protobufExtension.generateProtoTasks.ofSourceSet(sourceSet.name).each { GenerateProtoTask genProtoTask ->
SUPPORTED_LANGUAGES.each { String lang ->
linkGenerateProtoTasksToTaskName(sourceSet.getCompileTaskName(lang), genProtoTask)
}
Expand Down
Loading