diff --git a/gdk/buildSrc/src/main/groovy/gdk-cli.gradle b/gdk/buildSrc/src/main/groovy/gdk-cli.gradle new file mode 100644 index 0000000..e0235ea --- /dev/null +++ b/gdk/buildSrc/src/main/groovy/gdk-cli.gradle @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ + +plugins { + id 'gdk-module' + id 'io.micronaut.application' + id 'com.github.johnrengelman.shadow' +} + +dependencies { + annotationProcessor mnLibs.picocli.codegen + + compileOnly mnLibs.graal + + implementation projects.gdkCliCore + + runtimeOnly libs.bouncycastle.bcpkix + runtimeOnly libs.bouncycastle.bcprov + runtimeOnly libs.jansi + runtimeOnly libs.jline + runtimeOnly libs.slf4j.nop +} + +configurations.configureEach { + exclude module: 'logback-classic' +} + +micronaut { + version libs.micronaut.starter.api.get().version + processing { + incremental true + annotations 'cloud.graal.gdk.*' + } +} + +tasks.named('shadowJar') { + mergeServiceFiles() +} + +tasks.named('shadowDistZip') { + enabled = false +} +tasks.named('shadowDistTar') { + enabled = false +} + +tasks.register('copyShadowJar', Sync) { + from shadowJar.outputs + into "${project.rootProject.buildDir}/libs" + rename { String fileName -> 'cli.jar' } +} diff --git a/gdk/buildSrc/src/main/groovy/gdk-module-public.gradle b/gdk/buildSrc/src/main/groovy/gdk-module-public.gradle new file mode 100644 index 0000000..a672a30 --- /dev/null +++ b/gdk/buildSrc/src/main/groovy/gdk-module-public.gradle @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ + +plugins { + id 'gdk-module' + id 'com.diffplug.spotless' +} + +spotless { + java { + licenseHeaderFile rootProject.file('config/spotless.license.java') + target 'src/main/java/**' + targetExclude '**/*.rocker.raw', '**/GdkBaseCommand.java', '**/GdkStarter.java', '**/AbstractStarter.java' + } + format 'javaMisc', { + target 'src/main/**/package-info.java', 'src/main/**/module-info.java' + licenseHeaderFile rootProject.file('config/spotless.license.java'), '\\/\\*\\*' + } +} + diff --git a/gdk/buildSrc/src/main/groovy/gdk-module.gradle b/gdk/buildSrc/src/main/groovy/gdk-module.gradle index 4146a44..63f77bf 100644 --- a/gdk/buildSrc/src/main/groovy/gdk-module.gradle +++ b/gdk/buildSrc/src/main/groovy/gdk-module.gradle @@ -17,19 +17,6 @@ plugins { id 'gdk-base' id 'checkstyle' - id 'com.diffplug.spotless' -} - -spotless { - java { - licenseHeaderFile rootProject.file('config/spotless.license.java') - target 'src/main/java/**' - targetExclude '**/*.rocker.raw', '**/GdkBaseCommand.java', '**/GdkStarter.java' - } - format 'javaMisc', { - target 'src/main/**/package-info.java', 'src/main/**/module-info.java' - licenseHeaderFile rootProject.file('config/spotless.license.java'), '\\/\\*\\*' - } } publishing { diff --git a/gdk/buildSrc/src/main/groovy/gdk-testing.gradle b/gdk/buildSrc/src/main/groovy/gdk-testing.gradle new file mode 100644 index 0000000..1313487 --- /dev/null +++ b/gdk/buildSrc/src/main/groovy/gdk-testing.gradle @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ + +plugins { + id 'groovy' + id 'com.adarshr.test-logger' + id 'io.micronaut.library' +} + +micronaut { + testRuntime 'spock2' +} + +test { + maxHeapSize = '16G' +} + +testlogger { + theme 'standard-parallel' + showFullStackTraces true + showStandardStreams true + showPassedStandardStreams false + showSkippedStandardStreams false + showFailedStandardStreams true +} diff --git a/gdk/gdk-cli-core/README.adoc b/gdk/gdk-cli-core/README.adoc new file mode 100644 index 0000000..7cf0732 --- /dev/null +++ b/gdk/gdk-cli-core/README.adoc @@ -0,0 +1,3 @@ += gdk-cli-core + +This submodule is a reusable library contains most of the code for the CLI except for the main class and the build configuration to enable running the CLI. diff --git a/gdk/gdk-cli-core/build.gradle b/gdk/gdk-cli-core/build.gradle new file mode 100644 index 0000000..c273c48 --- /dev/null +++ b/gdk/gdk-cli-core/build.gradle @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ + +plugins { + id 'gdk-module-public' + id 'io.micronaut.library' +} + +dependencies { + annotationProcessor mnLibs.picocli.codegen + + // not in libs.versions.toml to keep Micronaut version in one place + api(libs.micronaut.starter.cli) { + exclude group: 'io.micronaut', module: 'micronaut-buffer-netty' + exclude group: 'io.micronaut', module: 'micronaut-http-client' + exclude group: 'io.micronaut', module: 'micronaut-http-client-core' + exclude group: 'io.micronaut', module: 'micronaut-http-netty' + exclude group: 'io.micronaut', module: 'micronaut-websocket' + exclude group: 'io.micronaut.testresources', module: 'micronaut-test-resources-build-tools' + exclude group: 'io.netty', module: 'netty-buffer' + exclude group: 'io.netty', module: 'netty-codec' + exclude group: 'io.netty', module: 'netty-codec-http' + exclude group: 'io.netty', module: 'netty-codec-http2' + exclude group: 'io.netty', module: 'netty-codec-socks' + exclude group: 'io.netty', module: 'netty-common' + exclude group: 'io.netty', module: 'netty-handler' + exclude group: 'io.netty', module: 'netty-handler-proxy' + exclude group: 'io.netty', module: 'netty-resolver' + exclude group: 'io.netty', module: 'netty-transport' + exclude group: 'io.swagger.core.v3', module: 'swagger-annotations' + exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit' + exclude group: 'org.jline', module: 'jline' + } + api mnLibs.micronaut.picocli + api mnLibs.picocli + api mnLibs.micronaut.jackson.databind + api mnLibs.micronaut.validation + api projects.gdkCore +} + +micronaut { + version libs.micronaut.starter.api.get().version + processing { + incremental true + annotations 'cloud.graal.gdk.*' + } +} diff --git a/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/AbstractStarter.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/AbstractStarter.java new file mode 100644 index 0000000..5b39fb5 --- /dev/null +++ b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/AbstractStarter.java @@ -0,0 +1,104 @@ +/* + * Copyright 2017-2022 original authors + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ +package cloud.graal.gdk; + +import cloud.graal.gdk.command.GdkBaseCommand; +import io.micronaut.context.ApplicationContext; +import io.micronaut.context.BeanContext; +import io.micronaut.inject.BeanDefinition; +import io.micronaut.starter.cli.CodeGenConfig; +import io.micronaut.starter.cli.InteractiveShell; +import io.micronaut.starter.cli.MicronautFactory; +import io.micronaut.starter.cli.command.CodeGenCommand; +import io.micronaut.starter.io.ConsoleOutput; +import picocli.CommandLine; +import picocli.CommandLine.ParameterException; + +import java.util.function.BiFunction; + +/** + * Base class for CLI main classes. Starts an interactive shell if passed no + * arguments, otherwise instantiates the requested command class. + *

+ * Based on io.micronaut.starter.cli.MicronautStarter. + */ +public abstract class AbstractStarter extends GdkBaseCommand { + + protected static final BiFunction EXCEPTION_HANDLER = (e, commandLine) -> { + GdkBaseCommand command = commandLine.getCommand(); + command.err(e.getMessage()); + if (command.showStacktrace()) { + e.printStackTrace(commandLine.getErr()); + } + return 1; + }; + + protected boolean interactiveShell = false; + + protected CommandLine createCommandLine() { + boolean noOpConsole = interactiveShell; + try (BeanContext beanContext = ApplicationContext.builder().deduceEnvironment(false).start()) { + return createCommandLine(beanContext, noOpConsole); + } + } + + protected int execute(String[] args) { + boolean noOpConsole = args.length > 0 && args[0].startsWith("update-cli-config"); + try (BeanContext beanContext = ApplicationContext.builder().deduceEnvironment(false).start()) { + return createCommandLine(beanContext, noOpConsole).execute(args); + } + } + + protected CommandLine createCommandLine(BeanContext beanContext, boolean noOpConsole) { + CommandLine commandLine = new CommandLine(this, new MicronautFactory(beanContext)); + commandLine.setExecutionExceptionHandler((ex, commandLine1, parseResult) -> EXCEPTION_HANDLER.apply(ex, commandLine1)); + commandLine.setUsageHelpWidth(100); + + addCodegenCommands(beanContext, noOpConsole, commandLine); + + return commandLine; + } + + protected void addCodegenCommands(BeanContext beanContext, boolean noOpConsole, CommandLine commandLine) { + CodeGenConfig codeGenConfig = CodeGenConfig.load(beanContext, noOpConsole ? ConsoleOutput.NOOP : this); + if (codeGenConfig != null) { + beanContext.getBeanDefinitions(CodeGenCommand.class).stream() + .map(BeanDefinition::getBeanType) + .map(bt -> beanContext.createBean(bt, codeGenConfig)) + .filter(CodeGenCommand::applies) + .forEach(commandLine::addSubcommand); + } + } + + /** + * @return the name of the cli, for use in the interactive shell. + */ + protected String getCliName() { + return "gdk"; + } + + protected void startShell() { + CommandLine commandLine = createCommandLine(); + interactiveShell = true; + new InteractiveShell(commandLine, this::execute, EXCEPTION_HANDLER, "@|blue " + getCliName() + ">|@ ").start(); + } + + @Override + public Integer call() { + throw new ParameterException(spec.commandLine(), "No command specified"); + } +} diff --git a/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/AbstractExternalCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/AbstractExternalCommand.java new file mode 100644 index 0000000..9c5c344 --- /dev/null +++ b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/AbstractExternalCommand.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ +package cloud.graal.gdk.command; + +/** + * Convenience base class for external commands. + */ +public abstract class AbstractExternalCommand extends GdkBaseCommand implements ExternalCommand { +} diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/CloudTypeConverter.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/CloudTypeConverter.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/CloudTypeConverter.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/CloudTypeConverter.java diff --git a/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/ExternalCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/ExternalCommand.java new file mode 100644 index 0000000..6740553 --- /dev/null +++ b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/ExternalCommand.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ +package cloud.graal.gdk.command; + +/** + * Marker interface for addon commands, e.g. extensions created by users. + */ +public interface ExternalCommand { +} diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkBaseCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkBaseCommand.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkBaseCommand.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkBaseCommand.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCommonOptionsMixin.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCommonOptionsMixin.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCommonOptionsMixin.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCommonOptionsMixin.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateAppCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateAppCommand.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateAppCommand.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateAppCommand.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateCommand.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateCommand.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateCommand.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateFunctionCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateFunctionCommand.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateFunctionCommand.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateFunctionCommand.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateGatewayFunctionCommand.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateGatewayFunctionCommand.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/GdkCreateGatewayFunctionCommand.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/GdkCreateGatewayFunctionCommand.java diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/ServiceTypeConverter.java b/gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/ServiceTypeConverter.java similarity index 100% rename from gdk/gdk-cli/src/main/java/cloud/graal/gdk/command/ServiceTypeConverter.java rename to gdk/gdk-cli-core/src/main/java/cloud/graal/gdk/command/ServiceTypeConverter.java diff --git a/gdk/gdk-cli/src/main/resources/micronaut-starter-cli/resource-config.json b/gdk/gdk-cli-core/src/main/resources/micronaut-starter-cli/resource-config.json similarity index 100% rename from gdk/gdk-cli/src/main/resources/micronaut-starter-cli/resource-config.json rename to gdk/gdk-cli-core/src/main/resources/micronaut-starter-cli/resource-config.json diff --git a/gdk/gdk-cli/src/main/resources/org/fusesource/jansi/jansi.properties b/gdk/gdk-cli-core/src/main/resources/org/fusesource/jansi/jansi.properties similarity index 100% rename from gdk/gdk-cli/src/main/resources/org/fusesource/jansi/jansi.properties rename to gdk/gdk-cli-core/src/main/resources/org/fusesource/jansi/jansi.properties diff --git a/gdk/gdk-cli/README.adoc b/gdk/gdk-cli/README.adoc index 9cb3662..b1eb1c9 100644 --- a/gdk/gdk-cli/README.adoc +++ b/gdk/gdk-cli/README.adoc @@ -1,6 +1,6 @@ = gdk-cli -This submodule generates the GDK CLI application which is compiled to a native executable `gdk`, which works similarly to the Micronaut `mn` CLI with the addition of being able to generate GDK applications by specifying clouds and services. +This submodule generates the GDK CLI application which is compiled to a native executable `gdk`, which works similarly to the Micronaut `mn` CLI with the addition of being able to generate GDK applications by specifying clouds and services. It depends on the `gdk-cli-core` submodule which contains most of the code. == GdkStarter diff --git a/gdk/gdk-cli/build.gradle b/gdk/gdk-cli/build.gradle index 5320a76..790317c 100644 --- a/gdk/gdk-cli/build.gradle +++ b/gdk/gdk-cli/build.gradle @@ -15,66 +15,14 @@ */ plugins { - id 'gdk-module' - id 'io.micronaut.application' - id 'com.github.johnrengelman.shadow' -} - -dependencies { - annotationProcessor mnLibs.picocli.codegen - - compileOnly mnLibs.graal - - // not in libs.versions.toml to keep Micronaut version in 1 place (micronautVersion.txt) - implementation(libs.micronaut.starter.cli) { - exclude group: 'io.micronaut', module: 'micronaut-buffer-netty' - exclude group: 'io.micronaut', module: 'micronaut-http-client' - exclude group: 'io.micronaut', module: 'micronaut-http-client-core' - exclude group: 'io.micronaut', module: 'micronaut-http-netty' - exclude group: 'io.micronaut', module: 'micronaut-websocket' - exclude group: 'io.micronaut.testresources', module: 'micronaut-test-resources-build-tools' - exclude group: 'io.netty', module: 'netty-buffer' - exclude group: 'io.netty', module: 'netty-codec' - exclude group: 'io.netty', module: 'netty-codec-http' - exclude group: 'io.netty', module: 'netty-codec-http2' - exclude group: 'io.netty', module: 'netty-codec-socks' - exclude group: 'io.netty', module: 'netty-common' - exclude group: 'io.netty', module: 'netty-handler' - exclude group: 'io.netty', module: 'netty-handler-proxy' - exclude group: 'io.netty', module: 'netty-resolver' - exclude group: 'io.netty', module: 'netty-transport' - exclude group: 'io.swagger.core.v3', module: 'swagger-annotations' - exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit' - exclude group: 'org.jline', module: 'jline' - } - runtimeOnly libs.bouncycastle.bcpkix - runtimeOnly libs.bouncycastle.bcprov - runtimeOnly libs.jansi - runtimeOnly libs.jline - runtimeOnly libs.slf4j.nop - implementation mnLibs.micronaut.jackson.databind - implementation mnLibs.micronaut.picocli - implementation mnLibs.micronaut.validation - implementation mnLibs.picocli - implementation projects.gdkCore -} - -configurations.all { - exclude module: 'logback-classic' + id 'gdk-cli' + id 'gdk-module-public' } application { mainClass.set 'cloud.graal.gdk.GdkStarter' } -micronaut { - version libs.micronaut.starter.api.get().version - processing { - incremental true - annotations 'cloud.graal.gdk.*' - } -} - graalvmNative { binaries { main { @@ -86,20 +34,3 @@ graalvmNative { startScripts { applicationName = 'gdk' } - -tasks.named('shadowJar') { - mergeServiceFiles() -} - -tasks.named('shadowDistZip') { - enabled = false -} -tasks.named('shadowDistTar') { - enabled = false -} - -tasks.register('copyShadowJar', Sync) { - from shadowJar.outputs - into "${project.rootProject.buildDir}/libs" - rename { String fileName -> 'cli.jar' } -} diff --git a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/GdkStarter.java b/gdk/gdk-cli/src/main/java/cloud/graal/gdk/GdkStarter.java index 8ab8eec..de15231 100644 --- a/gdk/gdk-cli/src/main/java/cloud/graal/gdk/GdkStarter.java +++ b/gdk/gdk-cli/src/main/java/cloud/graal/gdk/GdkStarter.java @@ -16,33 +16,20 @@ */ package cloud.graal.gdk; -import cloud.graal.gdk.command.GdkBaseCommand; import cloud.graal.gdk.command.GdkCommonOptionsMixin; import cloud.graal.gdk.command.GdkCreateAppCommand; import cloud.graal.gdk.command.GdkCreateFunctionCommand; import cloud.graal.gdk.command.GdkCreateGatewayFunctionCommand; -import io.micronaut.context.ApplicationContext; -import io.micronaut.context.BeanContext; import io.micronaut.context.annotation.Prototype; import io.micronaut.core.annotation.TypeHint; -import io.micronaut.inject.BeanDefinition; -import io.micronaut.starter.cli.CodeGenConfig; -import io.micronaut.starter.cli.InteractiveShell; -import io.micronaut.starter.cli.MicronautFactory; import io.micronaut.starter.cli.command.BuildToolCandidates; import io.micronaut.starter.cli.command.BuildToolConverter; -import io.micronaut.starter.cli.command.CodeGenCommand; import io.micronaut.starter.cli.command.LanguageCandidates; import io.micronaut.starter.cli.command.LanguageConverter; import io.micronaut.starter.cli.command.TestFrameworkCandidates; import io.micronaut.starter.cli.command.TestFrameworkConverter; import io.micronaut.starter.cli.feature.acme.AcmeServerOption; -import io.micronaut.starter.io.ConsoleOutput; -import picocli.CommandLine; import picocli.CommandLine.Command; -import picocli.CommandLine.ParameterException; - -import java.util.function.BiFunction; /** * The main class for the library. Starts an interactive shell if passed no @@ -79,20 +66,9 @@ AcmeServerOption.class }) @Prototype -public class GdkStarter extends GdkBaseCommand { +public class GdkStarter extends AbstractStarter { // TODO disable commands create-test / create-command / feature-diff / create-bean / create-job - private static boolean interactiveShell = false; - - private static final BiFunction EXCEPTION_HANDLER = (e, commandLine) -> { - GdkBaseCommand command = commandLine.getCommand(); - command.err(e.getMessage()); - if (command.showStacktrace()) { - e.printStackTrace(commandLine.getErr()); - } - return 1; - }; - /** * Entry point for the CLI. Starts an interactive shell if passed no * arguments, otherwise instantiates the requested command class and @@ -102,54 +78,12 @@ public class GdkStarter extends GdkBaseCommand { */ public static void main(String[] args) { GdkUtils.configureJdkVersions(); + GdkStarter starter = new GdkStarter(); if (args.length == 0) { // The first command line isn't technically in the shell yet so this is called before setting the static flag - startShell(); + starter.startShell(); } else { - System.exit(execute(args)); - } - } - - private static CommandLine createCommandLine() { - boolean noOpConsole = GdkStarter.interactiveShell; - try (BeanContext beanContext = ApplicationContext.builder().deduceEnvironment(false).start()) { - return createCommandLine(beanContext, noOpConsole); - } - } - - private static int execute(String[] args) { - boolean noOpConsole = args.length > 0 && args[0].startsWith("update-cli-config"); - try (BeanContext beanContext = ApplicationContext.builder().deduceEnvironment(false).start()) { - return createCommandLine(beanContext, noOpConsole).execute(args); + System.exit(starter.execute(args)); } } - - private static CommandLine createCommandLine(BeanContext beanContext, boolean noOpConsole) { - GdkStarter starter = beanContext.getBean(GdkStarter.class); - CommandLine commandLine = new CommandLine(starter, new MicronautFactory(beanContext)); - commandLine.setExecutionExceptionHandler((ex, commandLine1, parseResult) -> EXCEPTION_HANDLER.apply(ex, commandLine1)); - commandLine.setUsageHelpWidth(100); - - CodeGenConfig codeGenConfig = CodeGenConfig.load(beanContext, noOpConsole ? ConsoleOutput.NOOP : starter); - if (codeGenConfig != null) { - beanContext.getBeanDefinitions(CodeGenCommand.class).stream() - .map(BeanDefinition::getBeanType) - .map(bt -> beanContext.createBean(bt, codeGenConfig)) - .filter(CodeGenCommand::applies) - .forEach(commandLine::addSubcommand); - } - - return commandLine; - } - - private static void startShell() { - CommandLine commandLine = createCommandLine(); - GdkStarter.interactiveShell = true; - new InteractiveShell(commandLine, GdkStarter::execute, EXCEPTION_HANDLER, "@|blue gdk>|@ ").start(); - } - - @Override - public Integer call() { - throw new ParameterException(spec.commandLine(), "No command specified"); - } } diff --git a/gdk/gdk-core/build.gradle b/gdk/gdk-core/build.gradle index 95be116..c1e3d37 100644 --- a/gdk/gdk-core/build.gradle +++ b/gdk/gdk-core/build.gradle @@ -15,7 +15,7 @@ */ plugins { - id 'gdk-module' + id 'gdk-module-public' id 'gdk.rocker' id 'gdk-dependencies' id 'io.micronaut.library' @@ -44,6 +44,19 @@ dependencies { exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit' } implementation(mnLibs.micronaut.http.client) + implementation(libs.boms.netty) + implementation(libs.netty.buffer) + implementation(libs.netty.codec.http) + implementation(libs.netty.codec.http2) + implementation(libs.netty.common) + implementation(libs.netty.incubator.codec.http3) + implementation(libs.netty.handler) + implementation(libs.netty.handler.proxy) + implementation(libs.netty.transport.native.epoll) + implementation(libs.netty.transport.native.kqueue) + implementation(libs.netty.transport.native.iouring) + implementation(libs.netty.transport.native.unix.common) + implementation(libs.netty.tcnative.boringssl.static) } def writeVersions = tasks.register('writeVersions', cloud.graal.gdk.util.WriteVersionsTask) { diff --git a/gdk/gdk-core/src/main/java/cloud/graal/gdk/feature/replaced/GdkMicronautBuildPlugin.java b/gdk/gdk-core/src/main/java/cloud/graal/gdk/feature/replaced/GdkMicronautBuildPlugin.java new file mode 100644 index 0000000..2b9a3f7 --- /dev/null +++ b/gdk/gdk-core/src/main/java/cloud/graal/gdk/feature/replaced/GdkMicronautBuildPlugin.java @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Oracle and/or its affiliates + * + * 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 + * + * https://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. + */ +package cloud.graal.gdk.feature.replaced; + +import io.micronaut.context.annotation.Replaces; +import io.micronaut.starter.application.ApplicationType; +import io.micronaut.starter.application.generator.GeneratorContext; +import io.micronaut.starter.build.dependencies.CoordinateResolver; +import io.micronaut.starter.feature.build.MicronautBuildPlugin; +import io.micronaut.starter.feature.build.gradle.Dockerfile; +import io.micronaut.starter.feature.build.gradle.MicronautApplicationGradlePlugin; +import io.micronaut.starter.feature.function.awslambda.AwsLambda; +import io.micronaut.starter.options.JdkVersion; +import jakarta.inject.Singleton; + +import static io.micronaut.starter.feature.graalvm.GraalVM.FEATURE_NAME_GRAALVM; + +/** + * Fix MicronautBuildPlugin by removing baseImage from build.gradle. + * + * @since 4.7 + */ +@Replaces(MicronautBuildPlugin.class) +@Singleton +public class GdkMicronautBuildPlugin extends MicronautBuildPlugin { + + public GdkMicronautBuildPlugin(CoordinateResolver coordinateResolver) { + super(coordinateResolver); + } + + @Override + protected MicronautApplicationGradlePlugin.Builder micronautGradleApplicationPluginBuilder(GeneratorContext generatorContext) { + MicronautApplicationGradlePlugin.Builder builder = micronautGradleApplicationPluginBuilder(generatorContext, MicronautApplicationGradlePlugin.Builder.APPLICATION); + if (generatorContext.getFeatures().contains(AwsLambda.FEATURE_NAME_AWS_LAMBDA) && ( + (generatorContext.getApplicationType() == ApplicationType.FUNCTION && generatorContext.getFeatures().contains(FEATURE_NAME_GRAALVM)) || + (generatorContext.getApplicationType() == ApplicationType.DEFAULT))) { + builder.dockerNative(Dockerfile.builder() + .javaVersion(generatorContext.getJdkVersion().asString()) + .arg("-XX:MaximumHeapSizePercent=80") + .arg("-Dio.netty.allocator.numDirectArenas=0") + .arg("-Dio.netty.noPreferDirect=true") + .build()); + } else if (generatorContext.getJdkVersion() != JdkVersion.JDK_17) { + builder.dockerNative(Dockerfile.builder().javaVersion(generatorContext.getJdkVersion().asString()).build()); + } + return builder; + } + +} diff --git a/gdk/gdk-core/src/main/java/cloud/graal/gdk/model/GdkCloud.java b/gdk/gdk-core/src/main/java/cloud/graal/gdk/model/GdkCloud.java index c58de07..c0547e6 100644 --- a/gdk/gdk-core/src/main/java/cloud/graal/gdk/model/GdkCloud.java +++ b/gdk/gdk-core/src/main/java/cloud/graal/gdk/model/GdkCloud.java @@ -52,13 +52,18 @@ public enum GdkCloud { */ NONE(null, "", "NONE", ROOT, ""), + /** + * Used when all supported clouds is selected for testing, not used as supported option. + */ + ALL(null, "", "", "all", ""), + /** * For testing. */ TESTING("testing", "-testing", "TESTING", "testing", ""); private static final GdkCloud[] SUPPORTED = Arrays.stream(values()) - .filter(c -> c != GdkCloud.TESTING && c != GdkCloud.NONE) + .filter(c -> c != GdkCloud.TESTING && c != GdkCloud.ALL && c != GdkCloud.NONE) .toArray(GdkCloud[]::new); private final String environmentName; diff --git a/gdk/gdk-core/src/main/java/cloud/graal/gdk/template/MavenPomPostProcessor.java b/gdk/gdk-core/src/main/java/cloud/graal/gdk/template/MavenPomPostProcessor.java index d5ea674..5f73081 100644 --- a/gdk/gdk-core/src/main/java/cloud/graal/gdk/template/MavenPomPostProcessor.java +++ b/gdk/gdk-core/src/main/java/cloud/graal/gdk/template/MavenPomPostProcessor.java @@ -101,13 +101,6 @@ public String process(@NonNull String pom) { if (libModule) { pom = fixArtifactId(pom); pom = fixProcessingModule(pom); - } else { - if (applicationType == ApplicationType.DEFAULT && !isGatewayFunction) { - pom = addDefaultDockerImageName(pom); - } - } - if (libModule || cloud != GdkCloud.NONE) { - pom = fixName(pom); } return pom; @@ -139,10 +132,6 @@ private String fixParent(@NonNull String pom) { return top + parent + bottom; } - private String fixName(@NonNull String pom) { - return pom.replace("${packaging}", "${packaging}\n " + artifactId + "-${project.artifactId}"); - } - @NonNull private String fixVersion(@NonNull String pom) { return pom.replaceFirst("0.1", "1.0-SNAPSHOT"); @@ -181,25 +170,6 @@ private String fixProcessingModule(@NonNull String pom) { return top + LIB_MODULE + bottom; } - @NonNull - private String addDefaultDockerImageName(@NonNull String pom) { - if (!pom.contains(PLUGINS_START)) { - return pom; - } - - pom = pom.replace(PLUGINS_START, PLUGINS_START + - " \n" + - " com.google.cloud.tools\n" + - " jib-maven-plugin\n" + - " \n" + - " \n" + - " ${project.name}\n" + - " \n" + - " \n" + - " \n"); - return pom; - } - @NonNull private String fixMicronautVersion(@NonNull String pom) { diff --git a/gdk/gradle/libs.versions.toml b/gdk/gradle/libs.versions.toml index a38613e..28156ca 100644 --- a/gdk/gradle/libs.versions.toml +++ b/gdk/gradle/libs.versions.toml @@ -23,6 +23,10 @@ jline = '3.26.3' logback = '1.5.8' micronaut-plugins = '4.4.2' micronaut-starter = '4.6.1' +netty = "4.1.115.Final" +netty-iouring = "0.0.25.Final" +netty-http3 = "0.0.28.Final" +netty-tcnative = "2.0.69.Final" reflections = '0.10.2' rocker = '1.4.0' shadow = '8.1.1' @@ -48,6 +52,19 @@ micronaut-application = { module = 'io.micronaut.gradle:micronaut-gradle-plugin' micronaut-library = { module = 'io.micronaut.gradle:micronaut-gradle-plugin', version.ref = 'micronaut-plugins' } micronaut-starter-api = { module = 'io.micronaut.starter:micronaut-starter-api', version.ref = 'micronaut-starter' } micronaut-starter-cli = { module = 'io.micronaut.starter:micronaut-cli', version.ref = 'micronaut-starter' } +boms-netty = { module = "io.netty:netty-bom", version.ref = "netty" } +netty-buffer = { module = "io.netty:netty-buffer", version.ref = "netty" } +netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" } +netty-codec-http2 = { module = "io.netty:netty-codec-http2", version.ref = "netty" } +netty-common = { module = "io.netty:netty-common", version.ref = "netty" } +netty-incubator-codec-http3 = { module = "io.netty.incubator:netty-incubator-codec-http3", version.ref = "netty-http3" } +netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" } +netty-handler-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" } +netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" } +netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" } +netty-transport-native-iouring = { module = "io.netty.incubator:netty-incubator-transport-native-io_uring", version.ref = "netty-iouring" } +netty-transport-native-unix-common = { module = "io.netty:netty-transport-native-unix-common", version.ref = "netty" } +netty-tcnative-boringssl-static = { module = "io.netty:netty-tcnative-boringssl-static", version.ref = "netty-tcnative" } reflections = { module = 'org.reflections:reflections', version.ref = 'reflections' } rocker = { module = 'com.fizzed:rocker-compiler', version.ref = 'rocker' } shadow = { module = 'com.github.johnrengelman:shadow', version.ref = 'shadow' } diff --git a/gdk/gradle/templates.versions.toml b/gdk/gradle/templates.versions.toml index 238d482..b3aa1a6 100644 --- a/gdk/gradle/templates.versions.toml +++ b/gdk/gradle/templates.versions.toml @@ -26,17 +26,17 @@ io-spring-gradle-dependency-management-plugin = "1.1.6" kotlin = "1.8.22" logback = "1.5.8" micronaut-cache = "5.0.1-oracle-00001" -micronaut-core = "4.6.5-oracle-00001" +micronaut-core = "4.6.8-oracle-00001" micronaut-data = "4.9.2-oracle-00001" micronaut-discovery = "4.4.0-oracle-00001" micronaut-email = "2.6.0-oracle-00001" micronaut-flyway = "7.4.0-oracle-00001" -micronaut-gradle-plugin = "4.4.2" +micronaut-gradle-plugin = "4.4.4" micronaut-jaxrs = "4.6.0-oracle-00001" micronaut-kafka = "5.6.0-oracle-00001" micronaut-kubernetes = "6.1.0-oracle-00001" micronaut-liquibase = "6.5.0-oracle-00001" -micronaut-maven-plugin = "4.6.3" +micronaut-maven-plugin = "4.7.0" micronaut-maven-test-resources-plugin = "2.6.0" micronaut-micrometer = "5.8.0-oracle-00001" micronaut-mongo = "5.4.0-oracle-00001" @@ -53,6 +53,8 @@ micronaut-sql = "5.8.1-oracle-00001" micronaut-tracing = "6.8.0-oracle-00001" micronaut-validation = "4.7.0-oracle-00001" micronaut-views = "5.5.0-oracle-00001" +netty = "4.1.115.Final" +netty-tcnative = "2.0.69.Final" okhttp = "4.12.0" opentelemetry-semconv = "1.30.1-alpha" org-springframework-boot-spring-boot-starter-parent = "3.3.3" @@ -137,6 +139,17 @@ io-micronaut-tracing-micronaut-tracing-bom = { module = 'io.micronaut.tracing:mi io-micronaut-validation-micronaut-validation-bom = { module = 'io.micronaut.validation:micronaut-validation-bom', version.ref = 'micronaut-validation'} io-micronaut-views-micronaut-views-core = { module = 'io.micronaut.views:micronaut-views-core', version.ref = 'micronaut-views'} io-micronaut-views-micronaut-views-jte = { module = 'io.micronaut.views:micronaut-views-jte', version.ref = 'micronaut-views'} +boms-netty = { module = "io.netty:netty-bom", version.ref = "netty" } +netty-buffer = { module = "io.netty:netty-buffer", version.ref = "netty" } +netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" } +netty-codec-http2 = { module = "io.netty:netty-codec-http2", version.ref = "netty" } +netty-common = { module = "io.netty:netty-common", version.ref = "netty" } +netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" } +netty-handler-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" } +netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" } +netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" } +netty-transport-native-unix-common = { module = "io.netty:netty-transport-native-unix-common", version.ref = "netty" } +netty-tcnative-boringssl-static = { module = "io.netty:netty-tcnative-boringssl-static", version.ref = "netty-tcnative" } io-opentelemetry-opentelemetry-semconv = { module = 'io.opentelemetry:opentelemetry-semconv', version.ref = 'opentelemetry-semconv'} org-apache-commons-commons-compress = { module = 'org.apache.commons:commons-compress', version.ref = 'apache-commons-compress'} org-bouncycastle-bcpkix-jdk15to18 = { module = 'org.bouncycastle:bcpkix-jdk15to18', version.ref = 'bouncycastle'}