diff --git a/.github/actions/setup-project/action.yaml b/.github/actions/setup-project/action.yaml index 6eae6c99..15d4458f 100644 --- a/.github/actions/setup-project/action.yaml +++ b/.github/actions/setup-project/action.yaml @@ -4,10 +4,10 @@ description: Setups the gradle and java environment runs: using: "composite" steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17' - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 diff --git a/.github/workflows/build-main.yaml b/.github/workflows/build-main.yaml index 684111ce..1747dea4 100755 --- a/.github/workflows/build-main.yaml +++ b/.github/workflows/build-main.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Project uses: ./.github/actions/setup-project diff --git a/.github/workflows/build-pull-request.yaml b/.github/workflows/build-pull-request.yaml index 8dc7fcb0..8e3cf0a3 100755 --- a/.github/workflows/build-pull-request.yaml +++ b/.github/workflows/build-pull-request.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Run Docker Container of Databroker in detached mode" run: docker run --pull=always --rm --publish 55556:55556/tcp --detach --name databroker ghcr.io/eclipse/kuksa.val/databroker:master --port 55556 --insecure diff --git a/.github/workflows/check-license.yaml b/.github/workflows/check-license.yaml index 1c73a27f..d1016db7 100755 --- a/.github/workflows/check-license.yaml +++ b/.github/workflows/check-license.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # required to grab the history of the PR fetch-depth: 0 diff --git a/.github/workflows/commitlint.yaml b/.github/workflows/commitlint.yaml index ed49d02a..19f916ee 100644 --- a/.github/workflows/commitlint.yaml +++ b/.github/workflows/commitlint.yaml @@ -8,6 +8,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: wagoid/commitlint-github-action@v5 diff --git a/.github/workflows/dash.yaml b/.github/workflows/dash.yaml index 50ab90d2..31e3dfad 100644 --- a/.github/workflows/dash.yaml +++ b/.github/workflows/dash.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Project uses: ./.github/actions/setup-project diff --git a/.github/workflows/deploy-release.yaml b/.github/workflows/deploy-release.yaml index 67b65a0a..bd101611 100644 --- a/.github/workflows/deploy-release.yaml +++ b/.github/workflows/deploy-release.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Project uses: ./.github/actions/setup-project diff --git a/.github/workflows/deploy-snapshot.yaml b/.github/workflows/deploy-snapshot.yaml index cc180e07..89c05d83 100644 --- a/.github/workflows/deploy-snapshot.yaml +++ b/.github/workflows/deploy-snapshot.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Project uses: ./.github/actions/setup-project diff --git a/README.md b/README.md index d3860696..b2a7b4df 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ within an Android App. The main functionality consists of fetching, updating and ## Integration -*build.gradle* +*app/build.gradle.kts* ``` implementation("org.eclipse.kuksa:kuksa-sdk:") ``` diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1889a5b8..13e6a391 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,3 @@ -import org.eclipse.kuksa.property.PropertiesLoader - /* * Copyright (c) 2023 Contributors to the Eclipse Foundation * @@ -19,9 +17,16 @@ import org.eclipse.kuksa.property.PropertiesLoader * */ +@file:Suppress("UnstableApiUsage") + +import org.eclipse.kuksa.property.PropertiesLoader +import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY + plugins { id("com.android.application") id("com.google.devtools.ksp") + id("org.eclipse.kuksa.vss-processor-plugin") // Always take the newest version since it's locally included kotlin("plugin.serialization") kotlin("android") } @@ -55,11 +60,14 @@ android { applicationId = "org.eclipse.kuksa.testapp" minSdk = 27 targetSdk = 34 - versionCode = rootProject.extra["projectVersionCode"].toString().toInt() - versionName = rootProject.extra["projectVersion"].toString() vectorDrawables { useSupportLibrary = true } + + val versionPath = rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] as String + val semanticVersion = SemanticVersion(versionPath) + versionCode = semanticVersion.versionCode + versionName = semanticVersion.versionName } signingConfigs { create("release") { diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt index 1f562550..52b48c0a 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt @@ -60,7 +60,7 @@ import org.eclipse.kuksa.testapp.ui.theme.KuksaAppAndroidTheme import org.eclipse.kuksa.vsscore.annotation.VssDefinition import org.eclipse.kuksa.vsscore.model.VssSpecification -@VssDefinition("vss_rel_4.0.yaml") +@VssDefinition class KuksaDataBrokerActivity : ComponentActivity() { private lateinit var connectionInfoRepository: ConnectionInfoRepository diff --git a/build.gradle.kts b/build.gradle.kts index 7ff5817d..afce8049 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,21 @@ * */ -import org.jetbrains.kotlin.incremental.createDirectory +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_NAME +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY +import java.nio.file.FileVisitResult +import java.nio.file.Path +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.bufferedWriter +import kotlin.io.path.createDirectories +import kotlin.io.path.createFile +import kotlin.io.path.deleteIfExists +import kotlin.io.path.name +import kotlin.io.path.useLines +import kotlin.io.path.visitFileTree + +val versionDefaultPath = "$rootDir/$VERSION_FILE_DEFAULT_NAME" +rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] = versionDefaultPath plugins { base @@ -47,6 +61,7 @@ subprojects { } } +@OptIn(ExperimentalPathApi::class) tasks.register("mergeDashFiles") { group = "oss" @@ -56,26 +71,30 @@ tasks.register("mergeDashFiles") { }, ) + val buildDir = layout.buildDirectory.asFile.get() + val buildDirPath = Path.of(buildDir.path) + doLast { - val sortedLinesSet = sortedSetOf() - files("build/oss").asFileTree.forEach { file -> - if (file.name != "dependencies.txt") return@forEach + val ossDir = buildDirPath.resolve("oss").createDirectories() + val ossAllDir = ossDir.resolve("all").createDirectories() + val ossDependenciesFile = ossAllDir.resolve("all-dependencies.txt") + ossDependenciesFile.deleteIfExists() + ossDependenciesFile.createFile() - file.useLines { - sortedLinesSet.addAll(it) - } - } + val sortedLinesSet = sortedSetOf() + ossDir.visitFileTree { + onVisitFile { file, _ -> + if (file.name != "dependencies.txt") return@onVisitFile FileVisitResult.CONTINUE - val folder = File("$rootDir/build/oss/all") - folder.createDirectory() + file.useLines { + sortedLinesSet.addAll(it) + } - val file = File("$folder/all-dependencies.txt") - if (file.exists()) { - file.delete() + FileVisitResult.CONTINUE + } } - file.createNewFile() - val bufferedWriter = file.bufferedWriter() + val bufferedWriter = ossDependenciesFile.bufferedWriter() bufferedWriter.use { writer -> sortedLinesSet.forEach { line -> writer.write(line + System.lineSeparator()) diff --git a/buildSrc/src/main/kotlin/org/eclipse/kuksa/version/SemanticVersion.kt b/buildSrc/src/main/kotlin/org/eclipse/kuksa/version/SemanticVersion.kt index 6f50845d..c014e299 100644 --- a/buildSrc/src/main/kotlin/org/eclipse/kuksa/version/SemanticVersion.kt +++ b/buildSrc/src/main/kotlin/org/eclipse/kuksa/version/SemanticVersion.kt @@ -18,15 +18,21 @@ package org.eclipse.kuksa.version +import java.io.File import java.util.Locale -class SemanticVersion(semanticVersion: String) { +const val VERSION_FILE_DEFAULT_PATH_KEY = "versionFilePathKey" +const val VERSION_FILE_DEFAULT_NAME = "version.txt" + +class SemanticVersion(versionFilePath: String) { val major: Int val minor: Int val patch: Int var suffix: String = "" - val versionString: String + val versionFile: File + + val versionName: String get() { var version = "$major.$minor.$patch" if (suffix.isNotEmpty()) { @@ -47,6 +53,9 @@ class SemanticVersion(semanticVersion: String) { } init { + versionFile = File(versionFilePath) + + val semanticVersion = versionFile.readText() val versions = semanticVersion.trim() .substringBefore("-") // Ignore suffixes like -SNAPSHOT .split(".") @@ -56,7 +65,5 @@ class SemanticVersion(semanticVersion: String) { minor = versions[1].toInt() patch = versions[2].toInt() this.suffix = suffix - - print("Current SemanticVersion($versionString)\n") } } diff --git a/buildSrc/src/main/kotlin/publish.gradle.kts b/buildSrc/src/main/kotlin/publish.gradle.kts index acf4522d..efb71751 100644 --- a/buildSrc/src/main/kotlin/publish.gradle.kts +++ b/buildSrc/src/main/kotlin/publish.gradle.kts @@ -111,18 +111,12 @@ afterEvaluate { ) sign(publishing.publications) - } -} -gradle.taskGraph.whenReady { - tasks.withType(Sign::class) { - val publishToMavenLocalTask = allTasks.find { it.name.contains("publishToMavenLocal") } - val isPublishingToMavenLocal = publishToMavenLocalTask != null - - if (isPublishingToMavenLocal) { - println(":${project.name}:$name - Signing is disabled (publishToMavenLocal)") - } + setRequired({ + val publishToMavenLocalTask = gradle.taskGraph.allTasks.find { it.name.contains("ToMavenLocal") } + val isPublishingToMavenLocal = publishToMavenLocalTask != null - onlyIf { !isPublishingToMavenLocal } // disable signing when publishing to MavenLocal + !isPublishingToMavenLocal // disable signing when publishing to MavenLocal + }) } } diff --git a/buildSrc/src/main/kotlin/version.gradle.kts b/buildSrc/src/main/kotlin/version.gradle.kts index 81c9398c..8ebceb04 100644 --- a/buildSrc/src/main/kotlin/version.gradle.kts +++ b/buildSrc/src/main/kotlin/version.gradle.kts @@ -18,51 +18,60 @@ */ import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_NAME -val file = File("$rootDir/version.txt") -val fileContent = file.readText() -val semanticVersion = SemanticVersion(fileContent) +private val versionPath = "$rootDir/$VERSION_FILE_DEFAULT_NAME" +private val semanticVersion = SemanticVersion(versionPath) -updateExtras() +/** + * Writes the given [suffix] into the given [inputFileProperty] while keeping the semantic version intact. + * E.g. 1.2.3 -> 1.2.3-SNAPSHOT (suffix = SNAPSHOT). Leave the suffix empty to restore the initial version. + */ +abstract class SetVersionSuffixTask : DefaultTask() { + @get:Input + abstract val suffix: Property + + @get:Incremental + @get:InputFile + abstract val inputFileProperty: RegularFileProperty + + @TaskAction + fun addVersionSuffix() { + val inputFile = inputFileProperty.asFile.get() + + val newSemanticVersion = SemanticVersion(inputFile.path) + newSemanticVersion.suffix = suffix.get() + + println("Applying version suffix: ${suffix.get()}") + + inputFile.writeText(newSemanticVersion.versionName) + } +} // Do not chain this command because it writes into a file which needs to be re-read inside the next gradle command -tasks.register("setReleaseVersion") { +tasks.register("setSnapshotVersion") { group = "version" - doLast { - semanticVersion.suffix = "" - updateVersion() - } + inputFileProperty = semanticVersion.versionFile + suffix = "SNAPSHOT" } // Do not chain this command because it writes into a file which needs to be re-read inside the next gradle command -tasks.register("setSnapshotVersion") { +tasks.register("setReleaseVersion") { group = "version" - doLast { - semanticVersion.suffix = "SNAPSHOT" - updateVersion() - } + inputFileProperty = semanticVersion.versionFile + suffix = "" } tasks.register("printVersion") { group = "version" - doLast { - val version = semanticVersion.versionString - println("VERSION=$version") + val versionFilePath = versionPath + doLast { // Prints the correct version if chained with SetVersionSuffix tasks + val currentSemanticVersion = SemanticVersion(versionFilePath) + println("Current version: ${currentSemanticVersion.versionName}") } mustRunAfter("setReleaseVersion", "setSnapshotVersion") } - -fun updateExtras() { - rootProject.extra["projectVersion"] = semanticVersion.versionString - rootProject.extra["projectVersionCode"] = semanticVersion.versionCode -} - -fun updateVersion() { - updateExtras() - - file.writeText(semanticVersion.versionString) -} diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md index 0082ddb2..9e7bea79 100644 --- a/docs/QUICKSTART.md +++ b/docs/QUICKSTART.md @@ -4,7 +4,7 @@ Get instantly bootstrapped into the world of the KUKSA SDK with the following co ## Integration -*build.gradle* +*app/build.gradle.kts* ``` implementation("org.eclipse.kuksa:kuksa-sdk:") ``` @@ -162,9 +162,20 @@ For a more convenient usage you can opt in to auto generate Kotlin models via [S of the same specification the Databroker uses. For starters you can retrieve an extensive default specification from the release page of the [COVESA Vehicle Signal Specification GitHub repository](https://github.com/COVESA/vehicle_signal_specification/releases). -*build.gradle* +*app/build.gradle.kts* ``` -ksp("org.eclipse.kuksa:vss-processor:") +plugins { + id("org.eclipse.kuksa.vss-processor-plugin") +} + +dependencies { + ksp("org.eclipse.kuksa:vss-processor:") +} + +// Optional - See plugin documentation. Files inside the "$rootDir/vss" folder are used automatically. +vssProcessor { + searchPath = "$rootDir/vss" +} ``` Use the new [`VssDefinition`](https://github.com/eclipse-kuksa/kuksa-android-sdk/blob/main/vss-core/src/main/java/org/eclipse/kuksa/vsscore/annotation/VssDefinition.kt) annotation and provide the path to the specification file (Inside the assets folder). @@ -174,12 +185,12 @@ convenience operators and extension methods to work with to manipulate the tree *Kotlin* ```kotlin -@VssDefinition("vss_rel_4.0.yaml") +@VssDefinition class KotlinActivity ``` *Java* ```java -@VssDefinition(vssDefinitionPath = "vss_rel_4.0.yaml") +@VssDefinition public class JavaActivity ``` > [!IMPORTANT] diff --git a/gradle.properties b/gradle.properties index 2574d3c5..14bfa477 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,3 @@ -android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=false android.nonTransitiveRClass=true android.useAndroidX=true @@ -10,3 +9,4 @@ kotlin.daemon.jvmargs=-Xmx2048m # When using compose + ksp the incremental compiler should be disabled: https://issuetracker.google.com/issues/207185051 ksp.incremental=false +org.gradle.configuration-cache=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 52309d1f..7bc3a432 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,16 +1,17 @@ [versions] -activityKtx = "1.8.0" -androidGradlePlugin = "8.1.3" # Check with detekt table first: https://detekt.dev/docs/introduction/compatibility/ +activityKtx = "1.8.2" +androidGradlePlugin = "8.2.2" # Check with detekt table first: https://detekt.dev/docs/introduction/compatibility/ +detekt = "1.23.5" datastore = "1.0.0" constraintlayoutCompose = "1.0.1" datastorePreferences = "1.0.0" -kotlin = "1.9.0" +dokka = "1.9.10" +kotlin = "1.9.22" kotlinpoet = "1.16.0" -kotlinxSerializationJson = "1.6.0" -runtimeLivedata = "1.5.3" -symbolProcessingApi = "1.9.10-1.0.13" +kotlinxSerializationJson = "1.6.1" +runtimeLivedata = "1.6.0" +symbolProcessingApi = "1.9.22-1.0.17" tomcatAnnotations = "6.0.53" -detekt = "1.23.1" ktlint = "0.0" # Maintained inside ktlint.gradle.kts androidxAppCompat = "1.6.1" grpc = "1.57.2" @@ -18,10 +19,10 @@ protobufGradlePlugin = "0.9.3" protobuf = "3.22.3" kotest = "5.7.2" mockk = "1.13.7" -androidxLifecycle = "2.6.2" +androidxLifecycle = "2.7.0" kotlinxCoroutines = "1.7.3" -kotlinCompilerExtension = "1.5.1" -composeBom = "2023.10.00" +kotlinCompilerExtension = "1.5.9" +composeBom = "2024.01.00" jvmTarget = "17" [libraries] @@ -70,4 +71,5 @@ detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-form grpc-protoc-java-gen = { group = "io.grpc", name = "protoc-gen-grpc-java", version.ref = "grpc" } [plugins] -dokka = { id = "org.jetbrains.dokka", version.ref = "kotlin" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } +pluginPublishing = { id = "com.gradle.plugin-publish", version = "1.2.1" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 84a0b92f..17655d0e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kuksa-sdk/build.gradle.kts b/kuksa-sdk/build.gradle.kts index f10156c0..be14acbb 100644 --- a/kuksa-sdk/build.gradle.kts +++ b/kuksa-sdk/build.gradle.kts @@ -20,6 +20,8 @@ @file:Suppress("UnstableApiUsage") import com.google.protobuf.gradle.id +import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY plugins { id("com.android.library") @@ -28,8 +30,10 @@ plugins { publish } +val versionPath = rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] as String +val semanticVersion = SemanticVersion(versionPath) +version = semanticVersion.versionName group = "org.eclipse.kuksa" -version = rootProject.extra["projectVersion"].toString() android { namespace = "org.eclipse.kuksa" @@ -92,7 +96,7 @@ dependencies { testImplementation(libs.mockk) } -configure { +publish { mavenPublicationName = "release" componentName = "release" description = "Android Connectivity Library for the KUKSA Databroker" diff --git a/samples/build.gradle.kts b/samples/build.gradle.kts index ece184fb..1245e7dc 100644 --- a/samples/build.gradle.kts +++ b/samples/build.gradle.kts @@ -1,3 +1,6 @@ +import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY + /* * Copyright (c) 2023 Contributors to the Eclipse Foundation * @@ -20,6 +23,7 @@ plugins { id("com.android.application") id("com.google.devtools.ksp") + id("org.eclipse.kuksa.vss-processor-plugin") kotlin("android") } @@ -31,8 +35,11 @@ android { applicationId = "org.eclipse.kuksa.samples" minSdk = 27 targetSdk = 34 - versionCode = 1 - versionName = "1.0" + + val versionPath = rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] as String + val semanticVersion = SemanticVersion(versionPath) + versionCode = semanticVersion.versionCode + versionName = semanticVersion.versionName testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -54,6 +61,11 @@ android { } } +vssProcessor { + // Optional - See plugin documentation. Files inside the "$rootDir/vss" folder are used automatically. + searchPath = "$rootDir/vss" +} + dependencies { implementation(project(":kuksa-sdk")) // org.eclipse.kuksa.kuksa-sdk: ksp(project(":vss-processor")) // org.eclipse.kuksa.vss-processor: diff --git a/samples/src/main/java/com/example/sample/JavaActivity.java b/samples/src/main/java/com/example/sample/JavaActivity.java index 48b91028..1ef1dd08 100644 --- a/samples/src/main/java/com/example/sample/JavaActivity.java +++ b/samples/src/main/java/com/example/sample/JavaActivity.java @@ -53,7 +53,7 @@ /** * @noinspection unused */ -//@VssDefinition(vssDefinitionPath = "vss_rel_4.0.yaml") // Commented out to prevent conflicts with the Kotlin activity +//@VssDefinition // Commented out to prevent conflicts with the Kotlin activity public class JavaActivity extends AppCompatActivity { private final DisconnectListener disconnectListener = () -> { diff --git a/samples/src/main/kotlin/com/example/sample/KotlinActivity.kt b/samples/src/main/kotlin/com/example/sample/KotlinActivity.kt index 0d550a22..12536968 100644 --- a/samples/src/main/kotlin/com/example/sample/KotlinActivity.kt +++ b/samples/src/main/kotlin/com/example/sample/KotlinActivity.kt @@ -42,7 +42,7 @@ import org.eclipse.kuksa.vsscore.annotation.VssDefinition import java.io.IOException @Suppress("UNUSED_VARIABLE", "SwallowedException") -@VssDefinition("vss_rel_4.0.yaml") +@VssDefinition class KotlinActivity : AppCompatActivity() { private var disconnectListener = DisconnectListener { diff --git a/settings.gradle.kts b/settings.gradle.kts index 28ff0f32..1ed12efd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,16 +18,19 @@ */ pluginManagement { + includeBuild("vss-processor-plugin") + repositories { gradlePluginPortal() google() mavenCentral() } + // Version catalog can't be used here plugins { - id("com.google.devtools.ksp") version "1.9.0-1.0.11" - kotlin("jvm") version "1.9.0-1.0.11" - kotlin("plugin.serialization") version "1.9.0" + id("com.google.devtools.ksp") version "1.9.22-1.0.17" + kotlin("jvm") + kotlin("plugin.serialization") version "1.9.22" } } @@ -40,6 +43,8 @@ dependencyResolutionManagement { } } +rootProject.name = "kuksa-android-sdk" + include(":app") include(":kuksa-sdk") include(":samples") diff --git a/vss-core/build.gradle.kts b/vss-core/build.gradle.kts index 20cc6bec..cde7e734 100644 --- a/vss-core/build.gradle.kts +++ b/vss-core/build.gradle.kts @@ -19,15 +19,21 @@ @file:Suppress("UnstableApiUsage") +import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY +import org.jetbrains.dokka.gradle.DokkaTask + + plugins { kotlin("jvm") - `maven-publish` publish alias(libs.plugins.dokka) } +val versionPath = rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] as String +val semanticVersion = SemanticVersion(versionPath) +version = semanticVersion.versionName group = "org.eclipse.kuksa" -version = rootProject.extra["projectVersion"].toString() dependencies { implementation(kotlin("stdlib")) @@ -49,7 +55,7 @@ tasks.withType().configureEach { } } -configure { +publish { mavenPublicationName = "release" componentName = "java" description = "Vehicle Signal Specification (VSS) Core Module of the KUKSA SDK" @@ -57,10 +63,16 @@ configure { tasks.register("javadocJar", Jar::class) { dependsOn("dokkaHtml") + + val buildDir = layout.buildDirectory.get() from("$buildDir/dokka/html") archiveClassifier.set("javadoc") } +tasks.withType().configureEach { + notCompatibleWithConfigurationCache("https://github.com/Kotlin/dokka/issues/2231") +} + java { withJavadocJar() // needs to be called after tasks.register("javadocJar") withSourcesJar() diff --git a/vss-core/src/main/java/org/eclipse/kuksa/vsscore/annotation/VssDefinition.kt b/vss-core/src/main/java/org/eclipse/kuksa/vsscore/annotation/VssDefinition.kt index fed48902..1098bb86 100644 --- a/vss-core/src/main/java/org/eclipse/kuksa/vsscore/annotation/VssDefinition.kt +++ b/vss-core/src/main/java/org/eclipse/kuksa/vsscore/annotation/VssDefinition.kt @@ -21,13 +21,28 @@ package org.eclipse.kuksa.vsscore.annotation /** * Add this annotation to any class to trigger the model generation (Kotlin Symbol Processing) for the given - * Vehicle Signal Specification definition file. Only .yaml files are currently supported. The searched root folder - * is the assets folder (example path: app/src/main/assets). + * Vehicle Signal Specification definition file by the "vss-processor-plugin". Only .yaml files are currently supported. + * Use the "VSS Processor Plugin" to provide the Symbol Processor with the necessary definition file(s). * - * ### Example + * ### Plugin Example * * ``` - * @VssDefinition("vss_rel_4.0.yaml") + * // app/build.gradle.kts + * plugins { + * id("org.eclipse.kuksa.vss-processor-plugin") version "" + * } + * + * // Optional - See plugin documentation. Files inside the "$rootDir/vss" folder are used automatically. + * vssProcessor { + * searchPath = "$rootDir/vss" + * } + * ``` + * + * ### Annotation Example + * + * ``` + * @VssDefinition + * class Activity * ``` * * ### Important @@ -36,10 +51,8 @@ package org.eclipse.kuksa.vsscore.annotation * then the incremental compiler for KSP needs to be disabled explicitly in the gradle properties. * ``` * - * - * @param vssDefinitionPath the path to the definition file * ``` */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.SOURCE) -annotation class VssDefinition(val vssDefinitionPath: String) +annotation class VssDefinition diff --git a/vss-processor-plugin/.gitignore b/vss-processor-plugin/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/vss-processor-plugin/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/vss-processor-plugin/build.gradle.kts b/vss-processor-plugin/build.gradle.kts new file mode 100644 index 00000000..f3c9fdff --- /dev/null +++ b/vss-processor-plugin/build.gradle.kts @@ -0,0 +1,169 @@ +import org.eclipse.kuksa.vssprocessor.plugin.version.SemanticVersion +import org.eclipse.kuksa.vssprocessor.plugin.version.VERSION_FILE_DEFAULT_NAME + +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +plugins { + alias(libs.plugins.pluginPublishing) + signing + `kotlin-dsl` +} + +// TODO: This linking to the version file currently throws a warning: +// Caught exception: Already watching path: kuksa-android-sdk/vss-processor-plugin/.. +// +// The reason is that two different root projects (main + composite (this)) are referencing to the same version.txt +// file because data models like SemanticVersion can't be shared. However the same build folder is used for the +// caching so the cache does not know about this. The issue will be ignored as a warning for now. +// +// Similar issue: https://github.com/gradle/gradle/issues/27940 +val versionPath = "$rootDir/../$VERSION_FILE_DEFAULT_NAME" +val semanticVersion = SemanticVersion(versionPath) +version = semanticVersion.versionName +group = "org.eclipse.kuksa" + +gradlePlugin { + website.set("https://github.com/eclipse-kuksa/kuksa-android-sdk") + vcsUrl.set("https://github.com/eclipse-kuksa/kuksa-android-sdk") + plugins { + create("VssProcessorPlugin") { + id = "org.eclipse.kuksa.vss-processor-plugin" + implementationClass = "org.eclipse.kuksa.vssprocessor.plugin.VssProcessorPlugin" + displayName = "VSS Processor Plugin" + tags.set(listOf("KUKSA", "Vehicle Signal Specification", "VSS", "Android", "Kotlin")) + description = "Vehicle Signal Specification (VSS) Plugin of the KUKSA SDK. This is used in combination " + + "with the KSP processor component 'KUKSA VSS Processor'. The plugin is configured to provide " + + "VSS Files to KSP processor. This is mandatory to use the 'KUKSA VSS Processor' component." + } + } +} + +// .set calls need to be done instead of "=" because of a IDEA bug. +// https://youtrack.jetbrains.com/issue/KTIJ-17783/False-positive-Val-cannot-be-reassigned-in-build.gradle.kts +afterEvaluate { + publishing { + repositories { + maven { + name = "OSSRHRelease" + + url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/") + credentials { + username = System.getenv("ORG_OSSRH_USERNAME") + password = System.getenv("ORG_OSSRH_PASSWORD") + } + } + // Snapshot are disabled for Plugins since the plugin marker has issues finding the correct jar with the + // automatic timestamps / build number being added as a postfix to the files. + } + publications { + getByName("pluginMaven") { + pom { + licenses { + license { + name.set("The Apache Software License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + developers { + developer { + name.set("Mark Hüsers") + email.set("mark.huesers@etas.com") + organization.set("ETAS GmbH") + organizationUrl.set("https://www.etas.com") + } + developer { + name.set("Sebastian Schildt") + email.set("sebastian.schildt@etas.com") + organization.set("ETAS GmbH") + organizationUrl.set("https://www.etas.com") + } + developer { + name.set("Andre Weber") + email.set("andre.weber3@etas.com") + organization.set("ETAS GmbH") + organizationUrl.set("https://www.etas.com") + } + } + scm { + connection.set("scm:git:github.com/eclipse-kuksa/kuksa-android-sdk.git") + developerConnection.set("scm:git:ssh://github.com/eclipse-kuksa/kuksa-android-sdk.git") + url.set("https://github.com/eclipse-kuksa/kuksa-android-sdk/tree/main") + } + } + } + } + } + + signing { + var keyId: String? = System.getenv("ORG_GPG_KEY_ID") + if (keyId != null && keyId.length > 8) { + keyId = keyId.takeLast(8) + } + val privateKey = System.getenv("ORG_GPG_PRIVATE_KEY") + val passphrase = System.getenv("ORG_GPG_PASSPHRASE") + + useInMemoryPgpKeys( + keyId, + privateKey, + passphrase, + ) + + sign(publishing.publications) + + setRequired({ + val publishToMavenLocalTask = gradle.taskGraph.allTasks.find { it.name.contains("ToMavenLocal") } + val isPublishingToMavenLocal = publishToMavenLocalTask != null + + !isPublishingToMavenLocal // disable signing when publishing to MavenLocal + }) + } +} + +tasks.withType().configureEach { + useJUnitPlatform() + testLogging.showStandardStreams = true +} + +afterEvaluate { + tasks.find { it.name.contains("generateMetadataFileForPluginMavenPublication") } + ?.notCompatibleWithConfigurationCache( + """ + The "generateMetadataFileForPluginMavenPublication" task is currently not using the configuration cache + correctly which leads to: + + java.io.FileNotFoundException: /build/libs/vss-processor-plugin-0.1.3.jar (No such file or directory) + + Reproduction steps: + ./gradlew :vss-processor-plugin:clean :vss-processor-plugin:generateMetadataFileForPluginMavenPublication + """.trimIndent(), + ) +} + +// IMPORTANT: The currently used dependencies here are already covered by the other modules in this project so dash oss +// scripts do not have to be included here (yet). +// But keep in mind to check the coverage when adding new dependencies. +// TODO: Automated with https://github.com/eclipse-kuksa/kuksa-android-sdk/issues/79 +dependencies { + implementation(kotlin("stdlib")) + + testImplementation(gradleTestKit()) + testImplementation(libs.kotest) + testImplementation(libs.mockk) +} diff --git a/vss-processor-plugin/buildSrc/build.gradle.kts b/vss-processor-plugin/buildSrc/build.gradle.kts new file mode 100644 index 00000000..d0e0e4f5 --- /dev/null +++ b/vss-processor-plugin/buildSrc/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +plugins { + `kotlin-dsl` + `kotlin-dsl-precompiled-script-plugins` +} diff --git a/vss-processor-plugin/buildSrc/settings.gradle.kts b/vss-processor-plugin/buildSrc/settings.gradle.kts new file mode 100644 index 00000000..3c6ef202 --- /dev/null +++ b/vss-processor-plugin/buildSrc/settings.gradle.kts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +dependencyResolutionManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} diff --git a/vss-processor-plugin/buildSrc/src/main/kotlin/org/eclipse/kuksa/vssprocessor/plugin/version/SemanticVersion.kt b/vss-processor-plugin/buildSrc/src/main/kotlin/org/eclipse/kuksa/vssprocessor/plugin/version/SemanticVersion.kt new file mode 100644 index 00000000..d27f4e5b --- /dev/null +++ b/vss-processor-plugin/buildSrc/src/main/kotlin/org/eclipse/kuksa/vssprocessor/plugin/version/SemanticVersion.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.version + +import java.io.File +import java.util.Locale + +const val VERSION_FILE_DEFAULT_PATH_KEY = "versionFilePathKey" +const val VERSION_FILE_DEFAULT_NAME = "version.txt" + +class SemanticVersion(versionFilePath: String) { + val major: Int + val minor: Int + val patch: Int + var suffix: String = "" + + val versionFile: File + + val versionName: String + get() { + var version = "$major.$minor.$patch" + if (suffix.isNotEmpty()) { + version += "-$suffix" + } + + return version + } + + val versionCode: Int + get() { + val decorator = "10" + val paddedMajorVersion = String.format(Locale.ROOT, "%02d", major) + val paddedMinorVersion = String.format(Locale.ROOT, "%02d", minor) + val paddedPatchVersion = String.format(Locale.ROOT, "%02d", patch) + + return "$decorator$paddedMajorVersion$paddedMinorVersion$paddedPatchVersion".toInt() + } + + init { + versionFile = File(versionFilePath) + + val semanticVersion = versionFile.readText() + val versions = semanticVersion.trim() + .substringBefore("-") // Ignore suffixes like -SNAPSHOT + .split(".") + val suffix = semanticVersion.substringAfter("-", "") + + major = versions[0].toInt() + minor = versions[1].toInt() + patch = versions[2].toInt() + this.suffix = suffix + } +} diff --git a/vss-processor-plugin/proguard-rules.pro b/vss-processor-plugin/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/vss-processor-plugin/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/vss-processor-plugin/settings.gradle.kts b/vss-processor-plugin/settings.gradle.kts new file mode 100644 index 00000000..2f92194d --- /dev/null +++ b/vss-processor-plugin/settings.gradle.kts @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenLocal() + google() + mavenCentral() + } + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "vss-processor-plugin" diff --git a/vss-processor-plugin/src/main/java/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPlugin.kt b/vss-processor-plugin/src/main/java/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPlugin.kt new file mode 100644 index 00000000..6dc4f9bc --- /dev/null +++ b/vss-processor-plugin/src/main/java/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPlugin.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin + +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.FileType +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.api.tasks.CacheableTask +import org.gradle.api.tasks.IgnoreEmptyDirectories +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.PathSensitive +import org.gradle.api.tasks.PathSensitivity +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.register +import org.gradle.work.ChangeType +import org.gradle.work.Incremental +import org.gradle.work.InputChanges +import java.io.File +import java.io.FileNotFoundException +import javax.inject.Inject + +open class VssProcessorPluginExtension +@Inject +internal constructor(objectFactory: ObjectFactory) { + /** + * The default search path is the $rootProject/vss folder. The defined folder will be crawled for all compatible + * extension types by this plugin. + */ + val searchPath: Property = objectFactory.property(String::class.java).convention("") +} + +private val fileSeparator = File.separator + +/** + * This Plugin searches for compatible specification files and copies them into an input folder for the + * KSP VSS Processor. This is necessary because the Symbol Processor does not have access to the android assets folder. + */ +class VssProcessorPlugin : Plugin { + override fun apply(project: Project) { + val extension = project.extensions.create(EXTENSION_NAME) + + // The extension variables are only available after the project has been evaluated + project.afterEvaluate { + val buildDir = layout.buildDirectory.asFile.get() + val buildDirPath = buildDir.absolutePath + val vssDir = "${rootDir}${fileSeparator}$VSS_FOLDER_NAME" + + val provideVssDefinitionTask = + project.tasks.register(PROVIDE_VSS_DEFINITION_TASK_NAME) { + val searchPath = extension.searchPath.get().ifEmpty { vssDir } + val vssDefinitionFilePath = StringBuilder(buildDirPath) + .append(fileSeparator) + .append(KSP_INPUT_BUILD_DIRECTORY) + .append(fileSeparator) + .toString() + val vssDefinitionBuildFile = File(vssDefinitionFilePath) + + logger.info("Searching directory $searchPath for VSS definitions") + + val searchDir = file(searchPath) + if (!searchDir.exists()) { + throw FileNotFoundException( + "Directory '$searchPath' for VSS files not found! Please create the folder relative to " + + "your project directory: ${searchDir.path}.", + ) + } + + inputDir.set(searchDir) + outputDir.set(vssDefinitionBuildFile) + } + + tasks.getByName("preBuild").dependsOn( + provideVssDefinitionTask.get(), + ) + } + } + + companion object { + private const val KSP_INPUT_BUILD_DIRECTORY = "kspInput" + private const val EXTENSION_NAME = "vssProcessor" + private const val PROVIDE_VSS_DEFINITION_TASK_NAME = "provideVssDefinition" + private const val VSS_FOLDER_NAME = "vss" + } +} + +/** + * This task takes an input directory [inputDir] which should contain all available VSS definition files and an + * output directory [outputDir] where all files are copied to so the VSSProcessor can work with them. + */ +@CacheableTask +private abstract class ProvideVssDefinitionTask : DefaultTask() { + @get:Incremental + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.NAME_ONLY) + @get:InputDirectory + abstract val inputDir: DirectoryProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @TaskAction + fun provideFile(inputChanges: InputChanges) { + inputChanges.getFileChanges(inputDir).forEach { change -> + if (change.fileType == FileType.DIRECTORY) return@forEach + + val file = change.file + val extension = file.extension + if (!validVssExtension.contains(extension)) { + logger.warn("Found incompatible VSS file: ${file.name} - Consider removing it") + return@forEach + } + + val targetFile = outputDir.file(change.normalizedPath).get().asFile + logger.info("Found VSS file changes for: ${targetFile.name}, change: ${change.changeType}") + + when (change.changeType) { + ChangeType.ADDED, + ChangeType.MODIFIED, + -> file.copyTo(targetFile, true) + + ChangeType.REMOVED -> targetFile.delete() + else -> logger.warn("Could not determine file change type: ${change.changeType}") + } + } + } + + companion object { + private val validVssExtension = setOf("yml", "yaml") + } +} diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/Tag.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/Tag.kt new file mode 100644 index 00000000..1e32633b --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/Tag.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin + +import io.kotest.core.NamedTag + +val Functional = NamedTag("Functional") diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPluginTest.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPluginTest.kt new file mode 100644 index 00000000..5dbd4a45 --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/VssProcessorPluginTest.kt @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin + +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import org.eclipse.kuksa.vssprocessor.plugin.generator.project.AndroidLibProject +import org.eclipse.kuksa.vssprocessor.plugin.generator.project.GradleProject.Companion.TEST_FOLDER_NAME_DEFAULT +import org.eclipse.kuksa.vssprocessor.plugin.generator.project.VssProcessorLibProject +import org.eclipse.kuksa.vssprocessor.plugin.generator.project.VssProcessorPluginProject +import org.eclipse.kuksa.vssprocessor.plugin.generator.project.dollar +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import java.io.File +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.deleteRecursively +import kotlin.io.path.exists +import kotlin.io.path.pathString + +// Note: +// - Debugging into functional gradle test cases do not work. +// - Sometimes test errors are obscured so try looking into the test report to see the actual one. +// +// ./gradlew :vss-processor-plugin:test -Dkotest.tags="Functional" +@OptIn(ExperimentalPathApi::class) +class VssProcessorPluginTest : BehaviorSpec({ + tags(Functional) + + given("A VSSProcessorPlugin project") { + val pluginProject = VssProcessorPluginProject() + val rootProjectDir = pluginProject.rootProjectDir.toFile() + val gradleRunner = GradleRunner.create() + .forwardOutput() + .withGradleVersion(GRADLE_VERSION_TEST) + .withPluginClasspath() + .withProjectDir(rootProjectDir) + + afterSpec { + pluginProject.close() + } + + `when`("the plugin is applied") { + pluginProject.generate() + + val pluginResult = gradleRunner.build() + + then("it should build successfully") { + pluginResult.output shouldContain "BUILD SUCCESSFUL" + } + + and("an Android library project is added") { + val androidLibProject = AndroidLibProject("lib") + androidLibProject.generate() + + pluginProject.add(androidLibProject) + + afterContainer { + pluginProject.refresh() // So the plugin project does not have 2 :lib includes + } + + `when`("the ProvideVssDefinitionTask is executed without correct input") { + val result = gradleRunner + .withArguments("provideVssDefinition") + .buildAndFail() + + then("it should throw an Exception") { + result.output shouldContain "Could not create task ':lib:provideVssDefinition'" + } + } + } + + // The following tests are mainly testing the configuration cache + // #1: A full clean of the build folder AND gradle cache -> SUCCESS + // #2: A full clean of the build folder BUT gradle cache stays -> FROM_CACHE + // #3: No clean -> UP_TO_DATE + // #4: Gradle + plugin / task input changed -> SUCCESS + // #5: Input file name changed -> SUCCESS + and("a VSS compatible Android library project is added") { + val vssFile2: File + val vssProcessorProject = VssProcessorLibProject("lib").apply { + copyVssFiles(vssDir, VSS_TEST_FILE_NAME) + vssFile2 = copyVssFiles(vssDir2, VSS_TEST_FILE_MINIMAL_NAME) + generate() + } + val vssDir2 = vssProcessorProject.vssDir2 + val vssDir2Path = vssDir2.pathString + + pluginProject.add(vssProcessorProject) + + `when`("the ProvideVssDefinitionTask is executed with build cache the #1 time") { + pluginProject.localCacheFolder.deleteRecursively() + + val result = gradleRunner + .withArguments("clean", "--build-cache", "provideVssDefinition") + .build() + + println("ProvideVssDefinitionTask + Build Cache #1 output: ${result.output}") + + then("it should build successfully") { + val outcome = result.task(":lib:provideVssDefinition")?.outcome + + outcome shouldBe TaskOutcome.SUCCESS + } + } + + `when`("the ProvideVssDefinitionTask is executed with build cache the #2 time") { + val result = gradleRunner + .withArguments("clean", "--build-cache", "provideVssDefinition") + .build() + + println("ProvideVssDefinitionTask + Build Cache #2 output: ${result.output}") + + then("it should build from cache") { + val outcome = result.task(":lib:provideVssDefinition")?.outcome + + outcome shouldBe TaskOutcome.FROM_CACHE + } + } + + `when`("the ProvideVssDefinitionTask is executed with build cache the #3 time") { + val kspInputDir = vssProcessorProject.buildDir.resolve(KSP_INPUT_BUILD_DIRECTORY) + val result = gradleRunner + .withArguments("--build-cache", "provideVssDefinition") + .build() + + println("ProvideVssDefinitionTask + Build Cache #3 output: ${result.output}") + + then("it should be up to date") { + val outcome = result.task(":lib:provideVssDefinition")?.outcome + + outcome shouldBe TaskOutcome.UP_TO_DATE + } + + then("it should copy all vss files") { + val vssFile = kspInputDir.resolve(VSS_TEST_FILE_NAME) + + vssFile.exists() shouldBe true + } + } + + `when`("the input of the ProvideVssDefinitionTask changes") { + val projectVssDir2 = vssDir2Path.substringAfter(TEST_FOLDER_NAME_DEFAULT) + vssProcessorProject.generate( + """ + vssProcessor { + searchPath = "${dollar}rootDir/$projectVssDir2" + } + """.trimIndent(), + ) + + val result = gradleRunner + .withArguments("--build-cache", "provideVssDefinition") + .build() + + println("ProvideVssDefinitionTask + Build Cache #4 output: ${result.output}") + + then("it should build successfully") { + val outcome = result.task(":lib:provideVssDefinition")?.outcome + + outcome shouldBe TaskOutcome.SUCCESS + } + } + + `when`("the name of the input of the ProvideVssDefinitionTask changes") { + vssFile2.renameTo(File("$vssDir2Path/vss_rel_4.0_test_renamed.yml")) + val result = gradleRunner + .withArguments("--build-cache", "provideVssDefinition") + .build() + + println("ProvideVssDefinitionTask + Build Cache #5 output: ${result.output}") + + then("it should build successfully") { + val outcome = result.task(":lib:provideVssDefinition")?.outcome + + outcome shouldBe TaskOutcome.SUCCESS + } + } + } + } + } +}) { + companion object { + private const val VSS_TEST_FILE_NAME = "vss_rel_4.0_test.yaml" + private const val VSS_TEST_FILE_MINIMAL_NAME = "vss_rel_4.0_test_minimal.yaml" + private const val GRADLE_VERSION_TEST = "8.6" + private const val KSP_INPUT_BUILD_DIRECTORY = "kspInput" + } +} diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/AndroidLibProject.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/AndroidLibProject.kt new file mode 100644 index 00000000..a6f44ccf --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/AndroidLibProject.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.generator.project + +import kotlin.io.path.appendText +import kotlin.io.path.createDirectories +import kotlin.io.path.writeText + +open class AndroidLibProject(name: String) : GradleProject(name) { + final override val projectDir = rootProjectDir.resolve(name).createDirectories() + + private val buildFile = projectDir.resolve("build.gradle.kts") + private val mainDir = projectDir.resolve("src/main").createDirectories() + private val androidManifestFile = mainDir.resolve("AndroidManifest.xml") + + override fun generate(appendix: String) { + androidManifestFile.writeText( + """ + + + + """.trimIndent(), + ) + + buildFile.writeText( + """ + plugins { + id("com.android.library") + id("org.eclipse.kuksa.vss-processor-plugin") + } + + android { + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + namespace = "org.eclipse.kuksa.vssProcessorPluginTest" + compileSdk = $COMPILE_SDK + + defaultConfig { + minSdk = $MIN_SDK + } + } + + dependencies { + } + + """.trimIndent(), + ) + + buildFile.appendText("\n$appendix") + } + + companion object { + private const val COMPILE_SDK = 34 + private const val MIN_SDK = 27 + } +} diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/GradleProject.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/GradleProject.kt new file mode 100644 index 00000000..d112efef --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/GradleProject.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.generator.project + +import java.nio.file.Path +import kotlin.io.path.createDirectories + +abstract class GradleProject(val name: String, testFolder: String = TEST_FOLDER_NAME_DEFAULT) : AutoCloseable { + val rootProjectDir = Path.of(testFolder).createDirectories() + open val projectDir: Path = rootProjectDir + + val buildDir: Path + get() = projectDir.resolve("build") + + abstract fun generate(appendix: String = "") + + open fun refresh() { + generate() + } + + override fun close() { + rootProjectDir.toFile().deleteRecursively() + } + + companion object { + const val TEST_FOLDER_NAME_DEFAULT = "build/functionalTest/" + } +} + +val dollar: String + get() = "\$" diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/RootGradleProject.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/RootGradleProject.kt new file mode 100644 index 00000000..8d9a53b0 --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/RootGradleProject.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.generator.project + +import kotlin.io.path.appendLines + +abstract class RootGradleProject(name: String) : GradleProject(name) { + protected val settingsFile = rootProjectDir.resolve("settings.gradle.kts") + protected val rootBuildFile = rootProjectDir.resolve("build.gradle.kts") + + private val addedProjects = mutableListOf() + + fun add(project: GradleProject) { + if (addedProjects.isEmpty()) settingsFile.appendLines(setOf("")) + + val addedProject = setOf( + """ + include(":${project.name}") + """.trimIndent(), + ) + settingsFile.appendLines(addedProject) + + addedProjects.add(project) + } + + override fun refresh() { + super.refresh() + + addedProjects.clear() + } +} diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorLibProject.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorLibProject.kt new file mode 100644 index 00000000..f9bfc84c --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorLibProject.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.generator.project + +import java.io.File +import java.nio.file.Path +import kotlin.io.path.createDirectories + +class VssProcessorLibProject(name: String) : AndroidLibProject(name) { + val vssDir = rootProjectDir.resolve(VSS_DIR_NAME).createDirectories() + val vssDir2 = rootProjectDir.resolve("${VSS_DIR_NAME}_2").createDirectories() + + fun copyVssFiles(directory: Path, fileName: String): File { + val certificateUrl = VssProcessorLibProject::class.java.classLoader?.getResource(fileName)!! + val certificateFile = File(certificateUrl.toURI()) + + val targetLocation = directory.resolve(certificateFile.name).toFile() + return certificateFile.copyTo(targetLocation, true) + } + + companion object { + const val VSS_DIR_NAME = "vss" + } +} diff --git a/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorPluginProject.kt b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorPluginProject.kt new file mode 100644 index 00000000..85e4507f --- /dev/null +++ b/vss-processor-plugin/src/test/kotlin/org/eclipse/kuksa/vssprocessor/plugin/generator/project/VssProcessorPluginProject.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.eclipse.kuksa.vssprocessor.plugin.generator.project + +import kotlin.io.path.createDirectories +import kotlin.io.path.writeText + +class VssProcessorPluginProject : RootGradleProject("VssProcessorPlugin") { + val localCacheFolder = projectDir.resolve("local-cache").createDirectories() + + override fun generate(appendix: String) { + settingsFile.writeText( + """ + pluginManagement { + includeBuild("../../../vss-processor-plugin") + + repositories { + gradlePluginPortal() + google() + mavenCentral() + } + } + + dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenLocal() + google() + mavenCentral() + } + versionCatalogs { + create("libs") { + from(files("../../../gradle/libs.versions.toml")) + } + } + } + + buildCache { + local { + directory = "${localCacheFolder.toFile().toURI()}" + } + } + + rootProject.name = "${this::class.simpleName}Test" + """.trimIndent(), + ) + + rootBuildFile.writeText( + """ + buildscript { + repositories { + google() + mavenCentral() + } + + dependencies { + classpath("com.android.tools.build:gradle:$AGP_VERSION") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION") + } + } + """.trimIndent(), + ) + } + + companion object { + private const val AGP_VERSION = "8.2.2" + private const val KOTLIN_VERSION = "1.9.22" + } +} diff --git a/app/src/main/assets/vss_rel_4.0.yaml b/vss-processor-plugin/src/test/resources/vss_rel_4.0_test.yaml similarity index 100% rename from app/src/main/assets/vss_rel_4.0.yaml rename to vss-processor-plugin/src/test/resources/vss_rel_4.0_test.yaml diff --git a/vss-processor-plugin/src/test/resources/vss_rel_4.0_test_minimal.yaml b/vss-processor-plugin/src/test/resources/vss_rel_4.0_test_minimal.yaml new file mode 100644 index 00000000..db9c669d --- /dev/null +++ b/vss-processor-plugin/src/test/resources/vss_rel_4.0_test_minimal.yaml @@ -0,0 +1,32 @@ +Vehicle: + description: High-level vehicle data. + type: branch + uuid: ccc825f94139544dbb5f4bfd033bece6 + +Vehicle.ADAS: + description: All Advanced Driver Assist Systems data. + type: branch + uuid: 14c2b2e1297b513197d320a5ce58f42e + +Vehicle.ADAS.ABS: + description: Antilock Braking System signals. + type: branch + uuid: 219270ef27c4531f874bbda63743b330 + +Vehicle.ADAS.ABS.IsEnabled: + datatype: boolean + description: Indicates if ABS is enabled. True = Enabled. False = Disabled. + type: actuator + uuid: cad374fbfdc65df9b777508f04d5b073 + +Vehicle.ADAS.ABS.IsEngaged: + datatype: boolean + description: Indicates if ABS is currently regulating brake pressure. True = Engaged. False = Not Engaged. + type: sensor + uuid: 6dd21979a2225e31940dc2ece1aa9a04 + +Vehicle.ADAS.ABS.IsError: + datatype: boolean + description: Indicates if ABS incurred an error condition. True = Error. False = No Error. + type: sensor + uuid: 13cfabb3122254128234f9a696f14678 diff --git a/vss-processor/build.gradle.kts b/vss-processor/build.gradle.kts index 2b242f33..d3099dd4 100644 --- a/vss-processor/build.gradle.kts +++ b/vss-processor/build.gradle.kts @@ -1,3 +1,7 @@ +import org.eclipse.kuksa.version.SemanticVersion +import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY +import org.jetbrains.dokka.gradle.DokkaTask + /* * Copyright (c) 2023 Contributors to the Eclipse Foundation * @@ -23,8 +27,10 @@ plugins { alias(libs.plugins.dokka) } +val versionPath = rootProject.ext[VERSION_FILE_DEFAULT_PATH_KEY] as String +val semanticVersion = SemanticVersion(versionPath) +version = semanticVersion.versionName group = "org.eclipse.kuksa" -version = rootProject.extra["projectVersion"].toString() dependencies { implementation(project(":vss-core")) @@ -52,7 +58,7 @@ tasks.withType().configureEach { } } -configure { +publish { mavenPublicationName = "release" componentName = "java" description = "Vehicle Signal Specification (VSS) Code Generator for the KUKSA SDK" @@ -60,11 +66,52 @@ configure { tasks.register("javadocJar", Jar::class) { dependsOn("dokkaHtml") + + val buildDir = layout.buildDirectory.get() from("$buildDir/dokka/html") archiveClassifier.set("javadoc") } +tasks.withType().configureEach { + notCompatibleWithConfigurationCache("https://github.com/Kotlin/dokka/issues/2231") +} + java { withJavadocJar() // needs to be called after tasks.register("javadocJar") withSourcesJar() } + +// Tasks for included composite builds need to be called separately. For convenience sake we depend on the most used +// tasks. Every task execution of this project will then be forwarded to the included build project. Since this module +// is hard coupled to the +// +// We have to manually define the task names because the task() method of the included build throws an error for any +// unknown task. +// +// WARNING: Do not depend on the task "clean" here: https://github.com/gradle/gradle/issues/23585 +val dependentCompositeTasks = setOf( + "publishToMavenLocal", + "publishAllPublicationsToOSSRHReleaseRepository", + "test", +) +val dependentCompositeBuilds = setOf("vss-processor-plugin") + +gradle.projectsEvaluated { + val subProjectTasks = tasks + subprojects.flatMap { it.tasks } + + println("Linking Composite Tasks:") + + subProjectTasks + .filter { dependentCompositeTasks.contains(it.name) } + .forEach { task -> + val compositeTask = gradle.includedBuilds + .filter { dependentCompositeBuilds.contains(it.name) } + .map { compositeBuild -> + println("- ${task.project.name}:${task.name} -> ${compositeBuild.name}:${task.name}") + + compositeBuild.task(":${task.name}") + } + + task.dependsOn(compositeTask) + } +} diff --git a/vss-processor/src/main/kotlin/org/eclipse/kuksa/vssprocessor/VssDefinitionProcessor.kt b/vss-processor/src/main/kotlin/org/eclipse/kuksa/vssprocessor/VssDefinitionProcessor.kt index 73b11c81..dee2f658 100644 --- a/vss-processor/src/main/kotlin/org/eclipse/kuksa/vssprocessor/VssDefinitionProcessor.kt +++ b/vss-processor/src/main/kotlin/org/eclipse/kuksa/vssprocessor/VssDefinitionProcessor.kt @@ -22,7 +22,6 @@ package org.eclipse.kuksa.vssprocessor import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAnnotationsByType import com.google.devtools.ksp.processing.CodeGenerator import com.google.devtools.ksp.processing.Dependencies import com.google.devtools.ksp.processing.KSPLogger @@ -70,7 +69,6 @@ class VssDefinitionProcessor( } private inner class VssDefinitionVisitor : KSVisitorVoid() { - @OptIn(KspExperimental::class) override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { val containingFile = classDeclaration.containingFile ?: return @@ -82,30 +80,34 @@ class VssDefinitionProcessor( annotatedProcessorFileName, ) - val vssDefinition = classDeclaration.getAnnotationsByType(VssDefinition::class).firstOrNull() ?: return - val vssDefinitionPath = vssDefinition.vssDefinitionPath - - val definitionFile = loadAssetFile(vssDefinitionPath) - if (definitionFile == null || !definitionFile.exists()) { - logger.info("No VSS definition file was found!") + val definitionFiles = loadVssDefinitionFiles() + if (definitionFiles.isEmpty()) { + logger.error("No VSS definition files were found! Is the plugin correctly configured?") return } - val simpleSpecificationElements = yamlParser.parseSpecifications(definitionFile) - val vssPathToSpecificationElement = simpleSpecificationElements.associateBy({ VssPath(it.vssPath) }, { it }) + definitionFiles.forEach { definitionFile -> + val simpleSpecificationElements = yamlParser.parseSpecifications(definitionFile) + val vssPathToSpecificationElement = simpleSpecificationElements + .associateBy({ VssPath(it.vssPath) }, { it }) - generateModelFiles(vssPathToSpecificationElement) + logger.info("Generating models for definition file: ${definitionFile.name}") + generateModelFiles(vssPathToSpecificationElement) + } } // Uses the default file path for generated files (from the code generator) and searches for the given file. - private fun loadAssetFile(fileName: String): File? { - val generatedFile = codeGenerator.generatedFile.firstOrNull() ?: return null + private fun loadVssDefinitionFiles(): Collection { + val generatedFile = codeGenerator.generatedFile.firstOrNull() ?: return emptySet() val generationPath = generatedFile.absolutePath - val buildPath = generationPath.replaceAfterLast(buildDir, "") - val assetsFilePath = buildPath + fileSeparator + assetsDir - val assetsFolder = File(assetsFilePath) - - return assetsFolder.walk().firstOrNull { it.name == fileName } + val buildPath = generationPath.replaceAfterLast("$BUILD_FOLDER_NAME$fileSeparator", "") + val kspInputFilePath = "$buildPath$fileSeparator$KSP_INPUT_BUILD_DIRECTORY" + val kspInputFolder = File(kspInputFilePath) + + return kspInputFolder + .walk() + .filter { it.isFile } + .toSet() } private fun generateModelFiles(vssPathToSpecification: Map) { @@ -184,10 +186,10 @@ class VssDefinitionProcessor( private companion object { private const val PACKAGE_NAME = "org.eclipse.kuksa.vss" private const val FILE_NAME_PROCESSOR_POSTFIX = "Processor" + private const val KSP_INPUT_BUILD_DIRECTORY = "kspInput" + private const val BUILD_FOLDER_NAME = "build" private val fileSeparator = File.separator - private val assetsDir = "intermediates" + fileSeparator + "assets" + fileSeparator - private val buildDir = fileSeparator + "build" + fileSeparator } } diff --git a/samples/src/main/assets/vss_rel_4.0.yaml b/vss/vss_rel_4.0.yaml similarity index 100% rename from samples/src/main/assets/vss_rel_4.0.yaml rename to vss/vss_rel_4.0.yaml