Skip to content

Commit

Permalink
Migrate from convention to extension
Browse files Browse the repository at this point in the history
More details can be found here: google#505
  • Loading branch information
rougsig committed Jul 6, 2022
1 parent 2b702eb commit 17c6f14
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 175 deletions.

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 {
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 = Utils.isAndroidProject(project)
? new AndroidGenerateProtoTaskCollection()
: new JavaGenerateProtoTaskCollection()
this.tools = new ToolsLocator(project)
this.taskConfigActions = []
this.generatedFilesBaseDir = "${project.buildDir}/generated/source/proto"
}

@PackageScope
ToolsLocator getTools() {
return tools
}

String getGeneratedFilesBaseDir() {
return generatedFilesBaseDir
}

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

void runTaskConfigClosures() {
taskConfigClosures.each { closure ->
ConfigureUtil.configure(closure, tasks)
@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 @@ -123,8 +136,7 @@ public class ProtobufConfigurator {
}
}

public class AndroidGenerateProtoTaskCollection
extends GenerateProtoTaskCollection {
public class AndroidGenerateProtoTaskCollection extends GenerateProtoTaskCollection {
public TaskCollection<GenerateProtoTask> ofFlavor(String flavor) {
return all().matching { GenerateProtoTask task ->
task.flavors.contains(flavor)
Expand All @@ -137,7 +149,8 @@ public class ProtobufConfigurator {
}
}

@TypeChecked(TypeCheckingMode.SKIP) // Don't depend on AGP
@TypeChecked(TypeCheckingMode.SKIP)
// Don't depend on AGP
public TaskCollection<GenerateProtoTask> ofVariant(String variant) {
return all().matching { GenerateProtoTask task ->
task.variant.name == variant
Expand All @@ -157,8 +170,7 @@ public class ProtobufConfigurator {
}
}

public class JavaGenerateProtoTaskCollection
extends GenerateProtoTaskCollection {
public class JavaGenerateProtoTaskCollection extends GenerateProtoTaskCollection {
public TaskCollection<GenerateProtoTask> ofSourceSet(String sourceSet) {
return all().matching { GenerateProtoTask task ->
task.sourceSet.name == sourceSet
Expand Down
70 changes: 42 additions & 28 deletions src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ class ProtobufPlugin implements Plugin<Project> {
"Gradle version is ${project.gradle.gradleVersion}. Minimum supported version is 5.6")
}

this.project = project
ProtobufExtension 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 All @@ -98,7 +100,7 @@ class ProtobufPlugin implements Plugin<Project> {
} else {
wasApplied = true

doApply()
doApply(protobufExtension)
}
}

Expand All @@ -119,12 +121,10 @@ class ProtobufPlugin implements Plugin<Project> {
task.source genProtoTask.getOutputSourceDirectorySet().include("**/*.java", "**/*.kt")
}

private void doApply() {
private void doApply(final ProtobufExtension protobufExtension) {
// 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 @@ -142,18 +142,18 @@ class ProtobufPlugin implements Plugin<Project> {
createCompileProtoPathConfiguration(sourceSet.name)
}
}
addProtoTasks()
project.protobuf.runTaskConfigClosures()
addProtoTasks(protobufExtension)
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()
linkGenerateProtoTasksToSourceCompile()
protobufExtension.generateProtoTasks.all()*.doneConfig()
linkGenerateProtoTasksToSourceCompile(protobufExtension)
// 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())
protobufExtension.tools.registerTaskDependencies(protobufExtension.getGenerateProtoTasks().all())

// Register proto and generated sources with IDE
addSourcesToIde()
Expand Down Expand Up @@ -248,26 +248,29 @@ class ProtobufPlugin implements Plugin<Project> {
/**
* Adds Protobuf-related tasks to the project.
*/
private void addProtoTasks() {
private void addProtoTasks(final ProtobufExtension protobufExtension) {
if (Utils.isAndroidProject(project)) {
getNonTestVariants().each { variant ->
addTasksForVariant(variant, false)
addTasksForVariant(protobufExtension, variant, false)
}
(project.android.unitTestVariants + project.android.testVariants).each { variant ->
addTasksForVariant(variant, true)
addTasksForVariant(protobufExtension, variant, true)
}
} else {
getSourceSets().each { sourceSet ->
addTasksForSourceSet(sourceSet)
addTasksForSourceSet(protobufExtension, sourceSet)
}
}
}

/**
* Creates Protobuf tasks for a sourceSet in a Java project.
*/
private void addTasksForSourceSet(final SourceSet sourceSet) {
Task generateProtoTask = addGenerateProtoTask(sourceSet.name, [sourceSet])
private void addTasksForSourceSet(
final ProtobufExtension protobufExtension,
final SourceSet sourceSet
) {
Task generateProtoTask = addGenerateProtoTask(protobufExtension, sourceSet.name, [sourceSet])
generateProtoTask.sourceSet = sourceSet
generateProtoTask.doneInitializing()
generateProtoTask.builtins {
Expand All @@ -290,9 +293,13 @@ 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 ProtobufExtension protobufExtension,
final Object variant,
final boolean isTestVariant
) {
// GenerateProto task, one per variant (compilation unit).
Task generateProtoTask = addGenerateProtoTask(variant.name, variant.sourceSets)
Task generateProtoTask = addGenerateProtoTask(protobufExtension, variant.name, variant.sourceSets)
generateProtoTask.setVariant(variant, isTestVariant)
generateProtoTask.flavors = ImmutableList.copyOf(variant.productFlavors.collect { it.name } )
if (variant.hasProperty('buildType')) {
Expand Down Expand Up @@ -346,22 +353,25 @@ class ProtobufPlugin implements Plugin<Project> {
* compiled. For Java it's the sourceSet that sourceSetOrVariantName stands
* for; for Android it's the collection of sourceSets that the variant includes.
*/
private Task addGenerateProtoTask(String sourceSetOrVariantName, Collection<Object> sourceSets) {
private Task addGenerateProtoTask(
ProtobufExtension protobufExtension,
String sourceSetOrVariantName,
Collection<Object> sourceSets
) {
String generateProtoTaskName = 'generate' +
Utils.getSourceSetSubstringForTaskNames(sourceSetOrVariantName) + 'Proto'
return project.tasks.create(generateProtoTaskName, GenerateProtoTask) {
description = "Compiles Proto source for '${sourceSetOrVariantName}'"
outputBaseDir = "${project.protobuf.generatedFilesBaseDir}/${sourceSetOrVariantName}"
outputBaseDir = "${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 { protobufExtension.tools.protoc })
pluginsExecutableLocators.set(project.providers.provider {
((NamedDomainObjectContainer<ExecutableLocator>) extension.tools.plugins).asMap
((NamedDomainObjectContainer<ExecutableLocator>) protobufExtension.tools.plugins).asMap
})
}
}
Expand All @@ -375,7 +385,9 @@ class ProtobufPlugin implements Plugin<Project> {
* its own extraction task.
*/
private Task setupExtractProtosTask(
GenerateProtoTask generateProtoTask, String sourceSetName) {
final GenerateProtoTask generateProtoTask,
final String sourceSetName
) {
String extractProtosTaskName = 'extract' +
Utils.getSourceSetSubstringForTaskNames(sourceSetName) + 'Proto'
Task task = project.tasks.findByName(extractProtosTaskName)
Expand Down Expand Up @@ -463,10 +475,12 @@ class ProtobufPlugin implements Plugin<Project> {
}
}

private void linkGenerateProtoTasksToSourceCompile() {
private void linkGenerateProtoTasksToSourceCompile(
ProtobufExtension protobufExtension
) {
if (Utils.isAndroidProject(project)) {
(getNonTestVariants() + project.android.testVariants).each { variant ->
project.protobuf.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
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 +490,7 @@ class ProtobufPlugin implements Plugin<Project> {
}

project.android.unitTestVariants.each { variant ->
project.protobuf.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
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 +504,7 @@ class ProtobufPlugin implements Plugin<Project> {
}
} else {
project.sourceSets.each { SourceSet sourceSet ->
project.protobuf.generateProtoTasks.ofSourceSet(sourceSet.name).each { GenerateProtoTask genProtoTask ->
protobufExtension.generateProtoTasks.ofSourceSet(sourceSet.name).each { GenerateProtoTask genProtoTask ->
SUPPORTED_LANGUAGES.each { String lang ->
linkGenerateProtoTasksToTaskName(sourceSet.getCompileTaskName(lang), genProtoTask)
}
Expand Down
Loading

0 comments on commit 17c6f14

Please sign in to comment.