migrate buildSrc plugins to includedBuild plugins

This commit is contained in:
Adam 2022-09-18 20:49:32 +02:00
parent 805d4c8170
commit f12a505d22
40 changed files with 159 additions and 112 deletions

View file

@ -1,22 +0,0 @@
package dev.adamko.kafkatorio
plugins {
base
idea
}
group = rootProject.group
version = rootProject.version
tasks.withType<WriteProperties>().configureEach {
encoding = Charsets.UTF_8.name()
comment = " Do not edit manually. This file was created with task '$name'"
}
tasks.withType<AbstractArchiveTask>().configureEach {
exclude("**/.secret.*")
}

View file

@ -1,37 +0,0 @@
package dev.adamko.kafkatorio
import io.kvision.gradle.KVisionExtension
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.findByType
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
object Versions {
const val node = "14.19.1"
}
/**
* `kotlin-js` adds a directory in the root-dir for the Yarn lock.
* That's a bit annoying. It's a little neater if it's in the
* gradle dir, next to the version-catalog.
*/
fun Project.relocateKotlinJsStore() {
afterEvaluate {
rootProject.extensions.configure<YarnRootExtension> {
lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store")
}
}
// rootProject.plugins.withType(YarnPlugin::class) {
// rootProject.the<YarnRootExtension>().lockFileDirectory =
// project.rootDir.resolve("gradle/kotlin-js-store")
// }
// KVision tries to be clever too
project.extensions.findByType<KVisionExtension>()?.apply {
enableHiddenKotlinJsStore.set(false)
}
}

View file

@ -1,44 +0,0 @@
package dev.adamko.kafkatorio.gradle
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Bundling
import org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE
import org.gradle.api.attributes.LibraryElements
import org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.model.ObjectFactory
import org.gradle.kotlin.dsl.named
fun Configuration.asProvider() {
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
}
fun Configuration.asConsumer() {
isVisible = false
isCanBeResolved = true
isCanBeConsumed = false
}
fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration =
attributes {
attribute(USAGE_ATTRIBUTE, objects.named("factorio"))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES_AND_RESOURCES))
attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED))
}
fun Configuration.typescriptAttributes(objects: ObjectFactory): Configuration =
attributes {
attribute(USAGE_ATTRIBUTE, objects.named("typescript"))
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.OBJECTS))
attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
}

View file

@ -1,118 +0,0 @@
package dev.adamko.kafkatorio.gradle
import java.io.ByteArrayOutputStream
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.file.FileCopyDetails
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RelativePath
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.provider.Provider
import org.gradle.api.specs.NotSpec
import org.gradle.api.specs.Spec
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.application.CreateStartScripts
import org.gradle.kotlin.dsl.register
import org.gradle.plugins.ide.idea.model.IdeaModule
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
import org.jetbrains.kotlin.gradle.targets.js.yarn.yarn
import org.jetbrains.kotlin.incremental.md5
operator fun <T> Spec<T>.not(): NotSpec<T> = NotSpec(this)
//fun isProcessRunning(process: String, ignoreCase: Boolean = true): Spec<Task> =
// Spec<Task> {
// ByteArrayOutputStream().use { outputStream ->
// project.exec {
// }
// outputStream.toString().contains(process, ignoreCase)
// }
// }
//
/** exclude generated Gradle code, so it doesn't clog up search results */
fun IdeaModule.excludeGeneratedGradleDsl(layout: ProjectLayout) {
excludeDirs.addAll(
layout.files(
"buildSrc/build/generated-sources/kotlin-dsl-accessors",
"buildSrc/build/generated-sources/kotlin-dsl-accessors/kotlin",
"buildSrc/build/generated-sources/kotlin-dsl-accessors/kotlin/gradle",
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders",
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders/kotlin",
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders/kotlin/gradle",
"buildSrc/build/generated-sources/kotlin-dsl-plugins",
"buildSrc/build/generated-sources/kotlin-dsl-plugins/kotlin",
"buildSrc/build/generated-sources/kotlin-dsl-plugins/kotlin/dev",
"buildSrc/build/pluginUnderTestMetadata",
)
)
}
// https://stackoverflow.com/a/70317110/4161471
fun Project.execCapture(spec: ExecSpec.() -> Unit): String {
return ByteArrayOutputStream().use { outputStream ->
exec {
this.spec()
this.standardOutput = outputStream
}
val output = outputStream.toString().trim()
logger.lifecycle(output)
output
}
}
/** https://youtrack.jetbrains.com/issue/KT-50848 */
fun Project.yarn(configure: YarnRootExtension.() -> Unit) = with(yarn, configure)
fun Directory.filesChecksum(): Long = asFileTree
.files
.map { it.readBytes() + it.absolutePath.toByteArray() }
.fold(byteArrayOf()) { acc, bytes -> acc + bytes }
.md5()
/** Drop the first [count] directories from the path */
fun FileCopyDetails.dropDirectories(count: Int): RelativePath =
RelativePath(true, *relativePath.segments.drop(count).toTypedArray())
/** Drop the first directory from the path */
fun FileCopyDetails.dropDirectory(): RelativePath =
dropDirectories(1)
/** https://github.com/gradle/gradle/issues/16543 */
fun Project.taskProvider(taskName: String): Provider<Task> = providers.provider {
taskName
}.flatMap {
tasks.named(it)
}
const val DOCKER_COMPOSE_TASK_GROUP = "docker-compose"
fun Project.registerStartScriptTask(
appName: String,
configureStartScripts: CreateStartScripts.() -> Unit = {},
): TaskProvider<CreateStartScripts> =
tasks.register<CreateStartScripts>("startScript$appName") {
val jarTask = tasks.getByName(JavaPlugin.JAR_TASK_NAME)
val runtimeClasspath = configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
dependsOn(jarTask)
dependsOn(runtimeClasspath)
applicationName = appName
outputDir = layout.buildDirectory.dir("scripts").get().asFile
classpath = jarTask.outputs.files + runtimeClasspath
configureStartScripts()
}

View file

@ -1,62 +0,0 @@
package dev.adamko.kafkatorio.infra
import dev.adamko.kafkatorio.gradle.DOCKER_COMPOSE_TASK_GROUP
import dev.adamko.kafkatorio.task.DockerEnvUpdateTask
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
plugins {
base
id("dev.adamko.kafkatorio.infra.process-runner")
}
val dockerComposeProjectName: String by extra(rootProject.name)
val dockerSrcDir: Directory by extra(layout.projectDirectory.dir("src"))
val dockerUp by tasks.registering(Exec::class) {
group = DOCKER_COMPOSE_TASK_GROUP
dependsOn(tasks.assemble)
logging.captureStandardOutput(LogLevel.LIFECYCLE)
workingDir = dockerSrcDir.asFile
commandLine = parseSpaceSeparatedArgs(""" docker-compose up -d """)
}
val dockerDown by tasks.registering(Exec::class) {
group = DOCKER_COMPOSE_TASK_GROUP
logging.captureStandardOutput(LogLevel.LIFECYCLE)
workingDir = dockerSrcDir.asFile
commandLine = parseSpaceSeparatedArgs(""" docker-compose down """)
}
val dockerRemove by tasks.registering(Exec::class) {
group = DOCKER_COMPOSE_TASK_GROUP
logging.captureStandardOutput(LogLevel.LIFECYCLE)
workingDir = dockerSrcDir.asFile
commandLine = parseSpaceSeparatedArgs(""" docker-compose rm --stop -v -f """)
}
tasks.matching { it.name == "processRun" }.configureEach { dependsOn(dockerUp, dockerEnvUpdate) }
tasks.matching { it.name == "processKill" }.configureEach { dependsOn(dockerDown) }
val dockerEnvUpdate by tasks.registering(DockerEnvUpdateTask::class) {
dotEnvFile.set(dockerSrcDir.file(".env"))
properties(
"COMPOSE_PROJECT_NAME" to dockerComposeProjectName,
"KAFKATORIO_VERSION" to project.version,
)
}
tasks.assemble { dependsOn(dockerEnvUpdate) }

View file

@ -1,22 +0,0 @@
package dev.adamko.kafkatorio.infra
plugins {
id("dev.adamko.kafkatorio.base")
}
val processRunnerTaskGroup: String by extra("processes")
val processRun by tasks.registering(Task::class) {
group = processRunnerTaskGroup
}
val processKill by tasks.registering(Task::class) {
group = processRunnerTaskGroup
}
val processRestart by tasks.registering {
group = processRunnerTaskGroup
dependsOn(processKill)
finalizedBy(processRun)
}

View file

@ -1,70 +0,0 @@
package dev.adamko.kafkatorio.lang
//import dev.adamko.kafkatorio.Versions
import dev.adamko.kafkatorio.relocateKotlinJsStore
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
//import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
//import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
//import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
plugins {
kotlin("js")
id("dev.adamko.kafkatorio.base")
}
//dependencies {
// implementation(
// project.dependencies.platform(
// "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${Versions.kotlinWrappers}"
// )
// )
//}
//val rootPackageJson by rootProject.tasks.getting(RootPackageJsonTask::class)
//fun NpmTask.setNodeModulesPath(path: String): Unit =
// environment.put("NODE_PATH", path)
//
//fun NpmTask.setNodeModulesPath(folder: File): Unit =
// setNodeModulesPath(folder.normalize().absolutePath)
// https://github.com/node-gradle/gradle-node-plugin/issues/150
// https://github.com/lamba92/kotlingram/blob/master/examples/js-bot/build.gradle.kts
//val nodePath: Directory by extra {
// val file = rootPackageJson.rootPackageJson.parentFile.normalize()
// logger.info("Kotlin/JS NODE_PATH: $file")
// project.layout.dir(project.provider { file }).get()
//}
//val nodeModulesDir: Directory by extra {
// val file = nodePath.dir(NpmProject.NODE_MODULES)
// logger.info("Kotlin/JS NODE_MODULES: $file")
// file
//}
relocateKotlinJsStore()
//plugins.withType<NodeJsRootPlugin> {
// configure<NodeJsRootExtension> {
// nodeVersion = "16.0.0"
// }
//}
//afterEvaluate {
// rootProject.extensions.configure<NodeJsRootExtension> {
// // https://github.com/rjaros/kvision/issues/410
// versions.webpackCli.version = "4.10.0"
// versions.webpackDevServer.version = "4.9.2"
// }
//
// rootProject.extensions.configure<YarnRootExtension> {
// resolution("http-proxy-middleware", "^2.0.6")
// }
//}

View file

@ -1,66 +0,0 @@
package dev.adamko.kafkatorio.lang
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("dev.adamko.kafkatorio.base")
kotlin("jvm")
}
val projectKotlinTarget = "1.7"
val projectJvmTarget = "11"
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("io.kotest:kotest-runner-junit5")
testImplementation("io.kotest:kotest-assertions-core")
testImplementation("io.kotest:kotest-property")
testImplementation("io.kotest:kotest-assertions-json")
testImplementation("io.mockk:mockk")
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = projectJvmTarget
apiVersion = projectKotlinTarget
languageVersion = projectKotlinTarget
}
kotlinOptions.freeCompilerArgs += listOf(
// "-Xcontext-receivers",
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlin.ExperimentalStdlibApi",
"-opt-in=kotlin.time.ExperimentalTime",
// "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
// "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
}
tasks.compileTestKotlin {
kotlinOptions.freeCompilerArgs += "-opt-in=io.kotest.common.ExperimentalKotest"
}
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(projectJvmTarget))
}
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
plugins.withType<ApplicationPlugin>().configureEach {
project.extensions.getByType<JavaApplication>().apply {
applicationDefaultJvmArgs += listOf("-Dkotlinx.coroutines.debug")
}
}

View file

@ -1,37 +0,0 @@
package dev.adamko.kafkatorio.lang
import dev.adamko.kafkatorio.relocateKotlinJsStore
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
//import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
plugins {
id("dev.adamko.kafkatorio.base")
// id("dev.adamko.kafkatorio.lang.node")
kotlin("multiplatform")
// id("io.kotest.multiplatform") // disabled because of https://github.com/kotest/kotest/issues/3141
}
relocateKotlinJsStore()
//plugins.withType<NodeJsRootPlugin> {
// configure<NodeJsRootExtension> {
// nodeVersion = "16.0.0"
// }
//}
//
//
//afterEvaluate {
// rootProject.extensions.configure<NodeJsRootExtension> {
// // https://github.com/rjaros/kvision/issues/410
// versions.webpackCli.version = "4.10.0"
// versions.webpackDevServer.version = "4.9.2"
// }
//
// rootProject.extensions.configure<YarnRootExtension> {
// resolution("http-proxy-middleware", "^2.0.6")
// }
//}

View file

@ -1,64 +0,0 @@
package dev.adamko.kafkatorio.lang
import com.github.gradle.node.npm.task.NpmInstallTask
import dev.adamko.kafkatorio.Versions
import dev.adamko.kafkatorio.task.UpdatePackageJson
import kotlinx.serialization.json.put
plugins {
id("com.github.node-gradle.node")
id("dev.adamko.kafkatorio.base")
}
node {
download.set(true)
version.set(Versions.node)
distBaseUrl.set(null as String?) // set by dependencyResolutionManagement
}
val projectVersion: Provider<String> = providers.provider { "${project.version}" }
val updatePackageJson by tasks.registering(UpdatePackageJson::class) {
// group = NodePlugin.NODE_GROUP
// description = "Read the package.json file and update the version and name, based on the project."
inputs.property("projectVersion", projectVersion)
// propertiesToCheck.put("version", projectVersion)
updateExpectedJson {
put("version", projectVersion.get())
}
// check to see if the properties are already up-to-date
// outputs.upToDateWhen(areJsonPropertiesUpToDate(packageJsonFile, propertiesToCheck))
// onlyIf(!areJsonPropertiesUpToDate(packageJsonFile, propertiesToCheck))
// doLast {
// val packageJsonContent = packageJsonFile.get().asFile.readText()
// val packageJson = jsonMapper.parseToJsonElement(packageJsonContent).jsonObject
//
// val newJsonProps = propertiesToCheck.get().mapValues { (_, newVal) -> JsonPrimitive(newVal) }
//
// val packageJsonUpdate = JsonObject(packageJson + newJsonProps)
// val packageJsonContentUpdated =
// jsonMapper
// .encodeToString(packageJsonUpdate)
// .suffixIfNot("\n")
//
// logger.debug(packageJsonContentUpdated)
//
// packageJsonFile.get().asFile.writer().useToRun {
// write(packageJsonContentUpdated)
// }
//
// }
}
tasks.assemble { dependsOn(updatePackageJson) }
tasks.withType<NpmInstallTask>().configureEach {
dependsOn(updatePackageJson)
}

View file

