From 2013ebba69d999a7b5cbefac29ca214bfaa73d1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A5le=20Pedersen?= Date: Thu, 28 Mar 2019 15:10:31 +0100 Subject: [PATCH] updated the cli to work similar as the maven and gradle tools --- bom/runtime/pom.xml | 2 +- devtools/aesh/pom.xml | 75 +++++++- devtools/aesh/reflectconfigs/quarkuscli.json | 23 ++- .../main/java/io/quarkus/cli/QuarkusCli.java | 58 +----- .../cli/commands/AddExtensionCommand.java | 75 -------- .../cli/commands/AddExtensionsCommand.java | 78 +++++++++ .../cli/commands/BuildToolConverter.java | 17 ++ .../cli/commands/CompileProjectCommand.java | 71 ++++++++ .../cli/commands/CreateProjectCommand.java | 165 ++++++++++++++---- .../quarkus/cli/commands/DevModeCommand.java | 160 +++++++++++++++++ .../cli/commands/DevModeDebugCompleter.java | 23 +++ .../cli/commands/DevModeDebugValidator.java | 22 +++ .../io/quarkus/cli/commands/ExecuteUtil.java | 135 ++++++++++++++ .../cli/commands/ExtensionCompleter.java | 30 ++++ .../quarkus/cli/commands/ExtensionFormat.java | 26 +++ .../quarkus/cli/commands/FormatCompleter.java | 21 +++ .../quarkus/cli/commands/FormatConverter.java | 15 ++ .../cli/commands/ListExtensionsCommand.java | 49 +++--- .../cli/commands/ProjectTypeCompleter.java | 27 +++ .../cli/commands/QuarkusBaseCommand.java | 49 ++++++ .../quarkus/cli/commands/QuarkusCommand.java | 28 --- .../devtools/commands/CreateProject.java | 1 + .../quarkus/devtools/project/BuildTool.java | 13 ++ 23 files changed, 943 insertions(+), 220 deletions(-) delete mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionCommand.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionsCommand.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/BuildToolConverter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/CompileProjectCommand.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeCommand.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugCompleter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugValidator.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/ExecuteUtil.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionCompleter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionFormat.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatCompleter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatConverter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/ProjectTypeCompleter.java create mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusBaseCommand.java delete mode 100644 devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusCommand.java diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml index df41d6eb5fd87..f227657bfc60c 100644 --- a/bom/runtime/pom.xml +++ b/bom/runtime/pom.xml @@ -14,7 +14,7 @@ pom - 1.11 + 2.5 2.1.3.Final 4.5.3.Final 0.31.0 diff --git a/devtools/aesh/pom.xml b/devtools/aesh/pom.xml index 0734633276b37..5aa72fc640fec 100644 --- a/devtools/aesh/pom.xml +++ b/devtools/aesh/pom.xml @@ -20,24 +20,85 @@ 1.8 + + + + io.quarkus + quarkus-bootstrap-core + io.quarkus quarkus-devtools-common - ${project.version} + + io.quarkus + quarkus-development-mode-spi + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-platform-descriptor-json + + + io.quarkus + quarkus-platform-descriptor-resolver-json + + + + org.aesh aesh + + org.junit.jupiter junit-jupiter test + + org.apache.commons + commons-lang3 + + + org.apache.maven.shared + maven-invoker + + + + ${project.basedir}/../bom-descriptor-json/target + quarkus-bom-descriptor + false + + extensions.json + + + maven-surefire-plugin @@ -65,10 +126,21 @@ + + org.apache.maven.plugins maven-shade-plugin 3.2.0 + + + + + io.quarkus.cli.QuarkusCli + + + package @@ -78,6 +150,7 @@ + io.quarkus:quarkus-bom-descriptor-json org.fusesource.jansi:jansi org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-depchain junit:junit diff --git a/devtools/aesh/reflectconfigs/quarkuscli.json b/devtools/aesh/reflectconfigs/quarkuscli.json index a5bb70bb4167a..d6776a45129eb 100644 --- a/devtools/aesh/reflectconfigs/quarkuscli.json +++ b/devtools/aesh/reflectconfigs/quarkuscli.json @@ -6,7 +6,8 @@ "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ - { "name" : "help" } + { "name" : "extensions" }, + { "name" : "path" } ] }, { @@ -16,10 +17,13 @@ "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ - { "name" : "help" }, - { "name" : "artifactid" }, - { "name" : "groupid" }, + { "name" : "artifactId" }, + { "name" : "groupId" }, { "name" : "version" }, + { "name" : "className" }, + { "name" : "resourcePath" }, + { "name" : "buildTool" }, + { "name" : "extensions" }, { "name" : "path" } ] }, @@ -30,19 +34,22 @@ "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ - { "name" : "help" } + { "name" : "all" }, + { "name" : "format" }, + { "name" : "searchPattern" }, + { "name" : "path" } ] }, { - "name" : "io.quarkus.cli.commands.QuarkusCommand", + "name" : "io.quarkus.cli.commands.QuarkusBaseCommand", "allDeclaredConstructors" : true, "allPublicConstructors" : true, "allDeclaredMethods" : true, "allPublicMethods" : true, "fields" : [ - { "name" : "help" } + { "name" : "interactive" } ] - }, + }, { "name" : "org.aesh.command.impl.completer.BooleanOptionCompleter", "allDeclaredConstructors" : true, diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/QuarkusCli.java b/devtools/aesh/src/main/java/io/quarkus/cli/QuarkusCli.java index 97d3da8324c9c..1df2f522983de 100644 --- a/devtools/aesh/src/main/java/io/quarkus/cli/QuarkusCli.java +++ b/devtools/aesh/src/main/java/io/quarkus/cli/QuarkusCli.java @@ -1,59 +1,17 @@ package io.quarkus.cli; -import java.io.IOException; +import org.aesh.AeshRuntimeRunner; -import org.aesh.command.AeshCommandRuntimeBuilder; -import org.aesh.command.CommandException; -import org.aesh.command.CommandNotFoundException; -import org.aesh.command.CommandRuntime; -import org.aesh.command.impl.registry.AeshCommandRegistryBuilder; -import org.aesh.command.parser.CommandLineParserException; -import org.aesh.command.registry.CommandRegistryException; -import org.aesh.command.validator.CommandValidatorException; -import org.aesh.command.validator.OptionValidatorException; - -import io.quarkus.cli.commands.QuarkusCommand; +import io.quarkus.cli.commands.QuarkusBaseCommand; public class QuarkusCli { - public static void main(String[] args) throws CommandRegistryException { - CommandRuntime runtime = AeshCommandRuntimeBuilder - .builder() - .commandRegistry(AeshCommandRegistryBuilder.builder().command(QuarkusCommand.class).create()) - .build(); - - if (args.length > 0) { - StringBuilder sb = new StringBuilder(QuarkusCommand.COMMAND_NAME).append(" "); - if (args.length == 1) { - sb.append(args[0]); - } else { - for (String arg : args) { - if (arg.indexOf(' ') >= 0) { - sb.append('"').append(arg).append("\" "); - } else { - sb.append(arg).append(' '); - } - } - } - - try { - runtime.executeCommand(sb.toString()); - } catch (CommandNotFoundException e) { - System.err.println("Command not found: " + sb.toString()); - } catch (CommandException | CommandLineParserException | CommandValidatorException | OptionValidatorException e) { - showHelpIfNeeded(runtime, e); - } catch (InterruptedException | IOException e) { - System.err.println(e.getMessage()); - } - } else { - showHelpIfNeeded(runtime, null); - } + public static void main(String[] args) { + AeshRuntimeRunner.builder() + .command(QuarkusBaseCommand.class) + .args(args) + .interactive(true) + .execute(); } - private static void showHelpIfNeeded(CommandRuntime runtime, Exception e) { - if (e != null) { - System.err.println(e.getMessage()); - } - System.err.println(runtime.commandInfo(QuarkusCommand.COMMAND_NAME)); - } } diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionCommand.java deleted file mode 100644 index 60d491fcddf4f..0000000000000 --- a/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionCommand.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.quarkus.cli.commands; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.List; - -import org.aesh.command.Command; -import org.aesh.command.CommandDefinition; -import org.aesh.command.CommandException; -import org.aesh.command.CommandResult; -import org.aesh.command.invocation.CommandInvocation; -import org.aesh.command.option.Argument; -import org.aesh.command.option.Option; -import org.aesh.io.Resource; - -import io.quarkus.dependencies.Extension; -import io.quarkus.devtools.commands.AddExtensions; -import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; -import io.quarkus.devtools.project.QuarkusProject; -import io.quarkus.platform.descriptor.QuarkusPlatformDescriptor; -import io.quarkus.platform.tools.config.QuarkusPlatformConfig; - -/** - * @author Ståle Pedersen - */ -@CommandDefinition(name = "add-extension", description = "Adds extensions to a project") -public class AddExtensionCommand implements Command { - - @Option(shortName = 'h', hasValue = false, overrideRequired = true) - private boolean help; - - @Option(shortName = 'e', required = true, description = "Name of the extension that will be added to the project") - private String extension; - - @Argument(description = "path to the project", required = true) - private Resource path; - - @Override - public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException { - if (help) { - commandInvocation.println(commandInvocation.getHelpInfo("quarkus add-extension")); - return CommandResult.SUCCESS; - } else { - - final QuarkusPlatformDescriptor platformDescr = QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor(); - if (!findExtension(extension, platformDescr.getExtensions())) { - commandInvocation.println("Can not find any extension named: " + extension); - return CommandResult.SUCCESS; - } - try { - final Path projectPath = Paths.get(path.getAbsolutePath()); - AddExtensions project = new AddExtensions(QuarkusProject.resolveExistingProject(projectPath, - platformDescr)).extensions(Collections.singleton(extension)); - QuarkusCommandOutcome result = project.execute(); - if (!result.isSuccess()) { - throw new CommandException("Unable to add an extension matching " + extension); - } - } catch (Exception e) { - throw new CommandException("Unable to add an extension matching " + extension, e); - } - } - - return CommandResult.SUCCESS; - } - - private boolean findExtension(String name, List extensions) { - for (Extension ext : extensions) { - if (ext.getName().equalsIgnoreCase(name)) { - return true; - } - } - return false; - } -} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionsCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionsCommand.java new file mode 100644 index 0000000000000..578e390028855 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/AddExtensionsCommand.java @@ -0,0 +1,78 @@ +package io.quarkus.cli.commands; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.aesh.command.Command; +import org.aesh.command.CommandDefinition; +import org.aesh.command.CommandException; +import org.aesh.command.CommandResult; +import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.option.Arguments; +import org.aesh.command.option.Option; +import org.aesh.io.Resource; +import org.aesh.selector.MultiSelect; + +import io.quarkus.dependencies.Extension; +import io.quarkus.devtools.commands.AddExtensions; +import io.quarkus.devtools.commands.data.QuarkusCommandException; +import io.quarkus.devtools.commands.data.QuarkusCommandOutcome; +import io.quarkus.devtools.project.QuarkusProject; +import io.quarkus.platform.tools.config.QuarkusPlatformConfig; + +@CommandDefinition(name = "add", description = "Install extensions to a project") +public class AddExtensionsCommand implements Command { + + @Option(shortName = 'p', description = "Path to the project, if not set it will use the current working directory") + private Resource path; + + @Arguments(completer = ExtensionCompleter.class, description = "Name of the extension that will be added to the project") + private Set extensions; + + @Override + public CommandResult execute(CommandInvocation invocation) throws CommandException, InterruptedException { + + try { + Path projectDirectory = path != null ? Paths.get(path.getAbsolutePath()) + : Paths.get(System.getProperty("user.dir")); + + QuarkusProject quarkusProject = QuarkusProject.resolveExistingProject(projectDirectory, + QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()); + + AddExtensions project = new AddExtensions(quarkusProject); + //if extensions is not set, create a selector + if (extensions == null || extensions.isEmpty()) { + MultiSelect selector = new MultiSelect(invocation.getShell(), + getAllExtensions(quarkusProject).stream().map(Extension::getSimplifiedArtifactId) + .collect(Collectors.toList()), + "Select the extensions that will be added to your project"); + + extensions = new HashSet<>(selector.doSelect()); + } + project.extensions(extensions); + + QuarkusCommandOutcome result = project.execute(); + if (result.isSuccess()) { + invocation.println("Added " + extensions + " to the project."); + } else { + invocation.println("Unable to add an extension matching " + extensions); + } + } catch (QuarkusCommandException | IOException e) { + invocation.println("Unable to add an extension matching " + extensions + ": " + e.getMessage()); + } catch (IllegalStateException e) { + invocation.println("No build file in " + path + " found. Will not attempt to add any extensions."); + } + + return CommandResult.SUCCESS; + } + + private List getAllExtensions(QuarkusProject quarkusProject) throws IOException { + return quarkusProject.getPlatformDescriptor().getExtensions(); + } + +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/BuildToolConverter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/BuildToolConverter.java new file mode 100644 index 0000000000000..3927cfd191007 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/BuildToolConverter.java @@ -0,0 +1,17 @@ +package io.quarkus.cli.commands; + +import org.aesh.command.converter.Converter; +import org.aesh.command.converter.ConverterInvocation; +import org.aesh.command.validator.OptionValidatorException; + +import io.quarkus.devtools.project.BuildTool; + +public class BuildToolConverter implements Converter { + @Override + public BuildTool convert(ConverterInvocation invocation) throws OptionValidatorException { + if (invocation.getInput() != null && invocation.getInput().length() > 0) + return BuildTool.findTool(invocation.getInput()); + else + throw new OptionValidatorException(invocation.getInput() + " was not recognized as a supported build tool"); + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/CompileProjectCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/CompileProjectCommand.java new file mode 100644 index 0000000000000..2f45ebd6a6d79 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/CompileProjectCommand.java @@ -0,0 +1,71 @@ +package io.quarkus.cli.commands; + +import java.io.File; + +import org.aesh.command.Command; +import org.aesh.command.CommandDefinition; +import org.aesh.command.CommandException; +import org.aesh.command.CommandResult; +import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.option.Argument; +import org.aesh.command.option.Option; +import org.aesh.io.Resource; + +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; + +@CommandDefinition(name = "build", description = "Compiles the targeted project") +public class CompileProjectCommand implements Command { + @Option(name = "clean", hasValue = false, shortName = 'c', description = "Clean the project before compiling") + private boolean clean; + + @Argument(description = "Path to the project, if not set it will use the current working directory") + private Resource path; + + @Override + public CommandResult execute(CommandInvocation invocation) throws CommandException, InterruptedException { + + File projectPath = path != null ? new File(path.getAbsolutePath()) : new File(System.getProperty("user.dir")); + + BuildTool buildTool = QuarkusProject.resolveExistingProjectBuildTool(projectPath.toPath()); + + if (buildTool.getBuildFiles() != null && buildTool.getBuildFiles().length > 0) { + File buildFile = new File(buildTool.getBuildFiles()[0]); + + if (!buildFile.isFile()) { + invocation.println("Was not able to find a build file in: " + projectPath); + return CommandResult.FAILURE; + } + + try { + if (buildTool.equals(BuildTool.MAVEN)) { + File wrapper = ExecuteUtil.getMavenWrapper(projectPath.getAbsolutePath()); + if (wrapper != null) { + ExecuteUtil.executeWrapper(invocation, wrapper, "package"); + } else { + ExecuteUtil.executeMaven(projectPath, invocation, "package"); + } + + } + //do gradle + else { + File wrapper = ExecuteUtil.getGradleWrapper(projectPath.getAbsolutePath()); + if (wrapper != null) { + ExecuteUtil.executeWrapper(invocation, wrapper, "build"); + } else { + ExecuteUtil.executeGradle(projectPath, invocation, "build"); + } + } + } catch (InterruptedException i) { + invocation.println("Build was interrupted."); + return CommandResult.FAILURE; + } + + return CommandResult.SUCCESS; + } else { + invocation.println("Was not able to find a build file in: " + projectPath); + return CommandResult.FAILURE; + } + } + +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/CreateProjectCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/CreateProjectCommand.java index 8d8f84279e97d..3c88453e72304 100644 --- a/devtools/aesh/src/main/java/io/quarkus/cli/commands/CreateProjectCommand.java +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/CreateProjectCommand.java @@ -1,66 +1,163 @@ package io.quarkus.cli.commands; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.aesh.command.Command; import org.aesh.command.CommandDefinition; import org.aesh.command.CommandResult; import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.option.Argument; import org.aesh.command.option.Option; +import org.aesh.command.option.OptionList; +import org.aesh.command.shell.Shell; import org.aesh.io.Resource; +import org.aesh.readline.action.KeyAction; +import org.aesh.readline.terminal.Key; +import org.aesh.selector.MultiSelect; +import org.aesh.selector.SelectorType; +import org.aesh.terminal.utils.Config; +import org.apache.commons.lang3.StringUtils; +import io.quarkus.dependencies.Extension; +import io.quarkus.devtools.commands.AddExtensions; import io.quarkus.devtools.commands.CreateProject; +import io.quarkus.devtools.commands.data.QuarkusCommandException; +import io.quarkus.devtools.project.BuildTool; +import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.platform.tools.config.QuarkusPlatformConfig; -/** - * @author Ståle Pedersen - */ -@CommandDefinition(name = "create-project", description = "Creates a base Quarkus maven project") +@CommandDefinition(name = "create", generateHelp = true, description = "Creates a base Quarkus project") public class CreateProjectCommand implements Command { - @Option(shortName = 'h', hasValue = false) - private boolean help; + @Option(name = "groupid", shortName = 'g', defaultValue = "org.acme.quarkus.sample", askIfNotSet = true, description = "The groupId of the project") + private String groupId; - @Option(shortName = 'g', defaultValue = "org.acme") - private String groupid; + @Option(name = "artifactid", shortName = 'a', defaultValue = "my-quarkus-project", askIfNotSet = true, description = "The artifactId of the project (also often the name of the project") + private String artifactId; - @Option(shortName = 'a', defaultValue = "quarkus") - private String artifactid; - - @Option(shortName = 'v', defaultValue = "1.0.0-SNAPSHOT") + @Option(shortName = 'v', defaultValue = "1.0.0-SNAPSHOT", askIfNotSet = true, description = "Project version number") private String version; - @Option(shortName = 'p', description = "path for the project") + @Option(shortName = 'c', name = "classname", description = "Rest resource name, by default set to: groupId+artifactId+HelloResource") + private String className; + + @Option(shortName = 'p', name = "resourcepath", description = "Rest resource path, by default set to /hello") + private String resourcePath; + + @Option(shortName = 'b', selector = SelectorType.SELECT, completer = ProjectTypeCompleter.class, converter = BuildToolConverter.class, description = "Build tool type for the project") + private BuildTool buildTool; + + @OptionList(shortName = 'e', completer = ExtensionCompleter.class, description = "Extensions that will be added to the build file") + private Set extensions; + + @Argument(description = "Path to the new project, if not set it will use the current working directory") private Resource path; - public CommandResult execute(CommandInvocation commandInvocation) { - if (help) { - commandInvocation.println(commandInvocation.getHelpInfo("quarkus create-project")); - return CommandResult.SUCCESS; - } + public CommandResult execute(CommandInvocation invocation) { + try { + Path projectDirectory = path != null ? Paths.get(path.getAbsolutePath()) + : Paths.get(System.getProperty("user.dir")); + + if (className == null) { + invocation.print("Do you want to create a REST resource? (y/n) "); + KeyAction input = invocation.input(); + invocation.print(Config.getLineSeparator()); + if (input == Key.y) + processClassName(invocation.getShell()); + } + + Files.createDirectories(projectDirectory); + + final Map context = new HashMap<>(); + context.put("path", resourcePath); + boolean status = new CreateProject(projectDirectory, + QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()) + .groupId(groupId) + .artifactId(artifactId) + .version(version) + .buildTool(buildTool) + .className(className) + .doCreateProject(context); + + if ((extensions == null || extensions.isEmpty()) && status) { + //ask if the user want to add any extensions + try { + invocation.print("Do you want to add any extensions in addition to rest? (y/n) "); + if (invocation.input() == Key.y) { + QuarkusProject quarkusProject = QuarkusProject.resolveExistingProject(projectDirectory, + QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()); + + MultiSelect selector = new MultiSelect(invocation.getShell(), + getAllExtensions(quarkusProject).stream().map(Extension::getSimplifiedArtifactId) + .collect(Collectors.toList()), + "Select the extensions that will be added to your project"); + + extensions = new HashSet<>(selector.doSelect()); - if (path != null) { - try { - boolean status = new CreateProject(Paths.get(path.getAbsolutePath()), - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor()) - .groupId(groupid) - .artifactId(artifactid) - .version(this.version) - .doCreateProject(new HashMap<>()); - if (status) { - commandInvocation.println("Project " + artifactid + " created successfully."); - } else { - commandInvocation.println("Failed to create project"); + status = new AddExtensions(QuarkusProject.resolveExistingProject(projectDirectory, + QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor())) + .extensions(extensions).execute() + .isSuccess(); + } + invocation.print(Config.getLineSeparator()); + } catch (InterruptedException ie) { + //ignored } - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); } - } else { - commandInvocation.println("You need to set the path for the project"); + + if (status) { + invocation.println("Project " + artifactId + + " created successfully at " + projectDirectory.toString() + "."); + } else { + invocation.println("Failed to create project"); + } + } catch (InterruptedException e) { + invocation.println("Project creation was aborted, " + e.getMessage()); + return CommandResult.FAILURE; + } catch (IOException | QuarkusCommandException e) { + invocation.println("Project creation failed, " + e.getMessage()); + invocation.println("Is the given path an empty folder?"); + return CommandResult.FAILURE; } return CommandResult.SUCCESS; } + + private void processClassName(Shell shell) throws InterruptedException { + String defaultResourceName = groupId.replace("-", ".").replace("_", "."); + className = shell.readLine("Set the resource class name, ( HelloResource ): "); + if (className == null || className.length() == 0) + className = defaultResourceName + ".HelloResource"; + else { + className = defaultResourceName + "." + className; + } + + if (resourcePath == null || resourcePath.length() == 0) { + resourcePath = shell.readLine("Set the resource path (" + getDerivedPath(className) + "): "); + if (resourcePath == null || resourcePath.length() == 0) + resourcePath = getDerivedPath(className); + if (!resourcePath.startsWith("/")) + resourcePath = "/" + resourcePath; + } + + } + + private static String getDerivedPath(String className) { + String[] resourceClassName = StringUtils.splitByCharacterTypeCamelCase( + className.substring(className.lastIndexOf(".") + 1)); + return "/" + resourceClassName[0].toLowerCase(); + } + + private List getAllExtensions(QuarkusProject quarkusProject) throws IOException { + return quarkusProject.getPlatformDescriptor().getExtensions(); + } } diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeCommand.java new file mode 100644 index 0000000000000..c84beaaadb17e --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeCommand.java @@ -0,0 +1,160 @@ +package io.quarkus.cli.commands; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.aesh.command.Command; +import org.aesh.command.CommandDefinition; +import org.aesh.command.CommandException; +import org.aesh.command.CommandNotFoundException; +import org.aesh.command.CommandResult; +import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.option.Argument; +import org.aesh.command.option.Option; +import org.aesh.command.option.OptionList; +import org.aesh.command.parser.CommandLineParserException; +import org.aesh.command.validator.CommandValidatorException; +import org.aesh.command.validator.OptionValidatorException; + +import io.quarkus.devtools.project.BuildTool; + +@CommandDefinition(name = "dev", description = "Starts up a development mode process for a Quarkus project.") +public class DevModeCommand implements Command { + + @Option(shortName = 'd', completer = DevModeDebugCompleter.class, defaultValue = { + "true" }, validator = DevModeDebugValidator.class, description = "If this server should be started in debug mode. " + + + "The default is to start in debug mode without suspending and listen on port 5005." + + " It supports the following options:\n" + + " \"false\" - The JVM is not started in debug mode\n" + + " \"true\" - The JVM is started in debug mode and suspends until a debugger is attached to port 5005\n" + + " \"client\" - The JVM is started in client mode, and attempts to connect to localhost:5005\n" + + "\"{port}\" - The JVM is started in debug mode and suspends until a debugger is attached to {port}") + private String debug; + + @Option(shortName = 'u', hasValue = false, name = "suspend", description = "Whether or not the JVM launch, in debug mode, should be suspended." + + "This parameter is only relevant when the JVM is launched in debug mode.") + private boolean suspend; + + @Option(shortName = 'b', name = "build", description = "Build folder, if not set the default folder for the used build tool will be used") + private File buildDir; + + @Option(shortName = 's', name = "source", description = "Source folder, if not set the default folder for the used build tool will be used") + private File sourceDir; + + @Option(name = "jvm-args", shortName = 'j', description = "JVM arguments to the dev mode process") + private String jvmArgs; + + @Option(name = "delete-dev-jar", shortName = 'e', hasValue = false, defaultValue = { + "true" }, description = "Delete the dev jar after it finishes") + private boolean deleteDevJar; + + @Option(name = "prevent-no-verify", shortName = 'p', defaultValue = { + "false" }, hasValue = false, description = "This value is intended to be set to true when some generated bytecode is eroneous causing " + + " the JVM to crash when the verify:non option is set (which is on by default).") + private boolean preventNoVerify; + + @Option(name = "no-deps", shortName = 'n', hasValue = false, defaultValue = { + "false" }, description = "Whether changes in the projects that appear to be dependencies of the project containing the " + + " application to be launched should trigger hot-reload. By default they do.") + + @OptionList(name = "compiler-args", shortName = 'c', description = "Additional parameters to pass to javac when recompiling changed source files.") + private List compilerArgs; + + @Argument(description = "Path to the project, if not set it will use the current working directory") + private File projectPath; + + private BuildTool buildTool; + private File buildFile; + + @Override + public CommandResult execute(CommandInvocation invocation) throws CommandException, InterruptedException { + + if (!verifyProjectStatus(invocation)) + return CommandResult.FAILURE; + + try { + devMode(invocation); + } catch (InterruptedException i) { + invocation.println("Stopping dev-mode"); + } + + return CommandResult.SUCCESS; + } + + private void devMode(CommandInvocation invocation) throws InterruptedException { + if (buildTool.equals(BuildTool.MAVEN)) { + File wrapper = ExecuteUtil.getMavenWrapper(projectPath.getAbsolutePath()); + if (wrapper != null) { + ExecuteUtil.executeWrapper(invocation, wrapper, "quarkus:dev"); + } else { + ExecuteUtil.executeMaven(projectPath, invocation, "quarkus:dev"); + } + + } + //do gradle + else { + File wrapper = ExecuteUtil.getGradleWrapper(projectPath.getAbsolutePath()); + if (wrapper != null) { + ExecuteUtil.executeWrapper(invocation, wrapper, "quarkusDev"); + } else { + ExecuteUtil.executeGradle(projectPath, invocation, "quarkusDev"); + } + } + } + + private boolean verifyProjectStatus(CommandInvocation invocation) { + + if (projectPath == null) + projectPath = new File(System.getProperty("user.dir")); + + buildTool = BuildTool.resolveExistingProject(projectPath.toPath()); + + if (buildTool.getBuildFiles().length > 0) + buildFile = new File(buildTool.getBuildFiles()[0]); + + if (buildFile == null || !buildFile.isFile()) { + invocation.println("Was not able to find a build file in: " + projectPath); + return false; + } + + if (buildDir == null) + buildDir = new File(buildTool.getBuildDirectory()); + + if (sourceDir == null) + sourceDir = resolveSourceDir(); + + if (!sourceDir.isDirectory()) { + invocation.println("ERROR: The project's sources directory does not exists (" + sourceDir); + return false; + } + + if (!buildDir.isDirectory() || !new File(buildDir, "classes").isDirectory()) { + invocation.println("Build directory (" + buildDir + " wasn't found. Compiling..."); + //if we run interactive, the name is 'compile-project', otherwise it's 'quarkus compile-project' + try { + invocation.executeCommand("compile-project"); + } catch (CommandNotFoundException e) { + try { + invocation.executeCommand("quarkus compile-project"); + } catch (CommandNotFoundException | CommandLineParserException | OptionValidatorException + | CommandValidatorException | CommandException | InterruptedException | IOException e2) { + invocation.println("Failure during compile, aborting: " + e2.getMessage()); + return false; + } + } catch (CommandLineParserException | OptionValidatorException + | CommandValidatorException | CommandException | InterruptedException | IOException e) { + invocation.println("Failure during compile, aborting: " + e.getMessage()); + return false; + } + } + + return true; + } + + private File resolveSourceDir() { + return new File(projectPath.getAbsolutePath() + File.separatorChar + "src" + + File.separatorChar + "main" + File.separatorChar + "java"); + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugCompleter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugCompleter.java new file mode 100644 index 0000000000000..b3bb9d03bee55 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugCompleter.java @@ -0,0 +1,23 @@ +package io.quarkus.cli.commands; + +import org.aesh.command.completer.CompleterInvocation; +import org.aesh.command.completer.OptionCompleter; + +public class DevModeDebugCompleter implements OptionCompleter { + @Override + public void complete(CompleterInvocation invocation) { + if (invocation.getGivenCompleteValue() == null || invocation.getGivenCompleteValue().length() == 0) { + invocation.addCompleterValue("false"); + invocation.addCompleterValue("true"); + invocation.addCompleterValue("client"); + invocation.addCompleterValue("{port}"); + } else { + if ("false".startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue("false"); + else if ("true".startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue("true"); + else if ("client".startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue("client"); + } + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugValidator.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugValidator.java new file mode 100644 index 0000000000000..69af1e0d5e63d --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/DevModeDebugValidator.java @@ -0,0 +1,22 @@ +package io.quarkus.cli.commands; + +import org.aesh.command.validator.OptionValidator; +import org.aesh.command.validator.OptionValidatorException; +import org.aesh.command.validator.ValidatorInvocation; + +public class DevModeDebugValidator implements OptionValidator> { + @Override + public void validate(ValidatorInvocation invocation) throws OptionValidatorException { + if (!invocation.getValue().equals("true") || + !invocation.getValue().equals("false") || + !invocation.getValue().equals("client")) { + //finally check if the value is a number + try { + Integer.parseInt(invocation.getValue()); + } catch (NumberFormatException nfe) { + throw new OptionValidatorException("The debug option need to be either: true, false, client or a port number"); + } + } + + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExecuteUtil.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExecuteUtil.java new file mode 100644 index 0000000000000..4a616f41f191d --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExecuteUtil.java @@ -0,0 +1,135 @@ +package io.quarkus.cli.commands; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Optional; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import org.aesh.command.invocation.CommandInvocation; +import org.apache.maven.shared.invoker.DefaultInvocationRequest; +import org.apache.maven.shared.invoker.DefaultInvoker; +import org.apache.maven.shared.invoker.InvocationRequest; +import org.apache.maven.shared.invoker.InvocationResult; +import org.apache.maven.shared.invoker.Invoker; +import org.apache.maven.shared.invoker.MavenInvocationException; + +public class ExecuteUtil { + + public static void executeGradle(File projectDirectory, CommandInvocation invocation, String buildTarget) + throws InterruptedException { + String gradleExecutable = findExecutable("gradle"); + if (gradleExecutable == null) { + invocation.println("unable to find the gradle executable, is it in your path?"); + } else { + gradleExecutable += File.separator + "bin" + File.separator + "gradle"; + + try { + Process process = new ProcessBuilder() + .command(gradleExecutable, buildTarget) + .directory(projectDirectory) + .start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + invocation.println(line); + } + + int exit = process.waitFor(); + if (exit != 0) + invocation.println("Build failed."); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static void executeMaven(File projectDirectory, CommandInvocation invocation, String buildTarget) { + String mvnPath = findExecutable("mvn"); + System.setProperty("maven.home", mvnPath); + + InvocationRequest request = new DefaultInvocationRequest(); + request.setPomFile(new File(projectDirectory.getAbsolutePath() + File.separatorChar + "pom.xml")); + request.setGoals(Collections.singletonList(buildTarget)); + + Invoker invoker = new DefaultInvoker(); + + InvocationResult result = null; + try { + result = invoker.execute(request); + } catch (MavenInvocationException e) { + invocation.println("Failed during invocation: " + e.getMessage()); + } + + if (result.getExitCode() != 0) { + invocation.println("Build failed."); + } + } + + public static String findExecutable(String exec) { + Optional mvnPath = Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator))) + .map(Paths::get) + .filter(path -> Files.exists(path.resolve(exec))).findFirst(); + + return mvnPath.map(value -> value.getParent().toString()).orElse(null); + } + + public static void executeWrapper(CommandInvocation invocation, File wrapper, String target) throws InterruptedException { + try { + Process process = new ProcessBuilder() + .command("./" + wrapper.getName(), target) + .directory(wrapper.getParentFile()) + .start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + invocation.println(line); + } + + int exit = process.waitFor(); + if (exit != 0) + invocation.println("Build failed."); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static File getGradleWrapper(String projectPath) { + if (System.getProperty("os.name").startsWith("Windows")) { + File wrapper = new File(projectPath + File.separator + "gradlew.bat"); + if (wrapper.isFile()) + return wrapper; + } else { + File wrapper = new File(projectPath + File.separator + "gradlew"); + if (wrapper.isFile()) + return wrapper; + } + + return null; + } + + public static File getMavenWrapper(String projectPath) { + if (System.getProperty("os.name").startsWith("Windows")) { + File wrapper = new File(projectPath + File.separator + "mvnw.bat"); + if (wrapper.isFile()) + return wrapper; + } else { + File wrapper = new File(projectPath + File.separator + "mvnw"); + if (wrapper.isFile()) + return wrapper; + } + + return null; + } + +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionCompleter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionCompleter.java new file mode 100644 index 0000000000000..a067f551114b3 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionCompleter.java @@ -0,0 +1,30 @@ +package io.quarkus.cli.commands; + +import java.util.List; +import java.util.stream.Collectors; + +import org.aesh.command.completer.CompleterInvocation; +import org.aesh.command.completer.OptionCompleter; + +import io.quarkus.dependencies.Extension; +import io.quarkus.platform.tools.config.QuarkusPlatformConfig; + +public class ExtensionCompleter implements OptionCompleter { + + @Override + public void complete(CompleterInvocation invocation) { + if (invocation.getGivenCompleteValue().length() == 0) { + invocation.addAllCompleterValues( + getAllExtensions().stream().map(Extension::getSimplifiedArtifactId).collect(Collectors.toList())); + } else { + for (Extension loadExtension : getAllExtensions()) { + if (loadExtension.getSimplifiedArtifactId().startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue(loadExtension.getSimplifiedArtifactId()); + } + } + } + + private List getAllExtensions() { + return QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor().getExtensions(); + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionFormat.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionFormat.java new file mode 100644 index 0000000000000..dd7527701775b --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ExtensionFormat.java @@ -0,0 +1,26 @@ +package io.quarkus.cli.commands; + +public enum ExtensionFormat { + CONCISE("concise"), + NAME("name"), + FULL("full"); + + private final String format; + + ExtensionFormat(String format) { + this.format = format; + } + + public String formatValue() { + return format; + } + + public static ExtensionFormat findFormat(String format) { + if (format.equalsIgnoreCase(FULL.format)) + return FULL; + else if (format.equalsIgnoreCase(NAME.format)) + return NAME; + else + return CONCISE; + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatCompleter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatCompleter.java new file mode 100644 index 0000000000000..75d2f1de4e5b5 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatCompleter.java @@ -0,0 +1,21 @@ +package io.quarkus.cli.commands; + +import org.aesh.command.completer.CompleterInvocation; +import org.aesh.command.completer.OptionCompleter; + +public class FormatCompleter implements OptionCompleter { + + @Override + public void complete(CompleterInvocation invocation) { + if (invocation.getGivenCompleteValue().length() == 0) { + for (ExtensionFormat format : ExtensionFormat.values()) + invocation.addCompleterValue(format.formatValue()); + } else { + for (ExtensionFormat format : ExtensionFormat.values()) { + if (format.formatValue().startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue(format.formatValue()); + } + } + + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatConverter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatConverter.java new file mode 100644 index 0000000000000..017c806df2910 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/FormatConverter.java @@ -0,0 +1,15 @@ +package io.quarkus.cli.commands; + +import org.aesh.command.converter.Converter; +import org.aesh.command.converter.ConverterInvocation; +import org.aesh.command.validator.OptionValidatorException; + +public class FormatConverter implements Converter { + @Override + public ExtensionFormat convert(ConverterInvocation converterInvocation) throws OptionValidatorException { + if (converterInvocation.getInput() != null && converterInvocation.getInput().length() > 0) + return ExtensionFormat.findFormat(converterInvocation.getInput()); + + return ExtensionFormat.CONCISE; + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ListExtensionsCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ListExtensionsCommand.java index 3420bdc6880ee..168da6237b02f 100644 --- a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ListExtensionsCommand.java +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ListExtensionsCommand.java @@ -1,5 +1,6 @@ package io.quarkus.cli.commands; +import java.nio.file.Path; import java.nio.file.Paths; import org.aesh.command.Command; @@ -7,46 +8,48 @@ import org.aesh.command.CommandException; import org.aesh.command.CommandResult; import org.aesh.command.invocation.CommandInvocation; -import org.aesh.command.option.Argument; import org.aesh.command.option.Option; import org.aesh.io.Resource; +import org.aesh.selector.SelectorType; import io.quarkus.devtools.commands.ListExtensions; +import io.quarkus.devtools.commands.data.QuarkusCommandException; import io.quarkus.devtools.project.QuarkusProject; import io.quarkus.platform.tools.config.QuarkusPlatformConfig; -/** - * @author Ståle Pedersen - */ -@CommandDefinition(name = "list-extensions", description = "List extensions for a project") +@CommandDefinition(name = "list", generateHelp = true, description = "List extensions for a project") public class ListExtensionsCommand implements Command { - @Option(shortName = 'h', hasValue = false) - private boolean help; - - @Option(shortName = 'a', hasValue = false, description = "Display all extensions or just the installable.") + @Option(shortName = 'a', hasValue = false, description = "Display all or just the installable extensions.") private boolean all = false; - @Option(shortName = 'f', hasValue = true, description = "Select the output format among 'name' (display the name only), 'concise' (display name and description) and 'full' (concise format and version related columns).") - private String format = "concise"; + @Option(shortName = 'f', selector = SelectorType.SELECT, completer = FormatCompleter.class, converter = FormatConverter.class, description = "Select the output format among:\n" + + + "'name' - display the name only\n" + + "'concise' - (display name and description\n" + + "'full' - (concise format and version related columns.\n") + private ExtensionFormat format; - @Option(shortName = 's', hasValue = true, description = "Search filter on extension list. The format is based on Java Pattern.") + @Option(shortName = 's', hasValue = true, defaultValue = { + "*" }, description = "Search filter on extension list. The format is based on Java Pattern.") private String searchPattern; - @Argument(description = "path to the project", required = true) + @Option(shortName = 'p', description = "Path to the project, if not set it will use the current working directory") private Resource path; public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException { - if (help) { - commandInvocation.println(commandInvocation.getHelpInfo("quarkus list-extensions")); - } else { - try { - new ListExtensions(QuarkusProject.resolveExistingProject(Paths.get(path.getAbsolutePath()), - QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor())) - .all(all).format(format).search(searchPattern); - } catch (Exception e) { - throw new CommandException("Unable to list extensions", e); - } + try { + Path projectDirectory = path != null ? Paths.get(path.getAbsolutePath()) + : Paths.get(System.getProperty("user.dir")); + + new ListExtensions(QuarkusProject.resolveExistingProject(projectDirectory, + QuarkusPlatformConfig.getGlobalDefault().getPlatformDescriptor())) + .all(all) + .format(format.formatValue()) + .search(searchPattern) + .execute(); + } catch (QuarkusCommandException e) { + e.printStackTrace(); } return CommandResult.SUCCESS; } diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/ProjectTypeCompleter.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ProjectTypeCompleter.java new file mode 100644 index 0000000000000..61f348e08bf38 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/ProjectTypeCompleter.java @@ -0,0 +1,27 @@ +package io.quarkus.cli.commands; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.aesh.command.completer.CompleterInvocation; +import org.aesh.command.completer.OptionCompleter; + +import io.quarkus.devtools.project.BuildTool; + +public class ProjectTypeCompleter implements OptionCompleter { + + @Override + public void complete(CompleterInvocation invocation) { + if (invocation.getGivenCompleteValue().length() == 0) + invocation.addAllCompleterValues( + Arrays.stream(BuildTool.values()).map(BuildTool::name).collect(Collectors.toList())); + else { + for (BuildTool tool : BuildTool.values()) { + if (tool.name().startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue(tool.name()); + else if (tool.name().toLowerCase().startsWith(invocation.getGivenCompleteValue())) + invocation.addCompleterValue(tool.name().toLowerCase()); + } + } + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusBaseCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusBaseCommand.java new file mode 100644 index 0000000000000..6cf383de0df86 --- /dev/null +++ b/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusBaseCommand.java @@ -0,0 +1,49 @@ +package io.quarkus.cli.commands; + +import org.aesh.AeshConsoleRunner; +import org.aesh.command.Command; +import org.aesh.command.CommandResult; +import org.aesh.command.GroupCommandDefinition; +import org.aesh.command.invocation.CommandInvocation; +import org.aesh.command.option.Option; +import org.aesh.terminal.utils.Config; + +@GroupCommandDefinition(name = QuarkusBaseCommand.COMMAND_NAME, generateHelp = true, groupCommands = { + ListExtensionsCommand.class, + AddExtensionsCommand.class, + CreateProjectCommand.class, + DevModeCommand.class, + CompileProjectCommand.class }, description = " [] \n\nThese are the common quarkus commands used in various situations") +public class QuarkusBaseCommand implements Command { + public static final String COMMAND_NAME = "quarkus"; + + @Option(shortName = 'i', hasValue = false, description = "Starts an interactive Quarkus Shell") + private boolean interactive; + + public CommandResult execute(CommandInvocation commandInvocation) { + if (interactive) { + commandInvocation.println("Starting interactive CLI...."); + //we need to stop first since the QuarkusCli starts the runner with interactive = true + commandInvocation.stop(); + startInteractive(); + } + + return CommandResult.SUCCESS; + } + + private void startInteractive() { + //we start the CLI in a new thread since the caller has a TerminalConnection open + Runnable runnable = () -> { + AeshConsoleRunner.builder() + .command(CreateProjectCommand.class) + .command(AddExtensionsCommand.class) + .command(ListExtensionsCommand.class) + .command(DevModeCommand.class) + .command(CompileProjectCommand.class) + .prompt("[quarkus@" + Config.getUserDir() + "]$ ") + .addExitCommand() + .start(); + }; + new Thread(runnable).start(); + } +} diff --git a/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusCommand.java b/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusCommand.java deleted file mode 100644 index 1fec366174193..0000000000000 --- a/devtools/aesh/src/main/java/io/quarkus/cli/commands/QuarkusCommand.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.quarkus.cli.commands; - -import org.aesh.command.Command; -import org.aesh.command.CommandException; -import org.aesh.command.CommandResult; -import org.aesh.command.GroupCommandDefinition; -import org.aesh.command.invocation.CommandInvocation; -import org.aesh.command.option.Option; - -/** - * @author Ståle Pedersen - */ -@GroupCommandDefinition(name = QuarkusCommand.COMMAND_NAME, groupCommands = { ListExtensionsCommand.class, - AddExtensionCommand.class, - CreateProjectCommand.class }, description = " [] \n\nThese are the common quarkus commands used in various situations") -public class QuarkusCommand implements Command { - public static final String COMMAND_NAME = "quarkus"; - - @Option(shortName = 'h', hasValue = false) - private boolean help; - - public CommandResult execute(CommandInvocation commandInvocation) throws CommandException, InterruptedException { - if (help) - commandInvocation.println(commandInvocation.getHelpInfo(COMMAND_NAME)); - - return CommandResult.SUCCESS; - } -} diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java index 72b326d1a2431..f362312b243a9 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java @@ -36,6 +36,7 @@ */ public class CreateProject { + public static final String NAME = "create-project"; private static final Pattern JAVA_VERSION_PATTERN = Pattern.compile("(?:1\\.)?(\\d+)(?:\\..*)?"); private final Path projectDirPath; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java index 1ec7fcad604b3..f4bb1b3d98a5f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/BuildTool.java @@ -62,4 +62,17 @@ public ExtensionManager createExtensionManager(final Path projectDirPath, return new MavenBuildFile(projectDirPath, platformDescriptor); } } + + public static BuildTool resolveExistingProject(Path path) { + return QuarkusProject.resolveExistingProjectBuildTool(path); + } + + public static BuildTool findTool(String tool) { + if ("GRADLE".equalsIgnoreCase(tool)) + return GRADLE; + else if ("MAVEN".equalsIgnoreCase(tool)) + return MAVEN; + else + return null; + } }