google / protobuf-gradle-plugin

Protobuf Plugin for Gradle
Other
1.77k stars 273 forks source link

Missing extension functions for Kotlin DSL #309

Open zhangkun83 opened 5 years ago

zhangkun83 commented 5 years ago

Reported by @alexvas in #275:

As of plugin version of 0.8.8 I still need a pair of auxiliary functions:

fun ProtobufConfigurator.plugins(closure: NamedDomainObjectContainerScope<ExecutableLocator>.() -> Unit) {
    plugins(closureOf<NamedDomainObjectContainer<ExecutableLocator>> {
        closure(NamedDomainObjectContainerScope.of(this))
    })
}

fun GenerateProtoTask.plugins(configuration: NamedDomainObjectContainerScope<GenerateProtoTask.PluginOptions>.()-> Unit) {
    plugins(closureOf<NamedDomainObjectContainer<GenerateProtoTask.PluginOptions>> {
        configuration(NamedDomainObjectContainerScope.of(this))
    })
}

to make

protobuf {
    protoc {
        // The artifact spec for the Protobuf Compiler
        artifact = Libs.protoc
    }
    plugins {
        // Optional: an artifact spec for a protoc plugin, with "grpc" as
        // the identifier, which can be referred to in the "plugins"
        // container of the "generateProtoTasks" closure.
        id("grpc") {
            artifact = Libs.protoc_gen_grpc_java
        }
    }
   generateProtoTasks {
        ofSourceSet("main").forEach {
            it.plugins {
                // Apply the "grpc" plugin whose spec is defined above, without
                // options.  Note the braces cannot be omitted, otherwise the
                // plugin will not be added. This is because of the implicit way
                // NamedDomainObjectContainer binds the methods.
                id("grpc")
            }
        }
    }
}

work. Otherwise there is a gradle configuration error:

  Line 31:         id("grpc") {
                              ^ Too many arguments for public open fun id(id: String): PluginDependencySpec defined in org.gradle.kotlin.dsl.PluginDependenciesSpecScope

  Line 32:             artifact = Libs.protoc_gen_grpc_java
                       ^ Unresolved reference: artifact

2 errors

using Gradle 5.2.1

marcoferrer commented 5 years ago

I’ll take a look into this later today.

marcoferrer commented 5 years ago

I was unable to reproduce this issue using the example project in master, gradle 5.2.1, and plugin version 0.8.8

image

I left type hints enabled to show that all types still resolved correctly.

My best guess is that the original reporter had conflicting imports in their build script. Specifically some other function named id from another library with a different signature. This would explain the too many arguments message in the exception. Since the conflicting import wouldnt have the same signature.

Since we are only using id() in two specific cases we can make the receiver less generic and reduce the likely hood of users experiencing conflicting imports.

We would need to

Marking the existing id() method as private shouldnt break existing users since existing import statements would still resolve the correct method.

Proposed change.

private fun <T : Any> NamedDomainObjectContainerScope<T>.id(id: String, action: (T.() -> Unit)? = null) {
    action?.let { create(id, closureOf(it)) }
            ?: create(id)
}

@JvmName("executableLocatorId")
fun NamedDomainObjectContainerScope<ExecutableLocator>.id(
    id: String,
    action: (ExecutableLocator.() -> Unit)? = null
) {
    id<ExecutableLocator>(id,action)
}

@JvmName("pluginOptionsId")
fun NamedDomainObjectContainerScope<GenerateProtoTask.PluginOptions>.id(
    id: String,
    action: (GenerateProtoTask.PluginOptions.() -> Unit)? = null
) {
    id<GenerateProtoTask.PluginOptions>(id,action)
}

@zhangkun83 If we want to try to limit issues with conflicting imports I can submit the PR for this change.

zhangkun83 commented 5 years ago

Thank you @marcoferrer! Please go ahead with the PR.

Decat-SimonA commented 5 years ago

I can reproduce this issue by removing the import com.google.protobuf.gradle.*. Adding it solve the problem in my project

sgalcheung commented 6 months ago

use Groovy DSL also has similar issue.

protobuf {
   protoc {
       // By default the plugin will search for the protoc executable in the system search path.
       // We recommend you to take the advantage of pre-compiled protoc that we have published on Maven Central
       artifact = libs.protoc
   }
   plugins {
       grpc {
           artifact = libs.protoc.gen.grpc.java
       }
   }
   generateProtoTasks {
       all()*.plugins { grpc {} }
   }
}

./gradlew build

Task :app:extractIncludeProto Task :app:extractProto Task :app:generateProto FAILED

FAILURE: Build failed with an exception.

  • What went wrong: Execution failed for task ':app:generateProto'.

    protoc: stdout: . stderr: protoc-gen-grpc: program not found or is not executable Please specify a program using absolute path or make sure the program is available in your PATH system variable --grpc_out: protoc-gen-grpc: Plugin failed with status code 1.

  • Try:

    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights. Get more help at https://help.gradle.org.

BUILD FAILED in 2s 3 actionable tasks: 3 executed

When I specified the specific package info, it worked well. Seems this plugin doesn't support 'Sharing dependency versions between projects'?

protobuf {
   protoc {
       // By default the plugin will search for the protoc executable in the system search path.
       // We recommend you to take the advantage of pre-compiled protoc that we have published on Maven Central
    //    artifact = libs.protoc
       artifact = "com.google.protobuf:protoc:3.25.1"
   }
   plugins {
       grpc {
        //    artifact = libs.protoc.gen.grpc.java
           artifact = "io.grpc:protoc-gen-grpc-java:1.64.0"
       }
   }
   generateProtoTasks {
       all()*.plugins { grpc {} }
   }
}