@ -1,81 +0,0 @@
package dev.adamko.kafkatorio.task
import dev.adamko.kafkatorio.gradle.filesChecksum
import javax.inject.Inject
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import org.gradle.process.ExecOperations
import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
@CacheableTask
@Suppress("UnstableApiUsage")
abstract class DockerComposeExec @Inject constructor(
private val executor: ExecOperations,
private val objects: ObjectFactory,
private val providers: ProviderFactory,
) : DefaultTask() {
@get:InputDirectory
@get:SkipWhenEmpty
@get:PathSensitive(PathSensitivity.RELATIVE)
@get:NormalizeLineEndings
abstract val dockerComposeDir: DirectoryProperty
@get:Input
abstract val command: Property<String>
@get:Input
val dockerIsActive: Property<Boolean> = objects.property<Boolean>().convention(
providers.exec {
commandLine = parseSpaceSeparatedArgs("docker info")
isIgnoreExitValue = true
}.result.map {
it.exitValue == 0
}
)
@get:OutputFile
val stateFile: RegularFileProperty = objects.fileProperty().convention {
temporaryDir.resolve("docker-files.md5")
}
init {
group = DOCKER_COMPOSE_GROUP
logging.captureStandardOutput(LogLevel.LIFECYCLE)
super.onlyIf { task ->
require(task is DockerComposeExec)
task.dockerIsActive.getOrElse(false)
}
}
@TaskAction
fun exec() {
executor.exec {
workingDir = dockerComposeDir.asFile.get()
commandLine = parseSpaceSeparatedArgs(command.get())
}
val inputChecksum = dockerComposeDir.get().filesChecksum()
stateFile.get().asFile.writeText("$inputChecksum")
}
companion object {
const val DOCKER_COMPOSE_GROUP: String = "docker-compose"
}
}

View file

@ -1,27 +0,0 @@
package dev.adamko.kafkatorio.task
import dev.adamko.kafkatorio.gradle.DOCKER_COMPOSE_TASK_GROUP
import javax.inject.Inject
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.WriteProperties
@CacheableTask
open class DockerEnvUpdateTask @Inject constructor(
private val objects: ObjectFactory
) : WriteProperties() {
@Internal
val dotEnvFile: RegularFileProperty = objects.fileProperty()
init {
group = DOCKER_COMPOSE_TASK_GROUP
super.setOutputFile(dotEnvFile)
super.getLogging().captureStandardOutput(LogLevel.LIFECYCLE)
}
}

View file

@ -1,37 +0,0 @@
package dev.adamko.kafkatorio.task
import javax.inject.Inject
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault
@DisableCachingByDefault(because = "caching makes regenerating more difficult")
abstract class GenerateTypeScriptTask @Inject constructor(
private val fileOps: FileSystemOperations,
) : JavaExec() {
@get:OutputDirectory
abstract val output: DirectoryProperty
init {
group = "kt2ts"
}
@TaskAction
fun generate() {
fileOps.delete { delete(temporaryDir) }
temporaryDir.mkdirs()
super.exec()
fileOps.sync {
from(temporaryDir)
into(output)
include("**/*.ts")
}
}
}

View file

@ -1,59 +0,0 @@
package dev.adamko.kafkatorio.task
import dev.adamko.kafkatorio.task.UpdatePackageJson.Companion.foldParseToJsonObject
import dev.adamko.kafkatorio.task.UpdatePackageJson.Companion.parseToJsonObject
import kotlinx.serialization.json.JsonObject
import org.gradle.api.Task
import org.gradle.api.internal.specs.ExplainingSpec
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
object JsonPropertiesUpToDateSpec : ExplainingSpec<Task> {
private val logger: Logger = Logging.getLogger(this::class.java)
override fun isSatisfiedBy(element: Task?): Boolean {
val reason = whyUnsatisfied(element)
if (reason != null) {
logger.lifecycle("JsonProperties not up to date:\n$reason")
}
return reason == null
}
// Returns a description explaining why the task is outdated,
// or null if the task is up to date
override fun whyUnsatisfied(task: Task?): String? {
require(task is UpdatePackageJson) { "$task is not a UpdatePackageJson task" }
val current = task.packageJsonFile.asFile.orNull?.parseToJsonObject()
?: return "no package.json file"
val updates = task.expectedJsonUpdates.orNull?.toList()?.foldParseToJsonObject()
?: return "no package.json updates"
val expected = JsonObject(current + updates)
if (current != expected) {
return (current.keys + expected.keys)
.asSequence()
.distinct()
.sorted()
.mapNotNull {
val currentVal = current[it]
val expectedVal = expected[it]
if (currentVal == expectedVal) {
null
} else {
"'$it' - expected:$expectedVal, actual:$currentVal"
}
}.joinToString(separator = "\n\t", prefix = "package.json is not up to date.\n\t")
}
return null
}
}

