diff --git a/generator/generator-core/build.gradle.kts b/generator/generator-core/build.gradle.kts index abedfbc..c27833c 100644 --- a/generator/generator-core/build.gradle.kts +++ b/generator/generator-core/build.gradle.kts @@ -57,12 +57,12 @@ tasks { dependencies { // Align versions of all Kotlin components implementation(platform("org.jetbrains.kotlin:kotlin-bom")) - // Use SLF4J api for logging, logger implementation to be provided by lib consumer api(libs.slf4jApi) // Use the Kotlin test library. // testImplementation(libs.bundles.kotlinTest) + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") testImplementation(kotlin("test-junit")) // support logging in tests diff --git a/generator/generator-core/src/integrationTest/kotlin/io/ia/ignition/module/generator/IntegrationTests.kt b/generator/generator-core/src/integrationTest/kotlin/io/ia/ignition/module/generator/IntegrationTests.kt index da66150..7362fd1 100644 --- a/generator/generator-core/src/integrationTest/kotlin/io/ia/ignition/module/generator/IntegrationTests.kt +++ b/generator/generator-core/src/integrationTest/kotlin/io/ia/ignition/module/generator/IntegrationTests.kt @@ -70,21 +70,28 @@ class IntegrationTests { applyExecPermissions(workingDir.resolve("gradlew")) } val cmd = command(this) - val process = ProcessBuilder(*(cmd.toTypedArray())) - .directory(workingDir.toFile()) - .redirectOutput(ProcessBuilder.Redirect.INHERIT) - .redirectError(ProcessBuilder.Redirect.INHERIT) - .start() + var result: String = "" - val result = process.inputStream.bufferedReader().readText() + ProcessBuilder(*(cmd.toTypedArray())) + .directory(workingDir.toFile()) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectErrorStream(true) + .start().also { process -> + process.inputStream.bufferedReader().run { + while (true) { + readLine()?.let { line -> + result += "$line\n" + } ?: break + } + } + + process.waitFor(60, TimeUnit.SECONDS) + if (process.isAlive) { + result += "TIMEOUT occurred\n" + process.destroy() + } + } - if (!process.waitFor(60, TimeUnit.SECONDS)) { - process.destroy() - throw RuntimeException("execution timed out: $this") - } - if (process.exitValue() != 0) { - throw RuntimeException("execution failed with code ${process.exitValue()}: $this") - } return result } @@ -109,7 +116,7 @@ class IntegrationTests { val projectRootDir: Path = ModuleGenerator.generate(config) - var processOutput = "build".runCommand(projectRootDir) + val processOutput = "build".runCommand(projectRootDir) assertTrue(processOutput.contains("BUILD SUCCESSFUL")) } } @@ -117,13 +124,13 @@ class IntegrationTests { @Test fun `generated kotlin buildscript projects build successfully`() { listOf( - TestConfig("The Greatness", "le.examp", "G", dir("v1")), - TestConfig("almost Greatness", "le.examp.odd", "GC", dir("v2")), - TestConfig("The greatness", "le.examp.whoa", "GCD", dir("v3")), - TestConfig("oncegreatness", "buenos.dias.amigo", "GCD", dir("v4")), - TestConfig("The Greatness", "le.pant", "CD", dir("v5")), - TestConfig("A Goodness", "come.va", "C", dir("v6")), - TestConfig("The number 1 Greatness", "bon.gior.nio", "D", dir("v7")) + TestConfig("The Greatness", "le.examp", "G", dir("v1_kts")), + TestConfig("almost Greatness", "le.examp.odd", "GC", dir("v2_kts")), + TestConfig("The greatness", "le.examp.whoa", "GCD", dir("v3_kts")), + TestConfig("oncegreatness", "buenos.dias.amigo", "GCD", dir("v4_kts")), + TestConfig("The Greatness", "le.pant", "CD", dir("v5_kts")), + TestConfig("A Goodness", "come.va", "C", dir("v6_kts")), + TestConfig("The number 1 Greatness", "bon.gior.nio", "D", dir("v7_kts")) ).forEach { val config = GeneratorConfigBuilder() .moduleName(it.moduleName) @@ -136,6 +143,7 @@ class IntegrationTests { val projectRootDir: Path = ModuleGenerator.generate(config) val processOutput = "build".runCommand(projectRootDir) + println("OUTPUT:\n$processOutput") assertTrue(processOutput.contains("BUILD SUCCESSFUL")) } } diff --git a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/DefaultDependencies.kt b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/DefaultDependencies.kt index 1bdec04..e30d65f 100644 --- a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/DefaultDependencies.kt +++ b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/DefaultDependencies.kt @@ -1,5 +1,7 @@ package io.ia.ignition.module.generator.api +import io.ia.ignition.module.generator.api.TemplateMarker.SDK_VERSION_PLACEHOLDER + object DefaultDependencies { // default gradle version @@ -8,8 +10,6 @@ object DefaultDependencies { // default plugin configuration for the root build.gradle val MODL_PLUGIN: String = "id(\"io.ia.sdk.modl\") version(\"${TemplateMarker.MODL_PLUGIN_VERSION.key}\")" - const val SDK_VERSION_PLACEHOLDER = "" - // example // "com.inductiveautomation.ignitionsdk:client-api:${'$'}{sdk_version}" val ARTIFACTS: Map> = mapOf( @@ -37,7 +37,7 @@ object DefaultDependencies { ): String { return map { artifact -> val version = dsl.artifactSdkVersion() - "$configuration(\"${artifact.replace(SDK_VERSION_PLACEHOLDER, version)}\")" + "$configuration(\"${artifact.replace(SDK_VERSION_PLACEHOLDER.toString(), version)}\")" }.joinToString(separator = "\n ") } } diff --git a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/ProjectScope.kt b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/ProjectScope.kt index e054f7d..1cd57e1 100644 --- a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/ProjectScope.kt +++ b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/ProjectScope.kt @@ -31,7 +31,7 @@ enum class ProjectScope(val folderName: String) { /** * Returns a list of valid ProjectScope elements according the the string. Lower case letters treated as - * upper case, and invalid scope characters in the String are ignored. Common scope *is* represented in + * upper case, and invalid scope characters in the String are ignored. Common scope *is* represented in * the resulting list if the list includes more than one scope value.. Use [scopesFromShorthand] if needing * the exact project scopes given a shorthand string. */ diff --git a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/TemplateMarker.kt b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/TemplateMarker.kt index cf34060..655bb64 100644 --- a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/TemplateMarker.kt +++ b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/api/TemplateMarker.kt @@ -1,5 +1,10 @@ package io.ia.ignition.module.generator.api +import io.ia.ignition.module.generator.api.ProjectScope.CLIENT +import io.ia.ignition.module.generator.api.ProjectScope.COMMON +import io.ia.ignition.module.generator.api.ProjectScope.DESIGNER +import io.ia.ignition.module.generator.api.ProjectScope.GATEWAY + /** * Markers used in the various template files that are string replaced during assembly in order to create the * appropriately named project elements. @@ -86,15 +91,31 @@ enum class TemplateMarker(val key: String) { */ DESIGNER_DEPENDENCIES("//"), - DEPENDENCIES("//"), - JAVA_TOOLING_CONFIG("//"), SKIP_SIGNING_CONFIG("//"), - MODL_PLUGIN_VERSION(""); + MODL_PLUGIN_VERSION(""), + + SDK_VERSION_PLACEHOLDER(""); fun keys(): List { return values().map { it.key } } + + override fun toString(): String { + return key + } + + companion object { + fun dependencyKeyForScope(scope: ProjectScope): TemplateMarker? { + return when (scope) { + CLIENT -> TemplateMarker.CLIENT_DEPENDENCIES + DESIGNER -> TemplateMarker.DESIGNER_DEPENDENCIES + GATEWAY -> TemplateMarker.GATEWAY_DEPENDENCIES + COMMON -> TemplateMarker.COMMON_DEPENDENCIES + else -> null + } + } + } } diff --git a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/data/ModuleGeneratorContext.kt b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/data/ModuleGeneratorContext.kt index 5a80583..63490a9 100644 --- a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/data/ModuleGeneratorContext.kt +++ b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/data/ModuleGeneratorContext.kt @@ -14,10 +14,6 @@ import io.ia.ignition.module.generator.api.ProjectScope.GATEWAY import io.ia.ignition.module.generator.api.SourceFileType.JAVA import io.ia.ignition.module.generator.api.SourceFileType.KOTLIN import io.ia.ignition.module.generator.api.TemplateMarker -import io.ia.ignition.module.generator.api.TemplateMarker.CLIENT_DEPENDENCIES -import io.ia.ignition.module.generator.api.TemplateMarker.COMMON_DEPENDENCIES -import io.ia.ignition.module.generator.api.TemplateMarker.DESIGNER_DEPENDENCIES -import io.ia.ignition.module.generator.api.TemplateMarker.GATEWAY_DEPENDENCIES import io.ia.ignition.module.generator.api.TemplateMarker.HOOK_CLASS_CONFIG import io.ia.ignition.module.generator.api.TemplateMarker.MODULE_CLASSNAME import io.ia.ignition.module.generator.api.TemplateMarker.MODULE_FILENAME @@ -75,20 +71,7 @@ class ModuleGeneratorContext(override val config: GeneratorConfig) : GeneratorCo settingsHeaderReplacement() rootPluginReplacement() // populate the dependency replacements - scopes.forEach { - @Suppress("UNUSED_EXPRESSION") - when (it) { - CLIENT -> replacements[CLIENT_DEPENDENCIES.key] = - DefaultDependencies.ARTIFACTS[CLIENT]?.toDependencyFormat(config.buildDsl) ?: "" - DESIGNER -> replacements[DESIGNER_DEPENDENCIES.key] = - DefaultDependencies.ARTIFACTS[DESIGNER]?.toDependencyFormat(config.buildDsl) ?: "" - GATEWAY -> replacements[GATEWAY_DEPENDENCIES.key] = - DefaultDependencies.ARTIFACTS[GATEWAY]?.toDependencyFormat(config.buildDsl) ?: "" - COMMON -> replacements[COMMON_DEPENDENCIES.key] = - DefaultDependencies.ARTIFACTS[COMMON]?.toDependencyFormat(config.buildDsl) ?: "" - else -> "" - } - } + replacements.putAll(buildDependencyEntries(effectiveScopes)) // this is a quick hack to support arbitrary replacements for resource files. Works for now as all formal // template replacements are enclosed in < > characters, making collisions unlikely. @@ -97,6 +80,20 @@ class ModuleGeneratorContext(override val config: GeneratorConfig) : GeneratorCo } } + private fun buildDependencyEntries(scopes: List): Map { + return mutableMapOf().apply { + scopes.forEach { scope -> + TemplateMarker.dependencyKeyForScope(scope)?.let { tm -> + this[tm.key] = DefaultDependencies.ARTIFACTS[scope]?.toDependencyFormat(config.buildDsl) ?: "" + // if not a common scope and there is a common project, add it as a dependency to other scopes + if (scope != COMMON && scopes.size > 1) { + this[tm.key] = "${this[tm.key]}\n compileOnly(project(\":common\"))" + } + } + } + } + } + /** * Establishes the pluginManagement, so that the plugin can resolve the module signer lib from nexus */ diff --git a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/util/generatorUtils.kt b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/util/generatorUtils.kt index 0498007..b4220e1 100644 --- a/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/util/generatorUtils.kt +++ b/generator/generator-core/src/main/kotlin/io/ia/ignition/module/generator/util/generatorUtils.kt @@ -20,8 +20,8 @@ data class SubProjectSettings( val buildscriptLanguage: GradleDsl, val projectLanguage: SourceFileType, val scope: ProjectScope, - val dependencies: String = "" -) // optional dependencies injected into build file + val dependencies: String = "" // optional dependencies injected into build file +) fun buildSubProjectSettings(context: GeneratorContext, scope: ProjectScope): SubProjectSettings { val moduleRootDir = context.getRootDirectory()