diff --git a/build.gradle.kts b/build.gradle.kts index 0c70c86e1..dc5769af3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,21 +43,21 @@ description = "MQTT CLI is a tool that provides a feature rich command line inte "various MQTT clients simultaneously and supports MQTT 5.0 and MQTT 3.1.1 " application { - mainClass.set("com.hivemq.cli.MqttCLIMain") + mainClass = "com.hivemq.cli.MqttCLIMain" } /* ******************** java ******************** */ java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion = JavaLanguageVersion.of(21) } } tasks.compileJava { - javaCompiler.set(javaToolchains.compilerFor { - languageVersion.set(JavaLanguageVersion.of(8)) - }) + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(11) + } } tasks.jar { @@ -75,11 +75,11 @@ tasks.jar { } tasks.jar { - archiveClassifier.set("plain") + archiveClassifier = "plain" } tasks.shadowJar { - archiveClassifier.set("") + archiveClassifier = "" } /* ******************** dependencies ******************** */ @@ -160,11 +160,11 @@ dependencies { val generateHivemqOpenApi by tasks.registering(GenerateTask::class) { group = "hivemq" - generatorName.set("java") - inputSpec.set(hivemqOpenApi.singleFile.path) - outputDir.set(layout.buildDirectory.dir("tmp/$name").get().asFile.absolutePath) - apiPackage.set("com.hivemq.cli.openapi.hivemq") - modelPackage.set("com.hivemq.cli.openapi.hivemq") + generatorName = "java" + inputSpec = hivemqOpenApi.singleFile.path + outputDir = layout.buildDirectory.dir("tmp/$name").get().asFile.absolutePath + apiPackage = "com.hivemq.cli.openapi.hivemq" + modelPackage = "com.hivemq.cli.openapi.hivemq" configOptions.put("dateLibrary", "java8") configOptions.put("hideGenerationTimestamp", "true") @@ -184,11 +184,11 @@ val generateHivemqOpenApi by tasks.registering(GenerateTask::class) { val generateSwarmOpenApi by tasks.registering(GenerateTask::class) { group = "swarm" - generatorName.set("java") - inputSpec.set(swarmOpenApi.singleFile.path) - outputDir.set(layout.buildDirectory.dir("tmp/$name").get().asFile.absolutePath) - apiPackage.set("com.hivemq.cli.openapi.swarm") - modelPackage.set("com.hivemq.cli.openapi.swarm") + generatorName = "java" + inputSpec = swarmOpenApi.singleFile.path + outputDir = layout.buildDirectory.dir("tmp/$name").get().asFile.absolutePath + apiPackage = "com.hivemq.cli.openapi.swarm" + modelPackage = "com.hivemq.cli.openapi.swarm" configOptions.put("dateLibrary", "java8") configOptions.put("hideGenerationTimestamp", "true") @@ -356,9 +356,9 @@ tasks.named("forbiddenApisIntegrationTest") { enabled = false } //checks for java installations prior the execution. cliNative { - graalVersion.set(libs.versions.graal) - javaVersion.set(libs.versions.javaNative) + javaVersion = libs.versions.javaNative } +val majorJavaNativeVersion = libs.versions.javaNative.get().substringBefore(".") //reflection configuration files are currently created manually with the command: ./gradlew -Pagent agentMainRun --stacktrace //this yields an exception as the Graal plugin is currently quite buggy. The files are created nonetheless. @@ -367,23 +367,20 @@ val agentMainRun by tasks.registering(JavaExec::class) { group = "native" val launcher = javaToolchains.launcherFor { - languageVersion.set(JavaLanguageVersion.of(libs.versions.javaNative.get())) - vendor.set(JvmVendorSpec.GRAAL_VM) - + languageVersion = JavaLanguageVersion.of(majorJavaNativeVersion) + vendor = JvmVendorSpec.GRAAL_VM } - javaLauncher.set(launcher) + javaLauncher = launcher classpath = sourceSets.main.get().runtimeClasspath - mainClass.set("com.hivemq.cli.graal.NativeMain") + mainClass = "com.hivemq.cli.graal.NativeMain" } val nativeImageOptions by graalvmNative.binaries.named("main") { - javaLauncher.set(javaToolchains.launcherFor { - languageVersion.set(JavaLanguageVersion.of(libs.versions.javaNative.get())) - vendor.set(JvmVendorSpec.GRAAL_VM) - }) + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(majorJavaNativeVersion) + vendor = JvmVendorSpec.GRAAL_VM + } buildArgs.add("-Dio.netty.noUnsafe=true") - buildArgs.add("-H:+ReportExceptionStackTraces") - buildArgs.add("-H:+TraceServiceLoaderFeature") buildArgs.add("--no-fallback") buildArgs.add("--enable-https") buildArgs.add("--features=com.hivemq.cli.graal.BouncyCastleFeature") @@ -396,6 +393,7 @@ val nativeImageOptions by graalvmNative.binaries.named("main") { "org.jctools.util.UnsafeAccess," + "io.netty.util.ReferenceCountUtil," + "io.netty.util.ResourceLeakDetector," + + "io.netty.util.ResourceLeakDetector\$Level," + "io.netty.util.internal.shaded.org.jctools.queues.BaseMpscLinkedArrayQueue," + "io.netty.util.internal.shaded.org.jctools.queues.BaseSpscLinkedArrayQueue," + "io.netty.util.internal.shaded.org.jctools.util.UnsafeAccess," + @@ -403,6 +401,8 @@ val nativeImageOptions by graalvmNative.binaries.named("main") { "io.netty.util.internal.SystemPropertyUtil," + "io.netty.util.internal.PlatformDependent," + "io.netty.util.internal.PlatformDependent0," + + "io.netty.util.internal.PlatformDependent\$1," + + "io.netty.util.internal.PlatformDependent\$2," + "io.netty.util.internal.logging.JdkLogger," + "io.netty.buffer.AbstractByteBufAllocator" ) @@ -439,9 +439,9 @@ val nativeImageOptions by graalvmNative.binaries.named("main") { } graalvmNative { - toolchainDetection.set(false) + toolchainDetection = false agent { - defaultMode.set("standard") + defaultMode = "standard" tasksToInstrumentPredicate.set { t -> t == agentMainRun.get() } } binaries { @@ -453,8 +453,8 @@ graalvmNative { val buildBrewZip by tasks.registering(Zip::class) { - archiveClassifier.set("brew") - destinationDirectory.set(layout.buildDirectory.dir("packages/homebrew")) + archiveClassifier = "brew" + destinationDirectory = layout.buildDirectory.dir("packages/homebrew") into("brew") { from(tasks.shadowJar) @@ -537,24 +537,24 @@ val buildRpmPackage by tasks.registering(Copy::class) { /* ******************** windows zip ******************** */ launch4j { - headerType.set("console") - mainClassName.set(application.mainClass.get()) - icon.set("$projectDir/icons/05-mqtt-cli-icon.ico") + headerType = "console" + mainClassName = application.mainClass.get() + icon = "$projectDir/icons/05-mqtt-cli-icon.ico" setJarTask(tasks.shadowJar.get()) - copyConfigurable.set(emptyList()) - copyright.set("Copyright 2019-present HiveMQ and the HiveMQ Community") - companyName.set("HiveMQ GmbH") - downloadUrl.set("https://openjdk.java.net/install/") - jreMinVersion.set("1.8") - windowTitle.set("MQTT CLI") - version.set(project.version.toString()) - textVersion.set(project.version.toString()) + copyConfigurable = emptyList() + copyright = "Copyright 2019-present HiveMQ and the HiveMQ Community" + companyName = "HiveMQ GmbH" + downloadUrl = "https://openjdk.java.net/install/" + jreMinVersion = "1.8" + windowTitle = "MQTT CLI" + version = project.version.toString() + textVersion = project.version.toString() } val buildWindowsZip by tasks.registering(Zip::class) { - archiveClassifier.set("win") - destinationDirectory.set(layout.buildDirectory.dir("packages/windows")) + archiveClassifier = "win" + destinationDirectory = layout.buildDirectory.dir("packages/windows") from("packages/windows") { filter { it.replace("@@exeName@@", launch4j.outfile.get()) } @@ -573,7 +573,7 @@ val buildPackages by tasks.registering { githubRelease { token(System.getenv("githubToken")) - draft.set(true) + draft = true releaseAssets( tasks.shadowJar, buildBrewZip, @@ -581,15 +581,15 @@ githubRelease { buildRpmPackage.map { fileTree(it.destinationDir) }, buildWindowsZip, ) - allowUploadToExisting.set(true) + allowUploadToExisting = true } /* ******************** Update the Homebrew-Formula with the newly built package ******************** */ gitPublish { - repoUri.set("https://github.com/hivemq/homebrew-mqtt-cli.git") - branch.set("master") - commitMessage.set("Release version v${project.version}") + repoUri = "https://github.com/hivemq/homebrew-mqtt-cli.git" + branch = "master" + commitMessage = "Release version v${project.version}" contents.from(buildBrewFormula) } @@ -612,7 +612,7 @@ jib { /* ******************** platform distribution ******************** */ distributions.shadow { - distributionBaseName.set("mqtt-cli") + distributionBaseName = "mqtt-cli" contents { from("README.txt") } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5f438ae4..d2f3440e6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,22 +1,21 @@ [versions] -apache-commonsIO = "2.16.0" +apache-commonsIO = "2.16.1" apache-commonsLang = "3.14.0" apache-commonsText = "1.11.0" awaitility = "4.2.1" -bouncycastle = "1.77" +bouncycastle = "1.78" dagger = "2.51.1" -graal = "22.3.0" -graalvm-nativeImage-svm = "22.0.0.2" +graalvm-nativeImage-svm = "24.0.1" gson = "2.10.1" gsonFire = "1.9.0" guava = "33.1.0-jre" hivemq-communityEditionEmbedded = "2024.3" hivemq-mqttClient = "1.3.3" hivemq-testcontainer = "2.0.0" -javaNative = "17" +javaNative = "21.0.2" javax-annotation-api = "1.3.2" jetbrains-annotations = "24.1.0" -jline = "3.21.0" +jline = "3.25.1" jsr305 = "3.0.2" junit-jupiter = "5.10.2" junit-pioneer = "2.2.0" @@ -25,7 +24,7 @@ mockito = "5.11.0" netty = "4.1.109.Final" okhttp = "4.12.0" openCsv = "5.9" -picocli = "4.7.0" +picocli = "4.7.5" swagger-annotations = "1.6.14" testcontainers = "1.19.7" tinylog = "2.7.0" @@ -75,7 +74,7 @@ tinylog-impl = { module = "org.tinylog:tinylog-impl", version.ref = "tinylog" } [plugins] defaults = { id = "io.github.sgtsilvio.gradle.defaults", version = "0.2.0" } forbiddenApis = { id = "de.thetaphi.forbiddenapis", version = "3.7" } -gitPublish = { id = "org.ajoberstar.git-publish", version = "3.0.1" } +gitPublish = { id = "org.ajoberstar.git-publish", version = "4.2.2" } githubRelease = { id = "com.github.breadmoirai.github-release", version = "2.5.2" } graalvm-native = { id = "org.graalvm.buildtools.native", version = "0.10.1" } jib = { id = "com.google.cloud.tools.jib", version = "3.4.2" } diff --git a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/CliNativeImagePlugin.kt b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/CliNativeImagePlugin.kt index 2cee9bac3..42fcb345e 100644 --- a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/CliNativeImagePlugin.kt +++ b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/CliNativeImagePlugin.kt @@ -5,11 +5,14 @@ import com.hivemq.cli.native_image.extensions.CliNativeExtensionImpl import com.hivemq.cli.native_image.tasks.DownloadGraalJVMTask import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.file.RelativePath +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Exec import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.register import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform +import java.io.File class CliNativeImagePlugin : Plugin { @@ -26,7 +29,6 @@ class CliNativeImagePlugin : Plugin { val downloadTask = project.tasks.register("downloadGraalJvm") { group = "native" description = "Configures the correct download for Graal" - graalVersion.set(extension.graalVersion) javaVersion.set(extension.javaVersion) downloadBaseUrl.set(extension.graalBaseUrl) } @@ -34,60 +36,51 @@ class CliNativeImagePlugin : Plugin { val extractTask = project.tasks.register("extractGraalJvm") { group = "native" description = "Unzips the Graal JVM into the auto provisioning JDKS folder" - dependsOn(downloadTask) - workingDir(downloadTask.flatMap { it.jdksDirectory }) - commandLine("tar", "-xzf", downloadTask.flatMap { it.graalDownload }.get()) + inputs.file(downloadTask.flatMap { it.graalDownloadFile }) outputs.dir(downloadTask.flatMap { it.jdksDirectory.dir(it.graalFolderName) }) + + workingDir(downloadTask.flatMap { it.jdksDirectory.dir(it.graalFolderName) }) + commandLine("tar", "-xzf", downloadTask.flatMap { it.graalDownloadFile }.get(), "--strip-components=1") } val extractTaskWindows = project.tasks.register("extractGraalJvmWindows") { group = "native" description = "Unzips the Graal JVM into the auto provisioning JDKS folder" - dependsOn(downloadTask) - from(project.zipTree(downloadTask.flatMap { it.graalDownload }.get())) + inputs.file(downloadTask.flatMap { it.graalDownloadFile }) + + from(project.zipTree(downloadTask.flatMap { it.graalDownloadFile }.get())) into(downloadTask.flatMap { it.jdksDirectory }) + eachFile { + val originalPath = relativePath.pathString + val parts: MutableList = originalPath.split("/").toMutableList() + parts[0] = downloadTask.flatMap { it.graalFolderName }.get() + val newPath = parts.joinToString("/") + relativePath = RelativePath(!this.isDirectory, newPath) + } + doLast { + destinationDir = downloadTask.flatMap { it.jdksDirectory.dir(it.graalFolderName) }.get().asFile + } } - - project.tasks.register("installNativeImageTooling") { + project.tasks.register("installNativeImageTooling") { group = "native" - description = "Installs the native-image tooling and declares the Graal as auto provisioned" + description = "Declares the GraalVM installation as auto provisioned" + val graalVMFolderProvider: Provider if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows) { - dependsOn(extractTaskWindows) - val graalDirectory = extractTaskWindows.map { it.destinationDir } - .zip(downloadTask.flatMap { it.graalFolderName }) { jdkFolder, graalFolder -> - jdkFolder.resolve(graalFolder) - } - workingDir(graalDirectory) - commandLine("cmd", "/C", getGuPath(), "install", "native-image") - doLast { - graalDirectory.get().resolve("provisioned.ok").createNewFile() - } + graalVMFolderProvider = extractTaskWindows.map { it.outputs.files.singleFile } + inputs.dir(graalVMFolderProvider) } else { - dependsOn(extractTask) - workingDir(extractTask.map { it.outputs.files.singleFile }) - commandLine(getGuPath(), "install", "native-image") - doLast { - extractTask.map { it.outputs.files.singleFile }.get().resolve("provisioned.ok").createNewFile() - } + graalVMFolderProvider = extractTask.map { it.outputs.files.singleFile } + inputs.dir(graalVMFolderProvider) } - } - } + outputs.file(graalVMFolderProvider.get().resolve("provisioned.ok")) - private fun getGuPath(): String { - return if (DefaultNativePlatform.getCurrentOperatingSystem().isLinux) { - "./bin/gu" - } else if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows) { - "bin\\gu" - } else if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX) { - "./Contents/Home/bin/gu" - } else { - throw IllegalStateException( - "Unsupported operating system. (${DefaultNativePlatform.getCurrentOperatingSystem().displayName}" - ) + doLast { + graalVMFolderProvider.get().resolve("provisioned.ok").createNewFile() + } } } } diff --git a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtension.kt b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtension.kt index 65824fe70..7e42fb3e2 100644 --- a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtension.kt +++ b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtension.kt @@ -5,12 +5,7 @@ import org.gradle.api.provider.Property interface CliNativeExtension { /** - * Graal version, default: 22.2.0 - */ - val graalVersion: Property - - /** - * Java version, default: 17 + * Java version, default: 21.0.2 */ val javaVersion: Property @@ -18,4 +13,4 @@ interface CliNativeExtension { * Graal download base url, default: https://github.com/graalvm/graalvm-ce-builds/releases/download */ val graalBaseUrl: Property -} \ No newline at end of file +} diff --git a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtensionImpl.kt b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtensionImpl.kt index 86f4a89c9..31a324b00 100644 --- a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtensionImpl.kt +++ b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/extensions/CliNativeExtensionImpl.kt @@ -8,8 +8,7 @@ abstract class CliNativeExtensionImpl @Inject constructor( objectFactory: ObjectFactory ) : CliNativeExtension { - final override val graalVersion = objectFactory.property().convention("22.2.0") - final override val javaVersion = objectFactory.property().convention("17") + final override val javaVersion = objectFactory.property().convention("21.0.2") final override val graalBaseUrl = objectFactory.property().convention("https://github.com/graalvm/graalvm-ce-builds/releases/download") } diff --git a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/tasks/DownloadGraalJVMTask.kt b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/tasks/DownloadGraalJVMTask.kt index 1bfe656af..3cfee5a14 100644 --- a/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/tasks/DownloadGraalJVMTask.kt +++ b/mqtt-cli-plugins/src/main/kotlin/com/hivemq/cli/native_image/tasks/DownloadGraalJVMTask.kt @@ -3,6 +3,7 @@ package com.hivemq.cli.native_image.tasks import org.gradle.api.DefaultTask import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFile +import org.gradle.api.file.RegularFileProperty import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input @@ -18,9 +19,6 @@ abstract class DownloadGraalJVMTask @Inject constructor( objectFactory: ObjectFactory ) : DefaultTask() { - @get:Input - val graalVersion = objectFactory.property() - @get:Input val javaVersion = objectFactory.property() @@ -28,54 +26,44 @@ abstract class DownloadGraalJVMTask @Inject constructor( val downloadBaseUrl = objectFactory.property() @get:Internal - val jdksDirectory: DirectoryProperty = objectFactory.directoryProperty().convention( - project.layout.dir( - project.providers.provider { - project.gradle.gradleUserHomeDir.toPath() - .resolve("jdks") - //.resolve("com.hivemq.cli.native_image") - .toFile() - } - ) - ) + val jdksDirectory: DirectoryProperty = + objectFactory.directoryProperty().convention(project.layout.dir(project.providers.provider { + project.gradle.gradleUserHomeDir.toPath().resolve("jdks").toFile() + })) @get:Internal val graalFolderName = objectFactory.property().convention(createGraalFolderName()) @get:Internal - val graalDownloadFileName = objectFactory.property().convention(createDownloadGraalFileName()) + val graalDownloadFileName = objectFactory.property().convention(createGraalFileName()) @get:OutputFile - val graalDownload: Provider = jdksDirectory.file(graalDownloadFileName) + protected val graalDownloadFileProperty: RegularFileProperty = project.objects.fileProperty().value(jdksDirectory.file(graalDownloadFileName)) + + @get:Internal + val graalDownloadFile: Provider = graalDownloadFileProperty + @TaskAction fun download() { URL(createDownloadUrl()).openStream().use { input -> - graalDownload.get().asFile.outputStream().use { output -> input.copyTo(output) } + graalDownloadFile.get().asFile.outputStream().use { output -> input.copyTo(output) } } } - private fun createDownloadGraalFileName(): Provider { - return createGraalFileName().map { graalFileName -> - "${graalFileName}.${getArchiveExtension()}" + private fun createGraalFolderName(): Provider { + return javaVersion.map { javaVersion -> + "graalvm-community-openjdk-${javaVersion}" } } private fun createGraalFileName(): Provider { - return javaVersion.zip(graalVersion) { javaVersion, graalVersion -> - "graalvm-ce-java${javaVersion}-${getOperatingSystem()}-${getArchitecture()}-${graalVersion}" + return javaVersion.map { javaVersion -> + "graalvm-community-jdk-${javaVersion}_${getOperatingSystem()}-${getArchitecture()}_bin.${getArchiveExtension()}" } } - private fun createGraalFolderName(): Provider { - return javaVersion.zip(graalVersion) { javaVersion, graalVersion -> - "graalvm-ce-java${javaVersion}-${graalVersion}" - } - } - - private fun createDownloadUrl(): String { - return "${downloadBaseUrl.get()}/vm-${graalVersion.get()}/" + createDownloadGraalFileName().get() - } + private fun createDownloadUrl() = "${downloadBaseUrl.get()}/jdk-${javaVersion.get()}/${createGraalFileName().get()}" private fun getOperatingSystem(): String { return if (DefaultNativePlatform.getCurrentOperatingSystem().isLinux) { @@ -83,7 +71,7 @@ abstract class DownloadGraalJVMTask @Inject constructor( } else if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows) { "windows" } else if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX) { - "darwin" + "macos" } else { throw IllegalStateException( "Unsupported operating system. (${DefaultNativePlatform.getCurrentOperatingSystem().displayName}" @@ -93,7 +81,7 @@ abstract class DownloadGraalJVMTask @Inject constructor( private fun getArchitecture(): String { return if (DefaultNativePlatform.getCurrentArchitecture().isAmd64) { - "amd64" + "x64" } else if (DefaultNativePlatform.getCurrentArchitecture().isArm) { "aarch64" } else if (DefaultNativePlatform.getCurrentArchitecture().name == "arm-v8") { //used for M1 Apple devices diff --git a/src/main/java/com/hivemq/cli/graal/BouncyCastleFeature.java b/src/main/java/com/hivemq/cli/graal/BouncyCastleFeature.java index b3c910f31..5ca1166db 100644 --- a/src/main/java/com/hivemq/cli/graal/BouncyCastleFeature.java +++ b/src/main/java/com/hivemq/cli/graal/BouncyCastleFeature.java @@ -16,7 +16,6 @@ package com.hivemq.cli.graal; -import com.oracle.svm.core.annotate.AutomaticFeature; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.graalvm.nativeimage.hosted.Feature; import org.jetbrains.annotations.Nullable;