com.google.protobuf.gradle.ProtobufPlugin.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of protobuf-gradle-plugin Show documentation
Show all versions of protobuf-gradle-plugin Show documentation
Gradle build plugin to handle Protocol Buffers automated code generation and compilation
/*
* Original work copyright (c) 2015, Alex Antonov. All rights reserved.
* Modified work copyright (c) 2015, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.protobuf.gradle
import com.google.common.collect.ImmutableList
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.ConfigurableFileTree
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.tasks.SourceSet
import javax.inject.Inject
class ProtobufPlugin implements Plugin {
private final FileResolver fileResolver
private Project project
@Inject
public ProtobufPlugin(FileResolver fileResolver) {
this.fileResolver = fileResolver;
}
void apply(final Project project) {
this.project = project
def gv = project.gradle.gradleVersion =~ "(\\d*)\\.(\\d*).*"
if (!gv || !gv.matches() || gv.group(1).toInteger() < 2 || gv.group(2).toInteger() < 2) {
println("You are using Gradle ${project.gradle.gradleVersion}: This version of the protobuf plugin requires minimum Gradle version 2.2")
}
if (!project.plugins.hasPlugin('java') && !Utils.isAndroidProject(project)) {
throw new GradleException('Please apply the Java plugin or the Android plugin first.'
+ ' This error may also be a result of using the new Gradle plugins DSL.'
+ ' Please use the traditional "apply" function as described in README.md.')
}
// Provides the osdetector extension
project.apply plugin: 'osdetector'
project.convention.plugins.protobuf = new ProtobufConvention(project, fileResolver);
addSourceSetExtensions()
getSourceSets().all { sourceSet ->
createConfiguration(sourceSet.name)
}
project.afterEvaluate {
// The Android variants are only available at this point.
addProtoTasks()
project.protobuf.runTaskConfigClosures()
// Disallow user configuration outside the config closures, because
// next in linkGenerateProtoTasksToJavaCompile() 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()
linkGenerateProtoTasksToJavaCompile()
// protoc and codegen plugin configuration may change through the protobuf{}
// block. Only at this point the configuration has been finalized.
project.protobuf.tools.resolve()
}
}
/**
* Creates a configuration if necessary for a source set so that the build
* author can configure dependencies for it.
*/
private createConfiguration(String sourceSetName) {
String configName = Utils.getConfigName(sourceSetName, 'protobuf')
if (project.configurations.findByName(configName) == null) {
project.configurations.create(configName) {
visible = false
transitive = false
extendsFrom = []
}
}
}
/**
* Adds the proto extension to all SourceSets, e.g., it creates
* sourceSets.main.proto and sourceSets.test.proto.
*/
private addSourceSetExtensions() {
getSourceSets().all { sourceSet ->
sourceSet.extensions.create('proto', ProtobufSourceDirectorySet, project, sourceSet.name, fileResolver)
}
}
/**
* Returns the sourceSets container of a Java or an Android project.
*/
private Object getSourceSets() {
if (Utils.isAndroidProject(project)) {
return project.android.sourceSets
} else {
return project.sourceSets
}
}
private Object getNonTestVariants() {
return project.android.hasProperty('libraryVariants') ?
project.android.libraryVariants : project.android.applicationVariants
}
/**
* Adds Protobuf-related tasks to the project.
*/
private addProtoTasks() {
if (Utils.isAndroidProject(project)) {
getNonTestVariants().each { variant ->
addTasksForVariant(variant, false)
}
project.android.testVariants.each { testVariant ->
addTasksForVariant(testVariant, true)
}
} else {
getSourceSets().each { sourceSet ->
addTasksForSourceSet(sourceSet)
}
}
}
/**
* Creates Protobuf tasks for a sourceSet in a Java project.
*/
private addTasksForSourceSet(final SourceSet sourceSet) {
def generateProtoTask = addGenerateProtoTask(sourceSet.name, [sourceSet])
generateProtoTask.sourceSet = sourceSet
generateProtoTask.doneInitializing()
generateProtoTask.builtins {
java {}
}
def extractProtosTask = maybeAddExtractProtosTask(sourceSet.name)
generateProtoTask.dependsOn(extractProtosTask)
def extractIncludeProtosTask = maybeAddExtractIncludeProtosTask(sourceSet.name)
generateProtoTask.dependsOn(extractIncludeProtosTask)
// Include source proto files in the compiled archive, so that proto files from
// dependent projects can import them.
def processResourcesTask =
project.tasks.getByName(sourceSet.getTaskName('process', 'resources'))
processResourcesTask.from(generateProtoTask.inputs.sourceFiles) {
include '**/*.proto'
}
}
/**
* Creates Protobuf tasks for a variant in an Android project.
*/
private addTasksForVariant(final Object variant, final boolean isTestVariant) {
// The collection of sourceSets that will be compiled for this variant
def sourceSetNames = new ArrayList()
def sourceSets = new ArrayList()
if (isTestVariant) {
// All test variants will include the androidTest sourceSet
sourceSetNames.add 'androidTest'
} else {
// All non-test variants will include the main sourceSet
sourceSetNames.add 'main'
}
sourceSetNames.add variant.name
sourceSetNames.add variant.buildType.name
ImmutableList.Builder flavorListBuilder = ImmutableList.builder()
if (variant.hasProperty('productFlavors')) {
variant.productFlavors.each { flavor ->
sourceSetNames.add flavor.name
flavorListBuilder.add flavor.name
}
}
sourceSetNames.each { sourceSetName ->
sourceSets.add project.android.sourceSets.maybeCreate(sourceSetName)
}
def generateProtoTask = addGenerateProtoTask(variant.name, sourceSets)
generateProtoTask.setVariant(variant, isTestVariant)
generateProtoTask.flavors = flavorListBuilder.build()
generateProtoTask.buildType = variant.buildType.name
generateProtoTask.doneInitializing()
generateProtoTask.builtins {
javanano {}
}
sourceSetNames.each { sourceSetName ->
def extractProtosTask = maybeAddExtractProtosTask(sourceSetName)
generateProtoTask.dependsOn(extractProtosTask)
def extractIncludeProtosTask = maybeAddExtractIncludeProtosTask(sourceSetName)
generateProtoTask.dependsOn(extractIncludeProtosTask)
}
// TODO(zhangkun83): Include source proto files in the compiled archive,
// so that proto files from dependent projects can import them.
}
/**
* Adds a task to run protoc and compile all proto source files for a sourceSet or variant.
*
* @param sourceSetOrVariantName the name of the sourceSet (Java) or
* variant (Android) that this task will run for.
*
* @param sourceSets the sourceSets that contains the proto files to be
* 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