View file

@ -1,77 +0,0 @@
package dev.adamko.kafkatorio.task
import dev.adamko.kafkatorio.gradle.execCapture
import org.gradle.api.DefaultTask
import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
abstract class KafkaConsumerGroupsTask : DefaultTask() {
@get:Input
val bootstrapServer: String = "localhost:9092"
@get:Input
val kafkaDockerContainerName: String = "kafka"
@get:Internal
protected val bootstrapArg = "--bootstrap-server $bootstrapServer"
abstract class ResetAll : KafkaConsumerGroupsTask() {
@get:Input
@Language("Shell Script")
val resetCommand: String =
"""
/kafka/bin/kafka-consumer-groups.sh --execute --reset-offsets --all-topics --to-earliest $bootstrapArg
""".trimIndent()
@TaskAction
fun reset() {
getAllGroups().forEach { group ->
logger.lifecycle("Resetting group $group\n---")
dockerExec("$resetCommand --group $group")
logger.lifecycle("---")
}
}
}
abstract class DeleteAll : KafkaConsumerGroupsTask() {
@get:Input
@Language("Shell Script")
val deleteCommand: String =
"""
/kafka/bin/kafka-consumer-groups.sh --delete $bootstrapArg
""".trimIndent()
@TaskAction
fun reset() {
val groups = getAllGroups().joinToString(" ") { group -> "--group $group" }
dockerExec("$deleteCommand $groups")
}
}
@Internal
protected fun getAllGroups(): List<String> = dockerExec(
"""
/kafka/bin/kafka-consumer-groups.sh --list $bootstrapArg
""".trimIndent()
).lines()
.filter { it.trim().isNotBlank() }
// fun reset(applicationId: String) = """
// /kafka/bin/kafka-streams-application-reset.sh --application-id $applicationId --force --to-earliest
// """.trimIndent()
protected fun dockerExec(
@Language("Shell Script")
cmd: String
): String = project.execCapture {
logging.captureStandardOutput(LogLevel.LIFECYCLE)
commandLine = parseSpaceSeparatedArgs(""" docker exec $kafkaDockerContainerName $cmd """)
}
}

View file

@ -1,40 +0,0 @@
package dev.adamko.kafkatorio.task
import java.io.ByteArrayOutputStream
import javax.inject.Inject
import org.gradle.api.Task
import org.gradle.api.internal.specs.ExplainingSpec
import org.gradle.api.tasks.Exec
import org.gradle.process.ExecOperations
/** Checks if a process is running. Windows only. */
class ProcessRunningSpec(
private val executor: ExecOperations,
private val process: String,
private val ignoreCase: Boolean = true,
) : ExplainingSpec<Task> {
override fun isSatisfiedBy(element: Task?): Boolean = whyUnsatisfied(element) == null
override fun whyUnsatisfied(element: Task?): String? {
return when (element) {
null -> "task is null"
!is Exec -> "task ${this::class.simpleName} is not ${Exec::class.simpleName}"
else -> {
return ByteArrayOutputStream().use { outputStream ->
executor.exec {
commandLine("tasklist") // Windows only for now...
standardOutput = outputStream
}
if (outputStream.toString().contains(process, ignoreCase)) {
null
} else {
"found $process in tasklist"
}
}
}
}
}
}

View file

