From 0f6677e0b13d71e9122751e766ca11ad65ad440d Mon Sep 17 00:00:00 2001 From: Adam <897017+asemy@users.noreply.github.com> Date: Sun, 31 Oct 2021 08:52:40 +0100 Subject: [PATCH] standalone pb plugin working! --- .../archetype/kotlin-jvm.gradle.kts | 1 + .../dev/adamko/gradle/pbandg/Constants.kt | 20 + .../pbandg/ProtobufCompilerDependency.kt | 22 ++ .../gradle/pbandg/pattern/IntelliJPattern.kt | 48 +++ .../pattern/KotlinProjectConfiguration.kt | 39 ++ .../pbandg/pattern/ProtocPrepareTask.kt | 65 ++++ .../adamko/gradle/pbandg/pb-and-g.gradle.kts | 86 +++++ .../gradle/pbandg/settings/PBAndGSettings.kt | 103 +++++ .../gradle/pbandg/task/ProtobufCompileTask.kt | 153 ++++++++ .../task/ProtobufPrepareLibrariesTask.kt | 39 ++ .../pbandg/task/options/ProtocOutput.kt | 33 ++ .../build.gradle.kts | 357 +----------------- 12 files changed, 613 insertions(+), 353 deletions(-) create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/Constants.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/ProtobufCompilerDependency.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/IntelliJPattern.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/KotlinProjectConfiguration.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/ProtocPrepareTask.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pb-and-g.gradle.kts create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/settings/PBAndGSettings.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufCompileTask.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufPrepareLibrariesTask.kt create mode 100644 buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/options/ProtocOutput.kt diff --git a/buildSrc/src/main/kotlin/dev/adamko/factoriowebmap/archetype/kotlin-jvm.gradle.kts b/buildSrc/src/main/kotlin/dev/adamko/factoriowebmap/archetype/kotlin-jvm.gradle.kts index 7e3553c..f96fb0c 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/factoriowebmap/archetype/kotlin-jvm.gradle.kts +++ b/buildSrc/src/main/kotlin/dev/adamko/factoriowebmap/archetype/kotlin-jvm.gradle.kts @@ -37,6 +37,7 @@ dependencies { testImplementation("io.kotest:kotest-property-jvm:$kotestVersion") testImplementation("io.kotest:kotest-assertions-json:$kotestVersion") testImplementation("io.mockk:mockk:1.12.0") + // } diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/Constants.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/Constants.kt new file mode 100644 index 0000000..95d8bbc --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/Constants.kt @@ -0,0 +1,20 @@ +package dev.adamko.gradle.pbandg + +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.file.ProjectLayout +import org.gradle.api.provider.Provider + +object Constants { + const val PBG_SETTINGS_NAME = "pbAndG" + const val PBG_TASK_GROUP = PBG_SETTINGS_NAME// "pb-and-g" + const val PBG_LIBS_CONF_NAME = "protobufLibrary" + const val PBG_TASK_COMPILE = "protobufCompile" + + val Project.pbAndGBuildDir: Provider + get() = layout.pbAndGBuildDir + + val ProjectLayout.pbAndGBuildDir: Provider + get() = buildDirectory.dir(PBG_TASK_GROUP) + +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/ProtobufCompilerDependency.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/ProtobufCompilerDependency.kt new file mode 100644 index 0000000..fb0edbb --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/ProtobufCompilerDependency.kt @@ -0,0 +1,22 @@ +package dev.adamko.gradle.pbandg + +import dev.adamko.gradle.pbandg.settings.PBAndGSettings +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration + + +class ProtobufCompilerDependency( + project: Project, + pluginSettings: PBAndGSettings, + private val conf: Configuration = project.configurations.create("protobufCompiler") { + this.description = "Define a single dependency that provides the protoc.exe for this system" + isVisible = false + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false + + defaultDependencies { + add(pluginSettings.dependency.get()) + } + } +) : Configuration by conf diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/IntelliJPattern.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/IntelliJPattern.kt new file mode 100644 index 0000000..1624641 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/IntelliJPattern.kt @@ -0,0 +1,48 @@ +package dev.adamko.gradle.pbandg.pattern + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.hasPlugin +import org.gradle.kotlin.dsl.withType +import org.gradle.plugins.ide.idea.GenerateIdeaModule +import org.gradle.plugins.ide.idea.IdeaPlugin +import org.gradle.plugins.ide.idea.model.IdeaModel + +/** + * 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 + */ +class IntelliJPattern : Plugin { + + fun isIdeaPluginPresent(project: Project) = project.plugins.hasPlugin(IdeaPlugin::class) + + override fun apply(project: Project) { + + if (!isIdeaPluginPresent(project)) { + return + } + + 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.mkdir(jGenSrc) + + 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) + } + } + + } +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/KotlinProjectConfiguration.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/KotlinProjectConfiguration.kt new file mode 100644 index 0000000..f30af8c --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/KotlinProjectConfiguration.kt @@ -0,0 +1,39 @@ +package dev.adamko.gradle.pbandg.pattern + +import dev.adamko.gradle.pbandg.task.ProtobufCompileTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.SourceSet +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.findByType +import org.gradle.kotlin.dsl.getByName +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension + +class KotlinProjectConfiguration : Plugin { + + override fun apply(project: Project) { + addSourceSets(project) + + } + + private fun addSourceSets(project: Project) { + + project.extensions.findByType()?.apply { + + val srcSet = project.extensions.getByName(SourceSet.MAIN_SOURCE_SET_NAME) + + project.tasks + .withType() + .map { it.generatedSources.get() } + .forEach { generatedSourcesDir -> + project.logger.lifecycle("-------\nadding generated sources $generatedSourcesDir\n-------") + + srcSet.java { + srcDir(generatedSourcesDir.dir("java")) + srcDir(generatedSourcesDir.dir("kotlin")) + } + } + } + } +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/ProtocPrepareTask.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/ProtocPrepareTask.kt new file mode 100644 index 0000000..63b7c9e --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pattern/ProtocPrepareTask.kt @@ -0,0 +1,65 @@ +package dev.adamko.gradle.pbandg.pattern + + +import dev.adamko.gradle.pbandg.settings.PBAndGSettings +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.getByType + + +abstract class ProtocPrepareTask : DefaultTask() { + + @Internal + val protocPluginConfig: Provider = project.provider { + project.extensions.getByType() + } + + @get:OutputDirectory + val outputDirectory: DirectoryProperty = project.objects.directoryProperty() + .convention(protocPluginConfig.flatMap { it.protocWorkingDir }) + + @Internal + val protocOutput: RegularFileProperty = project.objects.fileProperty() + + @Internal + val protocDependency: Provider = + protocPluginConfig.flatMap { it.dependency } + + init { + super.setGroup("protobuf") + outputs.dir(outputDirectory) + } + + @TaskAction + fun action() { + + val protocDep: Configuration = project.configurations.create("protoc") { + isVisible = false + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false + + defaultDependencies { + add(protocDependency.get()) + } + } + + logger.lifecycle("Downloading protoc") + val resolvedProtocDep = protocDep.singleFile + logger.lifecycle("Downloaded $resolvedProtocDep") + + project.sync { + from(resolvedProtocDep) + into(outputDirectory) + logger.lifecycle("Syncing from $resolvedProtocDep to ${outputDirectory.asFile.get().canonicalPath}") + protocOutput.set(outputDirectory.asFileTree.singleFile) + } + } +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pb-and-g.gradle.kts b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pb-and-g.gradle.kts new file mode 100644 index 0000000..bfb6635 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/pb-and-g.gradle.kts @@ -0,0 +1,86 @@ +package dev.adamko.gradle.pbandg + +import dev.adamko.gradle.pbandg.settings.PBAndGSettings +import dev.adamko.gradle.pbandg.task.ProtobufCompileTask +import dev.adamko.gradle.pbandg.task.ProtobufPrepareLibrariesTask +import dev.adamko.gradle.pbandg.task.options.ProtocOutput.JavaOutput +import dev.adamko.gradle.pbandg.task.options.ProtocOutput.KotlinOutput + +//plugins { +// `kotlin-dsl` +//} + +plugins { + base +} + + +// TODO investigate builtBy and sourceDirectorySet? +// project.objects.fileCollection().builtBy() +// val pbSrcSet = project.objects.sourceDirectorySet("protobuf", "protobuf") + +//if (plugins.hasPlugin(IdeaPlugin::class)) { +// apply(IntelliJPattern()) +//} +//if (plugins.hasPlugin("org.jetbrains.kotlin.jvm")) { +// apply(KotlinProjectConfiguration()) +//} + +val pbAndGSettings = + project.extensions.create(Constants.PBG_SETTINGS_NAME, PBAndGSettings::class, project) + +//val protocDep = ProtobufCompilerDependency(project, pbAndGSettings) +val protocDep = project.configurations.create("protobufCompiler") { + this.description = "Define a single dependency that provides the protoc.exe for this system" + isVisible = false + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false + + defaultDependencies { + add(pbAndGSettings.dependency.get()) + } +} + +val protobufLibraryDependencies: Configuration = + project.configurations.create(Constants.PBG_LIBS_CONF_NAME) { + isVisible = true + isCanBeConsumed = false + isCanBeResolved = true + isTransitive = false + } + + +project.dependencies { + protobufLibraryDependencies("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") +} + +val protobufPrepareLibrariesTask = + project.tasks.register("protobufPrepareLibraries") { + librarySources.set(protobufLibraryDependencies) + } + +//project.dependencies { +// protobufLibraryDependencies("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") +//} + + +/** Convert `.proto` files to Kotlin */ +val pbCompileTask = project.tasks.register(Constants.PBG_TASK_COMPILE) { + dependsOn(protocDep, protobufPrepareLibrariesTask) + + protobufLibraryDirectories.add(protobufPrepareLibrariesTask.flatMap { it.librariesDirectory }) + + protocOutputs += KotlinOutput() + protocOutputs += JavaOutput() + + val exe = protocDep.singleFile + logger.lifecycle("protoc.exe: $exe") + protocExecutable.set(exe) +} + +project.tasks.assemble { dependsOn(pbCompileTask) } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/settings/PBAndGSettings.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/settings/PBAndGSettings.kt new file mode 100644 index 0000000..0023061 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/settings/PBAndGSettings.kt @@ -0,0 +1,103 @@ +package dev.adamko.gradle.pbandg.settings + + +import java.util.function.Supplier +import org.gradle.api.Project +import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.property +import org.gradle.nativeplatform.platform.Architecture +import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform +import org.gradle.nativeplatform.platform.internal.DefaultOperatingSystem + +abstract class PBAndGSettings(private val project: Project) { + + val protocWorkingDir: DirectoryProperty = + project.objects.directoryProperty() + .convention(project.rootProject.layout.projectDirectory.dir(".gradle/protoc")) + + val protocVersion: Property = + project.objects.property(String::class).convention("3.19.1") + + val protocGroup: Property = + project.objects.property(String::class).convention("com.google.protobuf") + + val protocArtifactName: Property = + project.objects.property(String::class).convention("protoc") + + val protocArtifactExtension: Property = + project.objects.property(String::class).convention("exe") + + val operatingSystemProvider: Property> = + project.objects.property>() + .convention { DefaultNativePlatform.getCurrentOperatingSystem() } + + /** + * Should return one of + * + * * `linux` + * * `osx` + * * `windows` + */ + val operatingSystemName: Property = + project.objects + .property() + .convention(operatingSystemProvider.map { it.get().toFamilyName() }) + + private val architectureProvider: Provider = + project.provider { DefaultNativePlatform.getCurrentArchitecture() } + + /** + * Should return one of + * + * * `aarch_64` + * * `ppcle_64` + * * `x86_32` + * * `x86_64` + */ + val architectureName: Property = + project.objects + .property() + .convention(architectureProvider.map { it.name.replace("-", "_") }) + + private val classifierProvider: Provider = + project.provider { "${operatingSystemName.get()}-${architectureName.get()}" } + + /** + * Default: concatenate [operatingSystemName] and [architectureName] + * + * 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) + +} diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufCompileTask.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufCompileTask.kt new file mode 100644 index 0000000..5ff5ef4 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufCompileTask.kt @@ -0,0 +1,153 @@ +package dev.adamko.gradle.pbandg.task + +import dev.adamko.gradle.pbandg.Constants +import dev.adamko.gradle.pbandg.Constants.pbAndGBuildDir +import dev.adamko.gradle.pbandg.task.options.ProtocOutput +import org.gradle.api.DefaultTask +import org.gradle.api.DomainObjectSet +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property + +abstract class ProtobufCompileTask : DefaultTask() { + + @get:InputFile + abstract val protocExecutable: RegularFileProperty + + @get:OutputDirectory + val generatedSources: DirectoryProperty = project.objects.directoryProperty() + .convention(project.pbAndGBuildDir.map { it.dir("generated-sources") }) + + @get:InputFiles + abstract val protobufLibraryDirectories: ListProperty + + @get:Input + abstract val protocOutputs: DomainObjectSet +// = project.objects.domainObjectSet(ProtocOutput::class.java) + + @get:InputFile + abstract val protoFile: RegularFileProperty + + @get:Input + val cliParamProtoPath: Property = + project.objects.property().convention("--proto_path=") + + init { + group = Constants.PBG_TASK_GROUP + } + + @TaskAction + fun compile() { + + val workDir = temporaryDir + project.delete(workDir) + + project.exec { + executable(protocExecutable.asFile.get()) + workingDir(workDir) + + // prepare directories + project.mkdir(workingDir) + project.mkdir(generatedSources) + + val mapOutputsToOutputDir = + protocOutputs.associateWith { workingDir.resolve(it.outputDirectoryName) } + mapOutputsToOutputDir.values.forEach { project.mkdir(it) } + + // set args + mapOutputsToOutputDir + .map { (opt, dir) -> + "${opt.cliParam}=${opt.protocOptions}:${dir}" + } + .also { args(it) } + + val protoPath = cliParamProtoPath.get() + val libArgs = protobufLibraryDirectories.get().map { "$protoPath${it.asFile}" } + args(libArgs) + + val targetProtoFile = protoFile.get().asFile + args("$protoPath${targetProtoFile.parentFile}") + args("$targetProtoFile") + } + + // sync compiled files + project.sync { + from(workDir) + into(generatedSources) + includeEmptyDirs = false + } + + // clean up temp-dir + project.delete(workDir) + } + +} + +/* + +{ + 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) + } +} + + */ \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufPrepareLibrariesTask.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufPrepareLibrariesTask.kt new file mode 100644 index 0000000..9f71c27 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/ProtobufPrepareLibrariesTask.kt @@ -0,0 +1,39 @@ +package dev.adamko.gradle.pbandg.task + +import dev.adamko.gradle.pbandg.Constants +import dev.adamko.gradle.pbandg.Constants.pbAndGBuildDir +import org.gradle.api.DefaultTask +import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.property + +/** Download protobuf libs */ +abstract class ProtobufPrepareLibrariesTask : DefaultTask() { + + @get:InputFiles + val librarySources: Property = project.objects.property() + + @OutputDirectory + val librariesDirectory: DirectoryProperty = project.objects.directoryProperty() + .convention(project.pbAndGBuildDir.map { it.dir("libs") }) + + init { + group = Constants.PBG_TASK_GROUP + description = "Download and extract protobuf libs" + } + + @TaskAction + fun doTask() { + project.sync { + includeEmptyDirs = false + from(librarySources.map { conf -> conf.map { project.zipTree(it) } }) + into(librariesDirectory) + include("**/*.proto") + } + } + +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/options/ProtocOutput.kt b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/options/ProtocOutput.kt new file mode 100644 index 0000000..966fab2 --- /dev/null +++ b/buildSrc/src/main/kotlin/dev/adamko/gradle/pbandg/task/options/ProtocOutput.kt @@ -0,0 +1,33 @@ +package dev.adamko.gradle.pbandg.task.options + +import dev.adamko.gradle.pbandg.Constants.pbAndGBuildDir +import java.io.Serializable +import org.gradle.api.file.Directory +import org.gradle.api.file.ProjectLayout +import org.gradle.api.provider.Provider + + +interface ProtocOutput : Serializable { + val cliParam: String + val protocOptions: String + val outputDirectoryName: String + + fun outputDirectory(layout: ProjectLayout): Provider { + return layout.pbAndGBuildDir.map { it.dir(outputDirectoryName) } + } + + data class KotlinOutput( + override val protocOptions: String = "lite", + override val outputDirectoryName: String = "kotlin", + ) : ProtocOutput { + override val cliParam: String = "--kotlin_out" + } + + data class JavaOutput( + override val protocOptions: String = "lite", + override val outputDirectoryName: String = "java", + ) : ProtocOutput { + override val cliParam: String = "--java_out" + } + +} \ No newline at end of file diff --git a/modules/factorio-events-data-model/build.gradle.kts b/modules/factorio-events-data-model/build.gradle.kts index b82d1a5..3dba8ca 100644 --- a/modules/factorio-events-data-model/build.gradle.kts +++ b/modules/factorio-events-data-model/build.gradle.kts @@ -1,21 +1,6 @@ -import java.util.function.Supplier -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.provider.Property -import org.gradle.api.tasks.TaskAction -import org.gradle.kotlin.dsl.provideDelegate -import org.gradle.kotlin.dsl.configure -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.property -import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform -import org.gradle.nativeplatform.platform.internal.DefaultOperatingSystem -import org.gradle.plugins.ide.idea.model.IdeaModel -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension -import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs - plugins { id("dev.adamko.factoriowebmap.archetype.kotlin-jvm") + id("dev.adamko.gradle.pbandg.pb-and-g") `kotlin-dsl` } @@ -24,343 +9,9 @@ val buildDir: Directory = layout.buildDirectory.dir(projectId).get() dependencies { + protobufLibrary("com.google.protobuf:protobuf-javalite:3.19.1") } - -open class ProtocPlugin : Plugin { - - override fun apply(project: Project) { - - configureIntelliJ(project) - - val protocConfig = - project.extensions.create("protocPluginConfig", ProtocPluginConfig::class, project) - - val protobufCompiler: Configuration = project.configurations.create("protobufCompiler") { - isVisible = false - isCanBeConsumed = false - isCanBeResolved = true - isTransitive = false - - defaultDependencies { - add(protocConfig.dependency.get()) - } - } - - val protobufLib: Configuration = project.configurations.create("protobufLib") { - isVisible = true - isCanBeConsumed = false - isCanBeResolved = true - isTransitive = false - } - - 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) } - - } - - /** Setup source dirs */ - 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) - } - } - - - /** - * 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 - */ - project.tasks.withType { - doFirst { - project.mkdir(ktGenSrc) - } - } - } +tasks.protobufCompile { + protoFile.set(layout.projectDirectory.file("src/main/proto/FactorioServerLogRecord.proto")) } - -abstract class ProtocPluginConfig(private val project: Project) { - - val protocWorkingDir: DirectoryProperty = - project.objects.directoryProperty() - .convention(project.rootProject.layout.projectDirectory.dir(".gradle/protoc")) - - val protocVersion: Property = - project.objects.property(String::class).convention("3.19.1") - - val protocGroup: Property = - project.objects.property(String::class).convention("com.google.protobuf") - - val protocArtifactName: Property = - project.objects.property(String::class).convention("protoc") - - val protocArtifactExtension: Property = - project.objects.property(String::class).convention("exe") - - val operatingSystemProvider: Property> = - project.objects.property>() - .convention { DefaultNativePlatform.getCurrentOperatingSystem() } - - /** - * Should return one of - * - * * `linux` - * * `osx` - * * `windows` - */ - val operatingSystemName: Property = - project.objects - .property() - .convention(operatingSystemProvider.map { it.get().toFamilyName() }) - - private val architectureProvider: Provider = - project.provider { DefaultNativePlatform.getCurrentArchitecture() } - - /** - * Should return one of - * - * * `aarch_64` - * * `ppcle_64` - * * `x86_32` - * * `x86_64` - */ - val architectureName: Property = - project.objects - .property() - .convention(architectureProvider.map { it.name.replace("-", "_") }) - - private val classifierProvider: Provider = - project.provider { "${operatingSystemName.get()}-${architectureName.get()}" } - - /** - * 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 ProtocPrepareTask : DefaultTask() { - - @Internal - val protocPluginConfig: Provider = project.provider { - project.extensions.getByType() - } - - @get:OutputDirectory - val outputDirectory: DirectoryProperty = project.objects.directoryProperty() - .convention(protocPluginConfig.flatMap { it.protocWorkingDir }) - - @Internal - val protocOutput: RegularFileProperty = project.objects.fileProperty() - - @Internal - val protocDependency: Provider = - protocPluginConfig.flatMap { it.dependency } - - init { - super.setGroup("protobuf") - outputs.dir(outputDirectory) - } - - @TaskAction - fun action() { - - val protocDep: Configuration = project.configurations.create("protoc") { - isVisible = false - isCanBeConsumed = false - isCanBeResolved = true - isTransitive = false - - defaultDependencies { - add(protocDependency.get()) - } - } - - logger.lifecycle("Downloading protoc") - val resolvedProtocDep = protocDep.singleFile - logger.lifecycle("Downloaded $resolvedProtocDep") - - project.sync { - from(resolvedProtocDep) - into(outputDirectory) - logger.lifecycle("Syncing from $resolvedProtocDep to ${outputDirectory.asFile.get().canonicalPath}") - protocOutput.set(outputDirectory.asFileTree.singleFile) - } - } -} - -abstract class ProtocGenerationTask : DefaultTask() { - - @TaskAction - fun generate() { - logger.lifecycle("generating protoc...") - } - -} - -apply() - -configure { -} - - -val logSS = tasks.create("logSourceSets") { - group = "protobuf" - - doLast { - sourceSets.forEach { set -> - logger.lifecycle("SourceSet name: ${set.name}") - set.allSource.forEach { src -> - logger.lifecycle("location: ${src.toRelativeString(rootProject.projectDir)}") - } - } - - logger.lifecycle("-------\nIdeaModel generated source dirs: ${project.idea.module.generatedSourceDirs.joinToString()}\n-------") - } -} - -tasks.named("protobufCompile") { finalizedBy(logSS) } -