From 59891678a52d7a7fdebf455819a9f4405f662f2d Mon Sep 17 00:00:00 2001 From: Adam <897017+asemy@users.noreply.github.com> Date: Sat, 30 Oct 2021 20:24:58 +0200 Subject: [PATCH] tried moving protobuf plugin to separate project, but IntelliJ doesn't like it --- buildSrc/build.gradle.kts | 11 + modules/protoc-gradle-plugin/build.gradle.kts | 102 +----- .../dev/adamko/gradle/pbandg/ProtocPlugin.kt | 330 +++++++++++++----- settings.gradle.kts | 2 +- 4 files changed, 260 insertions(+), 185 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8b7aba1..dba2d23 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { `kotlin-dsl` kotlin("jvm") version "1.5.31" @@ -20,3 +22,12 @@ dependencies { implementation("com.github.node-gradle:gradle-node-plugin:3.1.1") } + +tasks.withType().configureEach { + kotlinOptions.freeCompilerArgs += listOf( + "-Xopt-in=kotlin.OptIn", + "-Xopt-in=kotlin.ExperimentalStdlibApi", + "-Xopt-in=kotlin.time.ExperimentalTime", + "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + ) +} \ No newline at end of file diff --git a/modules/protoc-gradle-plugin/build.gradle.kts b/modules/protoc-gradle-plugin/build.gradle.kts index ab9eb2b..47892e9 100644 --- a/modules/protoc-gradle-plugin/build.gradle.kts +++ b/modules/protoc-gradle-plugin/build.gradle.kts @@ -1,16 +1,14 @@ -import org.gradle.nativeplatform.platform.internal.ArchitectureInternal -import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform - plugins { kotlin("jvm") version "1.5.31" `kotlin-dsl` `java-gradle-plugin` + `maven-publish` } gradlePlugin { plugins { - create("Protobuf & Gradle") { - id = "dev-adamko.pb-and-g" + create("ProtobufAndGradle") { + id = "dev.adamko.pb-and-g" implementationClass = "dev.adamko.gradle.pbandg.ProtocPluginKt" description = "Protobuf & Gradle. Wrapper for protoc to generate code from Proto Buffer files." @@ -18,6 +16,9 @@ gradlePlugin { } } +group = "dev.adamko.gradle.pbandg" +version = "0.0.1-SNAPSHOT" + val protocConfiguration: Configuration by configurations.creating { // A configuration meant for consumers that need the implementation of this component @@ -25,10 +26,13 @@ val protocConfiguration: Configuration by configurations.creating { isCanBeConsumed = false } -val protobufVersion = "3.19.0" +val protobufVersion = "3.19.1" val protocVersion = "3.9.2" dependencies { + implementation(platform("org.jetbrains.kotlin:kotlin-bom")) + implementation(kotlin("stdlib")) + implementation(platform("com.google.protobuf:protobuf-bom:$protobufVersion")) implementation("com.google.protobuf:protobuf-java:$protobufVersion") @@ -45,9 +49,6 @@ dependencies { implementation("io.grpc:protoc-gen-grpc-kotlin:1.2.0") implementation("javax.annotation:javax.annotation-api:1.3.2") -// - -// implementation(npm("protoc-gen-ts", "0.15.0")) implementation( group = "com.google.protobuf", @@ -67,93 +68,10 @@ dependencies { ext = "exe", ) -// protocConfiguration("com.google.protobuf:protoc:3.9.2@exe") - } - - -// https://github.com/protocolbuffers/protobuf/tree/master/protoc-artifacts -// The name of a published protoc artifact is in the format: -// protoc---.exe -// e.g., protoc-3.6.1-linux-x86_64.exe -// Note that artifacts for Linux/macOS also have the .exe suffix, but they are not windows binaries. -val os: OperatingSystem = DefaultNativePlatform.getCurrentOperatingSystem() -val arch: ArchitectureInternal = DefaultNativePlatform.getCurrentArchitecture() - repositories { mavenCentral() - -// ivy { -// url = project.repositories.mavenCentral().url -// -// patternLayout { -// -// // com/google/protobuf/protoc/3.9.2/protoc-3.9.2-linux-aarch_64.exe -// artifact("[organisation]/[module]/[revision]/[artifact]-[revision]-${os.name}-${arch.name}.[ext]") -// -//// artifact("3rd-party-artifacts/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]") -//// artifact("company-artifacts/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]") -//// ivy("ivy-files/[organisation]/[module]/[revision]/ivy.xml") -//// artifact("[organisation]/[module]/[revision]/[artifact]-[revision].[ext]") -// setM2compatible(true) -// metadataSources { -// artifact() -// } -// } -// } - } -tasks.register("protocExecCopy") { - group = project.name - -// from(protocConfiguration.artifacts) - - from(protocConfiguration.resolve()) - - into(project.layout.buildDirectory.dir("protocCopy")) -} - -//tasks.register("dlPc") { -// group = project.name -// -// val downloadDir = this.temporaryDir -// -// outputs.dir(downloadDir) -// -// doLast { -// -//// downloadDir.mkdirs() -// -// val protocArtifactFileExt = "exe" -// -// val osFamilyName = DefaultNativePlatform.host().operatingSystem.toFamilyName() -// -// val arch: String = -// DefaultNativePlatform.getCurrentArchitecture() -// .name -// .replace("-", "_") -// -// val artifact = "protoc-$protocVersion-${osFamilyName}-${arch}.$protocArtifactFileExt" -// -// val uri = uri( -// ArtifactRepositoryContainer.MAVEN_CENTRAL_URL -// + "com/google/protobuf/protoc/$protocVersion/$artifact" -// ) -// // actual: -// // https://repo.maven.apache.org/maven2/com/google/protobuf/protoc/3.9.2/protoc-3.9.2-windows-x86_64.exe -// // https://repo.maven.apache.org/maven2/com/google/protobuf/protoc/3.9.2/protoc-3.9.2-windows-x86-64.exe -// -// ant.invokeMethod( -// "get", mapOf( -// "src" to uri, -// "dest" to downloadDir.canonicalPath, -// "verbose" to true, -// ) -// ) -// } -// -//} -// diff --git a/modules/protoc-gradle-plugin/src/main/kotlin/dev/adamko/gradle/pbandg/ProtocPlugin.kt b/modules/protoc-gradle-plugin/src/main/kotlin/dev/adamko/gradle/pbandg/ProtocPlugin.kt index a7c882f..70080a8 100644 --- a/modules/protoc-gradle-plugin/src/main/kotlin/dev/adamko/gradle/pbandg/ProtocPlugin.kt +++ b/modules/protoc-gradle-plugin/src/main/kotlin/dev/adamko/gradle/pbandg/ProtocPlugin.kt @@ -1,67 +1,217 @@ package dev.adamko.gradle.pbandg +import java.io.File +import java.util.function.Supplier import org.gradle.api.DefaultTask import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ExternalDependency +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty import org.gradle.api.plugins.ExtensionAware import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.Sync import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.domainObjectContainer import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.defaultDependencies +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.findByType +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.getValue import org.gradle.kotlin.dsl.withType import org.gradle.kotlin.dsl.property +import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.register +import org.gradle.nativeplatform.platform.Architecture import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform +import org.gradle.nativeplatform.platform.internal.DefaultOperatingSystem +import org.gradle.plugins.ide.idea.GenerateIdeaModule +import org.gradle.plugins.ide.idea.IdeaPlugin +import org.gradle.plugins.ide.idea.model.IdeaModel +import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs -class ProtocPlugin : Plugin { +open class ProtocPlugin : Plugin { override fun apply(project: Project) { - val protocConfig = - project.extensions.create("protocConfig", ProtocConfigExtension::class.java) + configureIntelliJ(project) - val protocDeps = project.configurations.create("pbAndG") { + val protocConfig = + project.extensions.create("protocPluginConfig", ProtocPluginConfig::class, project) + + val protobufCompiler: Configuration = project.configurations.create("protobufCompiler") { isVisible = false isCanBeConsumed = false isCanBeResolved = true - description = "protoc dependencies" + isTransitive = false defaultDependencies { -// deps += project.dependencies.create("com.google.protobuf:protoc:3.19.0") - add(protocConfig.dependencyProvider()) + add(protocConfig.dependency.get()) } } - val generatorsContainer = - project.objects.domainObjectContainer(ProtocGenerationTask::class.java) - protocConfig.extensions.add("generate", generatorsContainer) - - - project.extensions.add("asd", project.provider { - DefaultNativePlatform.getCurrentOperatingSystem().toFamilyName() - }) - - project.tasks.withType { -// .getDataFiles()?.from(protocDeps) + val protobufLib: Configuration = project.configurations.create("protobufLib") { + isVisible = true + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false } -// project.getPlugins().withType(org.gradle.api.plugins.JavaPlugin::class) { javaPlugin -> -// val sourceSets: SourceSetContainer = -// project.getExtensions().getByType(SourceSetContainer::class.java) -// val main: SourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME) -// main.getJava().setSrcDirs(Arrays.asList("src")) -// } + project.dependencies { + protobufLib("com.google.protobuf:protobuf-javalite:3.19.1") +// implementation("com.google.protobuf:protobuf-javalite:3.19.1") +// implementation("com.google.protobuf:protobuf-kotlin-lite:3.19.1") + } + + /** Download protobuf libs */ + val protoLibsTask = project.tasks.register("protobufLibs") { + group = "protobuf" + description = "Download and extract protobuf libs" + includeEmptyDirs = false + dependsOn(protobufLib) + + val protoLibDir by project.objects.directoryProperty() + .convention(project.layout.buildDirectory.dir("protobuf/libs")) + into(protoLibDir) + + protobufLib + .map { project.zipTree(it) } + .forEach { + logger.lifecycle("protoc lib - $it") + from(it) { + include("**/*.proto") + } + } + } + + // TODO investigate builtBy and sourceDirectorySet? +// project.objects.fileCollection().builtBy() +// val pbSrcSet = project.objects.sourceDirectorySet("protobuf", "protobuf") + + + /** Convert `.proto` files to Kotlin */ + val pbCompileTask = project.tasks.register("protobufCompile") { + group = "protobuf" + dependsOn(protobufCompiler, protoLibsTask) + + standardOutput = System.out + + executable(protobufCompiler.singleFile) + workingDir(temporaryDirFactory) + + val outDir = project.layout.buildDirectory.dir("protobuf/generated-sources") + outputs.dir(outDir) + + val protoLibsDir: Provider = protoLibsTask.map { it.destinationDir } + + val javaOut = workingDir.resolve("java") + val kotlinOut = workingDir.resolve("kotlin") + val protoFile by project.objects.fileProperty() + .convention(project.layout.projectDirectory.file("src/main/proto/FactorioServerLogRecord.proto")) + + val protoFileParent = project.provider { protoFile.asFile.parentFile } + + val isLiteEnabled: Boolean by project.objects.property().convention(true) + + doFirst { + project.delete(workingDir) + + project.mkdir(outDir) + project.mkdir(javaOut) + project.mkdir(kotlinOut) + + val liteOpt: String = when (isLiteEnabled) { + true -> "lite:" + false -> "" + } + + args( + parseSpaceSeparatedArgs( + """ + --proto_path=${protoLibsDir.get()} + --proto_path=${protoFileParent.get()} + --java_out=$liteOpt$javaOut + --kotlin_out=$liteOpt$kotlinOut + $protoFile + """ + ) + ) + } + + doLast { + project.sync { + from(workingDir) + into(outDir) + } + project.delete(workingDir) + } + } + + project.tasks.assemble { dependsOn(pbCompileTask) } } + /** + * IntelliJ requires source dirs are configured first. + * + * https://github.com/google/protobuf-gradle-plugin/blob/master/src/main/groovy/com/google/protobuf/gradle/Utils.groovy#L128 + */ + private fun configureIntelliJ(project: Project) { + + val genSrcDir = project.layout.buildDirectory.dir("protobuf/generated-sources") + val ktGenSrc = genSrcDir.map { it.dir("kotlin") } + val jGenSrc = genSrcDir.map { it.dir("java") } + + project.mkdir(ktGenSrc) + + project.extensions.findByType()?.apply { + project.logger.lifecycle("-------\nadding generated sources $ktGenSrc\n-------") + + project.sourceSets.named("main") { + this.java.srcDir(ktGenSrc) + this.java.srcDir(jGenSrc) + } + +// sourceSets.main.get().kotlin.srcDir(ktGenSrc) + +// sourceSets.main.configure { +// this.kotlin.srcDir(ktGenSrc) +// } + } + + project.plugins.withType { + project.extensions.configure { + this.module.generatedSourceDirs.add(ktGenSrc.get().asFile) + this.module.generatedSourceDirs.add(jGenSrc.get().asFile) + } + } + + project.tasks.withType { + doFirst { + project.mkdir(ktGenSrc) + } + } + } } +abstract class ProtocPluginConfig(private val project: Project) { -abstract class ProtocConfigExtension(private val project: Project) : ExtensionAware { + val protocWorkingDir: DirectoryProperty = + project.objects.directoryProperty() + .convention(project.rootProject.layout.projectDirectory.dir(".gradle/protoc")) val protocVersion: Property = - project.objects.property(String::class).convention("3.9.2") + project.objects.property(String::class).convention("3.19.1") val protocGroup: Property = project.objects.property(String::class).convention("com.google.protobuf") @@ -72,77 +222,73 @@ abstract class ProtocConfigExtension(private val project: Project) : ExtensionAw val protocArtifactExtension: Property = project.objects.property(String::class).convention("exe") - var osFamilyNameProvider: () -> String = { - DefaultNativePlatform.getCurrentOperatingSystem().toFamilyName() - } + val operatingSystemProvider: Property> = + project.objects.property>() + .convention { DefaultNativePlatform.getCurrentOperatingSystem() } - var architectureProviderMapper: (String) -> String = { - it.replace("-", "_") - } + /** + * Should return one of + * + * * `linux` + * * `osx` + * * `windows` + */ + val operatingSystemName: Property = + project.objects + .property() + .convention(operatingSystemProvider.map { it.get().toFamilyName() }) - var architectureProvider: () -> String = { - DefaultNativePlatform.getCurrentArchitecture() - .name - .let(architectureProviderMapper) - } + private val architectureProvider: Provider = + project.provider { DefaultNativePlatform.getCurrentArchitecture() } - var classifierProvider: () -> String = { - "${osFamilyNameProvider()}-${architectureProvider()}" - } + /** + * Should return one of + * + * * `aarch_64` + * * `ppcle_64` + * * `x86_32` + * * `x86_64` + */ + val architectureName: Property = + project.objects + .property() + .convention(architectureProvider.map { it.name.replace("-", "_") }) - var dependencyProvider: () -> ExternalDependency = { - project.dependencies.create( - group = protocGroup.get(), - name = protocArtifactName.get(), - version = protocVersion.get(), - classifier = classifierProvider(), - ext = protocArtifactExtension.get(), - ) - } + private val classifierProvider: Provider = + project.provider { "${operatingSystemName.get()}-${architectureName.get()}" } - val generators = project.objects.domainObjectContainer(ProtocGenerationConfig::class) + /** + * Default: concatenate [osFamilyNameProvider] and [architectureProvider] + * + * Should return one of: + * + * * `linux-aarch_64` + * * `linux-ppcle_64` + * * `linux-x86_64` + * * `osx-x86_32` + * * `osx-x86_64` + * * `windows-x86_32` + */ + val classifier: Property = + project.objects + .property() + .convention(classifierProvider) + private val dependencyProvider: Provider = + project.provider { + project.dependencies.create( + group = protocGroup.get(), + name = protocArtifactName.get(), + version = protocVersion.get(), + classifier = classifierProvider.get(), + ext = protocArtifactExtension.get(), + ) + } + + val dependency: Property = + project.objects + .property() + .convention(dependencyProvider) + } - -abstract class ProtocGenerationConfig - -abstract class ProtocGenerationTask : DefaultTask() { - - @TaskAction - fun generate() { - logger.lifecycle("generating protoc...") - } - -} - - -//class ProtocDownloadExe : DefaultTask() { -// -////@Input -//val protocVersion = "3.9.2" -//val protocArtifactFileExt = "exe" -// -// -// @TaskAction -// fun download() { -// -// val baseUri = project.repositories.mavenCentral().url -// -// val os: OperatingSystem = DefaultNativePlatform.getCurrentOperatingSystem() -// val arch: ArchitectureInternal = DefaultNativePlatform.getCurrentArchitecture() -// -// val artifact = "protoc-$protocVersion-${os.name}-${arch.name}.$protocArtifactFileExt" -// -// ant.invokeMethod( -// "get", mapOf( -// "src" to baseUri.resolve("/com/google/protobuf/protoc/3.9.2/protoc-3.9.2-linux-aarch_64.exe"), -// "dest" to project.layout.buildDirectory.dir("protoc-artifact"), -// "verbose" to true, -// ) -// ) -// -// -// } -// -//} diff --git a/settings.gradle.kts b/settings.gradle.kts index ea5f799..30886cb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,7 +1,7 @@ rootProject.name = "factorio-web-map" -includeBuild("modules/protoc-gradle-plugin") +//includeBuild("modules/protoc-gradle-plugin") include( ":modules:mod",