@ -1,58 +0,0 @@
package dev.adamko.kafkatorio.task
import com.github.gradle.node.npm.task.NpmTask
import javax.inject.Inject
import org.gradle.api.file.ConfigurableFileTree
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.IgnoreEmptyDirectories
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.TaskAction
import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
@CacheableTask
abstract class TypescriptToLuaTask @Inject constructor(
private val fs: FileSystemOperations
) : NpmTask() {
@get:InputDirectory
@get:SkipWhenEmpty
@get:PathSensitive(PathSensitivity.RELATIVE)
@get:NormalizeLineEndings
@get:IgnoreEmptyDirectories
abstract val sourceFiles: DirectoryProperty
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
init {
super.setGroup(BasePlugin.BUILD_GROUP)
super.setDescription("Convert Typescript To Lua")
super.execOverrides { standardOutput = System.out }
super.npmCommand.set(listOf("run", "build"))
super.ignoreExitValue.set(false)
super.args.set(parseSpaceSeparatedArgs("-- --outDir $temporaryDir"))
}
@TaskAction
fun tstl() {
fs.delete { delete(temporaryDir) }
temporaryDir.mkdirs()
super.exec()
fs.sync {
from(temporaryDir)
into(outputDirectory)
}
}
}

View file

@ -1,116 +0,0 @@
package dev.adamko.kafkatorio.task
import com.github.gradle.node.NodePlugin
import dev.adamko.kafkatorio.*
import java.io.File
import javax.inject.Inject
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonObjectBuilder
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonObject
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.support.useToRun
import org.jetbrains.kotlin.util.suffixIfNot
@CacheableTask
abstract class UpdatePackageJson @Inject constructor(
private val providers: ProviderFactory,
) : DefaultTask(),
ProviderFactory by providers {
/** Cumulative updates - will be combined one by one, then applied to [packageJsonFile] */
@get:Input
internal abstract val expectedJsonUpdates: ListProperty<String>
@get:OutputFile
abstract val packageJsonFile: RegularFileProperty
init {
group = NodePlugin.NPM_GROUP
description = "Update package.json properties"
outputs.upToDateWhen(JsonPropertiesUpToDateSpec)
}
@TaskAction
fun exec() {
val packageJsonFile = packageJsonFile.asFile.get()
val expectedJsonUpdates: List<String> = expectedJsonUpdates.get().toList()
logger.lifecycle("updating package.json ${packageJsonFile.canonicalFile}")
val expectedJson = expectedJsonUpdates.fold(JsonObject(emptyMap())) { acc, update ->
val updateJson = jsonMapper.parseToJsonElement(update).jsonObject
JsonObject(acc + updateJson)
}
val updatedPackageJson = JsonObject(
packageJsonFile.parseToJsonObject() + expectedJson
)
val packageJsonContentFormatted =
jsonMapper
.encodeToString(updatedPackageJson)
// change empty arrays/objects, because `npm install` also formats package.json,
// but slightly differently to kxs.
.replace(": {\n }", ": {}")
.replace(": [\n ]", ": []")
.suffixIfNot("\n")
logger.info(packageJsonContentFormatted)
packageJsonFile.writer().useToRun {
write(packageJsonContentFormatted)
}
}
/** Update [expectedJson] by merging [updateJsonProvider] with the existing value. */
fun updateExpectedJson(
expectedJsonUpdate: JsonObjectBuilder.() -> Unit
) {
val expectedJsonUpdateProvider = provider {
buildJsonObject(expectedJsonUpdate).toString()
}
expectedJsonUpdates.add(expectedJsonUpdateProvider)
}
companion object {
private val jsonMapper = Json {
prettyPrint = true
prettyPrintIndent = " "
}
internal fun File.parseToJsonObject(): JsonObject =
jsonMapper.parseToJsonElement(readText()).jsonObject
internal fun Property<String>.parseToJsonObject(): JsonObject =
jsonMapper.parseToJsonElement(get()).jsonObject
internal fun List<String>.foldParseToJsonObject(): JsonObject =
fold(JsonObject(emptyMap())) { acc, update ->
val updateJson = jsonMapper.parseToJsonElement(update).jsonObject
JsonObject(acc + updateJson)
}
}
}