![JAR search and dependency download from the Maven repository](/logo.png)
com.parmet.buf.gradle.ProtobufGradlePluginSupport.kt Maven / Gradle / Ivy
/*
* Copyright (c) 2021 Andrew Parmet
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.parmet.buf.gradle
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.AppliedPlugin
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByName
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.the
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
const val CREATE_SYM_LINKS_TO_MODULES_TASK_NAME = "createSymLinksToModules"
const val WRITE_WORKSPACE_YAML_TASK_NAME = "writeWorkspaceYaml"
private val BUILD_EXTRACTED_INCLUDE_PROTOS_MAIN =
listOf("build", "extracted-include-protos", "main").joinToString(File.separator)
private val BUILD_EXTRACTED_PROTOS_MAIN =
listOf("build", "extracted-protos", "main").joinToString(File.separator)
internal fun Project.hasProtobufGradlePlugin() =
pluginManager.hasPlugin("com.google.protobuf")
internal fun Project.withProtobufGradlePlugin(action: (AppliedPlugin) -> Unit) =
pluginManager.withPlugin("com.google.protobuf", action)
internal fun Project.configureCreateSymLinksToModules() {
tasks.register(CREATE_SYM_LINKS_TO_MODULES_TASK_NAME) {
workspaceCommonConfig()
}
}
abstract class CreateSymLinksToModulesTask : DefaultTask() {
@TaskAction
fun createSymLinksToModules() {
allProtoDirs().forEach {
val symLinkFile = File(bufbuildDir, mangle(it))
if (!symLinkFile.exists()) {
logger.info("Creating symlink for $it at $symLinkFile")
Files.createSymbolicLink(
symLinkFile.toPath(),
bufbuildDir.toPath().relativize(project.file(it).toPath())
)
}
}
}
}
internal fun Project.configureWriteWorkspaceYaml() {
tasks.register(WRITE_WORKSPACE_YAML_TASK_NAME) {
workspaceCommonConfig()
}
}
abstract class WriteWorkspaceYamlTask : DefaultTask() {
@TaskAction
fun writeWorkspaceYaml() {
val bufWork =
"""
|version: v1
|directories:
${workspaceSymLinkEntries()}
""".trimMargin()
logger.info("Writing generated buf.work.yaml:\n$bufWork")
File(bufbuildDir, "buf.work.yaml").writeText(bufWork)
}
}
private fun Task.workspaceCommonConfig() {
dependsOn(
project
.tasks
.matching { it::class.java.name == "com.google.protobuf.gradle.ProtobufExtract_Decorated" }
)
createsOutput()
}
private fun Task.workspaceSymLinkEntries() =
allProtoDirs().joinToString("\n") { "| - ${mangle(it)}" }
private fun Task.allProtoDirs(): List =
(project.srcProtoDirs() + extractProtoDirs()).filter { project.anyProtos(it) }
internal fun Project.srcProtoDirs() =
the().flatMap { it.protoDirs(this) } + androidSrcProtoDirs()
private fun Project.androidSrcProtoDirs() =
extensions.findByName("android")
?.let { baseExtension ->
val prop = baseExtension::class.declaredMemberProperties.single { it.name == "sourceSets" }
@Suppress("UNCHECKED_CAST")
(prop as KProperty1>).get(baseExtension)
}
.orEmpty()
.flatMap { it.protoDirs(this) }
private fun ExtensionAware.protoDirs(project: Project) =
extensions.getByName("proto").srcDirs
.map { project.projectDir.toPath().relativize(it.toPath()) }
.filter { project.anyProtos(it) }
private fun extractProtoDirs() =
listOf(
BUILD_EXTRACTED_INCLUDE_PROTOS_MAIN,
BUILD_EXTRACTED_PROTOS_MAIN
).map(Paths::get)
private fun Project.anyProtos(path: Path) =
file(path).walkTopDown().any { it.extension == "proto" }
internal fun mangle(name: Path) =
name.toString().replace("-", "--").replace(File.separator, "-")
internal inline fun Project.registerBufTask(
name: String,
noinline configuration: T.() -> Unit
): TaskProvider {
val taskProvider = tasks.register(name, configuration)
withProtobufGradlePlugin {
afterEvaluate {
taskProvider.dependsOn(CREATE_SYM_LINKS_TO_MODULES_TASK_NAME)
taskProvider.dependsOn(WRITE_WORKSPACE_YAML_TASK_NAME)
}
}
return taskProvider
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy