diff --git a/distribution/server-x-dist/src/main/content/bin/kc.sh b/distribution/server-x-dist/src/main/content/bin/kc.sh index b3540d65b2..d8960c8bab 100644 --- a/distribution/server-x-dist/src/main/content/bin/kc.sh +++ b/distribution/server-x-dist/src/main/content/bin/kc.sh @@ -46,9 +46,10 @@ do ;; *) if [[ $1 = --* || ! $1 =~ ^-D.* ]]; then - CONFIG_ARGS="$CONFIG_ARGS $1" if [[ "$1" = "start-dev" ]]; then - CONFIG_ARGS="$CONFIG_ARGS --profile=dev --auto-build" + CONFIG_ARGS="$CONFIG_ARGS --profile=dev $1 --auto-build" + else + CONFIG_ARGS="$CONFIG_ARGS $1" fi else SERVER_OPTS="$SERVER_OPTS $1" diff --git a/quarkus/README.md b/quarkus/README.md index 82d3450f5b..271cc29a67 100644 --- a/quarkus/README.md +++ b/quarkus/README.md @@ -50,13 +50,13 @@ the HTTP port, run the server in development mode as follows: To run the server in development mode: - mvn -f server/pom.xml compile quarkus:dev + mvn -f server/pom.xml compile quarkus:dev -Dquarkus.args="start-dev" You should be able to attach your debugger to port `5005`. For debugging the build steps, you can suspend the JVM by running: - mvn -f server/pom.xml -Dsuspend=true compile quarkus:dev + mvn -f server/pom.xml -Dsuspend=true compile quarkus:dev -Dquarkus.args="start-dev" When running using `quarkus:dev` you should be able to do live coding whenever code changes within the `server` module. Changes you make to transient dependencies from the server extension (e.g: services, model, etc) won't be reflected into the running server. However, you can still leverage the hot swapping capabilities from your IDE to make changes at runtime. diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java index 8095e06623..a3d4dd35ce 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Environment.java @@ -150,11 +150,6 @@ public final class Environment { return true; } - // if running in quarkus:dev mode - if (ProfileManager.getLaunchMode() == LaunchMode.DEVELOPMENT) { - return true; - } - return DEV_PROFILE_VALUE.equals(getBuiltTimeProperty(PROFILE).orElse(null)); } @@ -194,4 +189,8 @@ public final class Environment { } })).collect(Collectors.toMap(File::getName, Function.identity())); } + + public static boolean isQuarkusDevMode() { + return ProfileManager.getLaunchMode().equals(LaunchMode.DEVELOPMENT); + } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java index 1f34b76ada..f5a276553d 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/KeycloakMain.java @@ -19,10 +19,8 @@ package org.keycloak.quarkus.runtime; import static org.keycloak.quarkus.runtime.Environment.isDevProfile; import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault; -import static org.keycloak.quarkus.runtime.cli.Picocli.error; import static org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -31,11 +29,13 @@ import io.quarkus.runtime.ApplicationLifecycleManager; import io.quarkus.runtime.Quarkus; import org.jboss.logging.Logger; +import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler; import org.keycloak.quarkus.runtime.cli.Picocli; import org.keycloak.common.Version; import io.quarkus.runtime.QuarkusApplication; import io.quarkus.runtime.annotations.QuarkusMain; +import picocli.CommandLine; /** *

The main entry point, responsible for initialize and run the CLI as well as start the server. @@ -59,17 +59,21 @@ public class KeycloakMain implements QuarkusApplication { parseAndRun(cliArgs); } - public static void start(List cliArgs, PrintWriter errorWriter) { + public static void start(CommandLine cmd) { try { Quarkus.run(KeycloakMain.class, (integer, cause) -> { if (cause != null) { - error(cliArgs, errorWriter, + ExecutionExceptionHandler exceptionHandler = (ExecutionExceptionHandler) cmd.getExecutionExceptionHandler(); + + exceptionHandler.error(cmd.getErr(), String.format("Failed to start server using profile (%s)", getProfileOrDefault("prod")), cause.getCause()); } }); } catch (Throwable cause) { - error(cliArgs, errorWriter, + ExecutionExceptionHandler exceptionHandler = (ExecutionExceptionHandler) cmd.getExecutionExceptionHandler(); + + exceptionHandler.error(cmd.getErr(), String.format("Unexpected error when starting the server using profile (%s)", getProfileOrDefault("prod")), cause.getCause()); } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/Messages.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Messages.java similarity index 78% rename from quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/Messages.java rename to quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Messages.java index 77b2f75291..c37b942ade 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/Messages.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/Messages.java @@ -15,9 +15,9 @@ * limitations under the License. */ -package org.keycloak.quarkus.runtime.configuration.mappers; +package org.keycloak.quarkus.runtime; -import org.keycloak.quarkus.runtime.Environment; +import picocli.CommandLine; public final class Messages { @@ -25,11 +25,11 @@ public final class Messages { } - static IllegalArgumentException invalidDatabaseVendor(String db, String... availableOptions) { + public static IllegalArgumentException invalidDatabaseVendor(String db, String... availableOptions) { return new IllegalArgumentException("Invalid database vendor [" + db + "]. Possible values are: " + String.join(", ", availableOptions) + "."); } - static IllegalArgumentException invalidProxyMode(String mode) { + public static IllegalArgumentException invalidProxyMode(String mode) { return new IllegalArgumentException("Invalid value [" + mode + "] for configuration property [proxy]."); } @@ -41,4 +41,8 @@ public final class Messages { builder.append("."); return new IllegalStateException(builder.toString()); } + + public static void cliExecutionError(CommandLine cmd, String message, Throwable cause) { + throw new CommandLine.ExecutionException(cmd, message, cause); + } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/ExecutionExceptionHandler.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/ExecutionExceptionHandler.java index 6aff6b9ac4..ed63c5eb86 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/ExecutionExceptionHandler.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/ExecutionExceptionHandler.java @@ -17,15 +17,131 @@ package org.keycloak.quarkus.runtime.cli; +import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig; + +import java.io.PrintWriter; +import java.nio.file.FileSystemException; +import java.util.Optional; +import org.jboss.logging.Logger; +import org.keycloak.platform.Platform; +import org.keycloak.quarkus.runtime.Environment; +import org.keycloak.quarkus.runtime.InitializationException; +import org.keycloak.quarkus.runtime.Messages; +import org.keycloak.quarkus.runtime.integration.QuarkusPlatform; + +import io.quarkus.runtime.Quarkus; +import io.smallrye.config.ConfigValue; import picocli.CommandLine; import picocli.CommandLine.ParseResult; -public class ExecutionExceptionHandler implements CommandLine.IExecutionExceptionHandler { +public final class ExecutionExceptionHandler implements CommandLine.IExecutionExceptionHandler { + + private Logger logger; + private boolean verbose; + + ExecutionExceptionHandler() {} @Override - public int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) { - commandLine.getErr().println(ex.getMessage()); - commandLine.usage(commandLine.getErr()); - return commandLine.getCommandSpec().exitCodeOnExecutionException(); + public int handleExecutionException(Exception cause, CommandLine cmd, ParseResult parseResult) { + error(cmd.getErr(), "Failed to run '" + parseResult.subcommands().stream() + .map(ParseResult::commandSpec) + .map(CommandLine.Model.CommandSpec::name) + .findFirst() + .orElse(Environment.getCommand()) + "' command.", cause); + return cmd.getCommandSpec().exitCodeOnExecutionException(); + } + + public void error(PrintWriter errorWriter, String message, Throwable cause) { + if (message != null) { + logError(errorWriter, "ERROR: " + message); + } + + if (cause != null) { + if (cause instanceof InitializationException) { + InitializationException initializationException = (InitializationException) cause; + if (initializationException.getSuppressed() == null || initializationException.getSuppressed().length == 0) { + dumpException(errorWriter, initializationException); + } else if (initializationException.getSuppressed().length == 1) { + dumpException(errorWriter, initializationException.getSuppressed()[0]); + } else { + logError(errorWriter, "ERROR: Multiple configuration errors during startup"); + int counter = 0; + for (Throwable inner : initializationException.getSuppressed()) { + counter++; + logError(errorWriter, "ERROR " + counter); + dumpException(errorWriter, inner); + } + } + } else { + dumpException(errorWriter, cause); + } + + if (!verbose) { + logError(errorWriter, "For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command."); + } + } + + Quarkus.asyncExit(1); + } + + private void dumpException(PrintWriter errorWriter, Throwable cause) { + if (verbose) { + logError(errorWriter, cause == null ? "Unknown error." : "Error details:", cause); + } else { + do { + if (cause.getMessage() != null) { + logError(errorWriter, String.format("ERROR: %s", cause.getMessage())); + } + printErrorHints(errorWriter, cause); + } while ((cause = cause.getCause()) != null); + } + + printErrorHints(errorWriter, cause); + } + + private void printErrorHints(PrintWriter errorWriter, Throwable cause) { + if (cause instanceof FileSystemException) { + FileSystemException fse = (FileSystemException) cause; + ConfigValue httpsCertFile = getConfig().getConfigValue("kc.https.certificate.file"); + + if (fse.getFile().equals(Optional.ofNullable(httpsCertFile.getValue()).orElse(null))) { + logError(errorWriter, Messages.httpsConfigurationNotSet().getMessage()); + } + } + } + + private void logError(PrintWriter errorWriter, String errorMessage) { + logError(errorWriter, errorMessage, null); + } + + // The "cause" can be null + private void logError(PrintWriter errorWriter, String errorMessage, Throwable cause) { + QuarkusPlatform platform = (QuarkusPlatform) Platform.getPlatform(); + if (platform.isStarted()) { + // Can delegate to proper logger once the platform is started + if (cause == null) { + getLogger().error(errorMessage); + } else { + getLogger().error(errorMessage, cause); + } + } else { + if (cause == null) { + errorWriter.println(errorMessage); + } else { + errorWriter.println(errorMessage); + cause.printStackTrace(errorWriter); + } + } + } + + private Logger getLogger() { + if (logger == null) { + logger = Logger.getLogger(ExecutionExceptionHandler.class); + } + return logger; + } + + public void setVerbose(boolean verbose) { + this.verbose = verbose; } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Picocli.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Picocli.java index 800bddc918..10456e3a09 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Picocli.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Picocli.java @@ -32,13 +32,19 @@ import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIS import java.io.File; import java.io.FileInputStream; import java.io.InputStream; -import java.io.PrintWriter; -import java.nio.file.FileSystemException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.Set; +import java.util.function.UnaryOperator; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.jboss.logging.Logger; import org.keycloak.quarkus.runtime.cli.command.Build; import org.keycloak.quarkus.runtime.cli.command.Main; import org.keycloak.quarkus.runtime.cli.command.Start; @@ -47,11 +53,7 @@ import org.keycloak.common.Profile; import org.keycloak.quarkus.runtime.configuration.mappers.ConfigCategory; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers; import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider; -import org.keycloak.quarkus.runtime.configuration.mappers.Messages; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper; -import org.keycloak.platform.Platform; -import org.keycloak.quarkus.runtime.InitializationException; -import org.keycloak.quarkus.runtime.integration.QuarkusPlatform; import org.keycloak.quarkus.runtime.Environment; import io.smallrye.config.ConfigValue; @@ -64,8 +66,6 @@ import picocli.CommandLine.Model.ArgGroupSpec; public final class Picocli { - private static final Logger logger = Logger.getLogger(Picocli.class); - private static final String ARG_SEPARATOR = ";;"; public static final String ARG_PREFIX = "--"; public static final String ARG_SHORT_PREFIX = "-"; @@ -105,7 +105,7 @@ public final class Picocli { int exitCode = cmd.execute(cliArgs.toArray(new String[0])); - if (isDevMode()) { + if (Environment.isQuarkusDevMode()) { // do not exit if running in dev mode, otherwise quarkus dev mode will exit when running from IDE return; } @@ -146,7 +146,7 @@ public final class Picocli { } private static void runReAugmentation(List cliArgs, CommandLine cmd) { - if (StartDev.NAME.equals(cliArgs.get(0))) { + if (cliArgs.contains(StartDev.NAME)) { String profile = Environment.getProfile(); if (profile == null) { @@ -159,13 +159,18 @@ public final class Picocli { List configArgsList = new ArrayList<>(cliArgs); - if (!configArgsList.get(0).startsWith("--")) { - configArgsList.remove(0); - } - configArgsList.remove(AUTO_BUILD_OPTION_LONG); configArgsList.remove(AUTO_BUILD_OPTION_SHORT); - configArgsList.add(0, Build.NAME); + + configArgsList.replaceAll(new UnaryOperator() { + @Override + public String apply(String arg) { + if (arg.equals(Start.NAME) || arg.equals(StartDev.NAME)) { + return Build.NAME; + } + return arg; + } + }); cmd.execute(configArgsList.toArray(new String[0])); @@ -421,100 +426,10 @@ public final class Picocli { return parseResult.expandedArgs(); } - public static void error(List cliArgs, PrintWriter errorWriter, String message, Throwable throwable) { - logError(errorWriter, "ERROR: " + message); - - if (throwable != null) { - boolean verbose = cliArgs.contains("--verbose") || cliArgs.contains("-v"); - - if (throwable instanceof InitializationException) { - InitializationException initializationException = (InitializationException) throwable; - if (initializationException.getSuppressed() == null || initializationException.getSuppressed().length == 0) { - dumpException(errorWriter, initializationException, verbose); - } else if (initializationException.getSuppressed().length == 1) { - dumpException(errorWriter, initializationException.getSuppressed()[0], verbose); - } else { - logError(errorWriter, "ERROR: Multiple configuration errors during startup"); - int counter = 0; - for (Throwable inner : initializationException.getSuppressed()) { - counter++; - logError(errorWriter, "ERROR " + counter); - dumpException(errorWriter, inner, verbose); - } - } - } else { - dumpException(errorWriter, throwable, verbose); - } - - if (!verbose) { - logError(errorWriter, "For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command."); - } - } - - System.exit(1); - } - - public static void error(CommandLine cmd, String message, Throwable throwable) { - error(getCliArgs(cmd), cmd.getErr(), message, throwable); - } - - public static void error(CommandLine cmd, String message) { - error(getCliArgs(cmd), cmd.getErr(), message, null); - } - public static void println(CommandLine cmd, String message) { cmd.getOut().println(message); } - private static void dumpException(PrintWriter errorWriter, Throwable cause, boolean verbose) { - if (verbose) { - logError(errorWriter, "ERROR: Details:", cause); - } else { - do { - if (cause.getMessage() != null) { - logError(errorWriter, String.format("ERROR: %s", cause.getMessage())); - } - printErrorHints(errorWriter, cause); - } while ((cause = cause.getCause())!= null); - } - printErrorHints(errorWriter, cause); - } - - private static void printErrorHints(PrintWriter errorWriter, Throwable cause) { - if (cause instanceof FileSystemException) { - FileSystemException fse = (FileSystemException) cause; - ConfigValue httpsCertFile = getConfig().getConfigValue("kc.https.certificate.file"); - - if (fse.getFile().equals(Optional.ofNullable(httpsCertFile.getValue()).orElse(null))) { - logError(errorWriter, Messages.httpsConfigurationNotSet().getMessage()); - } - } - } - - private static void logError(PrintWriter errorWriter, String errorMessage) { - logError(errorWriter, errorMessage, null); - } - - // The "cause" can be null - private static void logError(PrintWriter errorWriter, String errorMessage, Throwable cause) { - QuarkusPlatform platform = (QuarkusPlatform) Platform.getPlatform(); - if (platform.isStarted()) { - // Can delegate to proper logger once the platform is started - if (cause == null) { - logger.error(errorMessage); - } else { - logger.error(errorMessage, cause); - } - } else { - if (cause == null) { - errorWriter.println(errorMessage); - } else { - errorWriter.println(errorMessage); - cause.printStackTrace(); - } - } - } - public static String normalizeKey(String key) { return replaceNonAlphanumericByUnderscores(key).replace('_', '.'); } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractCommand.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractCommand.java index 6ffea5b16a..fead68ca73 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractCommand.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractCommand.java @@ -17,16 +17,15 @@ package org.keycloak.quarkus.runtime.cli.command; +import static org.keycloak.quarkus.runtime.Messages.cliExecutionError; + import org.keycloak.quarkus.runtime.Environment; -import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider; import picocli.CommandLine; import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Spec; import picocli.CommandLine.Option; -import static org.keycloak.quarkus.runtime.cli.Picocli.error; - public abstract class AbstractCommand { @Spec @@ -37,22 +36,15 @@ public abstract class AbstractCommand { usageHelp = true) boolean help; - @Option(names = {"-pf", "--profile"}, - description = "Set the profile. Use 'dev' profile to enable development mode.") - public void setProfile(String profile) { - Environment.setProfile(profile); + protected void devProfileNotAllowedError(String cmd) { + executionError(spec.commandLine(), String.format("You can not '%s' the server using the '%s' configuration profile. Please re-build the server first, using './kc.sh build' for the default production profile, or using '/.kc.sh build --profile=' with a profile more suitable for production.%n", cmd, Environment.DEV_PROFILE_VALUE)); } - @Option(names = { "-cf", "--config-file" }, - arity = "1", - description = "Set the path to a configuration file. By default, configuration properties are read from the \"keycloak.properties\" file in the \"conf\" directory.", - paramLabel = "file", - scope = CommandLine.ScopeType.INHERIT) - public void setConfigFile(String path) { - System.setProperty(KeycloakConfigSourceProvider.KEYCLOAK_CONFIG_FILE_PROP, path); + protected void executionError(CommandLine cmd, String message) { + executionError(cmd, message, null); } - protected void showDevNotAllowedErrorAndExit(String cmd) { - error(spec.commandLine(), String.format("You can not '%s' the server using the 'dev' configuration profile. Please re-build the server first, using './kc.sh build' for the default production profile, or using '/.kc.sh build --profile=' with a profile more suitable for production.%n", cmd)); + protected void executionError(CommandLine cmd, String message, Throwable cause) { + cliExecutionError(cmd, message, cause); } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractExportImportCommand.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractExportImportCommand.java index 7ba6f8c182..170936c64e 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractExportImportCommand.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractExportImportCommand.java @@ -17,8 +17,6 @@ package org.keycloak.quarkus.runtime.cli.command; -import static org.keycloak.quarkus.runtime.cli.Picocli.error; - import org.keycloak.quarkus.runtime.Environment; import picocli.CommandLine; @@ -62,7 +60,7 @@ public abstract class AbstractExportImportCommand extends AbstractCommand implem System.setProperty("keycloak.migration.provider", "singleFile"); System.setProperty("keycloak.migration.file", toFile); } else { - error(spec.commandLine(), "Must specify either --dir or --file options."); + executionError(spec.commandLine(), "Must specify either --dir or --file options."); } if (realm != null) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractStartCommand.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractStartCommand.java index 716697a50c..4883d1c869 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractStartCommand.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractStartCommand.java @@ -29,8 +29,7 @@ public abstract class AbstractStartCommand extends AbstractCommand implements Ru @Override public void run() { doBeforeRun(); - CommandLine cmd = spec.commandLine(); - KeycloakMain.start(cmd.getParseResult().expandedArgs(), cmd.getErr()); + KeycloakMain.start(spec.commandLine()); } protected void doBeforeRun() { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Build.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Build.java index 58e88e808b..829fccd655 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Build.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Build.java @@ -17,8 +17,8 @@ package org.keycloak.quarkus.runtime.cli.command; -import static org.keycloak.quarkus.runtime.Environment.*; -import static org.keycloak.quarkus.runtime.cli.Picocli.error; +import static org.keycloak.quarkus.runtime.Environment.getHomePath; +import static org.keycloak.quarkus.runtime.Environment.isDevMode; import static org.keycloak.quarkus.runtime.cli.Picocli.println; import org.keycloak.quarkus.runtime.Environment; @@ -83,7 +83,7 @@ public final class Build extends AbstractCommand implements Runnable { println(spec.commandLine(), "\t" + Environment.getCommand() + " show-config\n"); } } catch (Throwable throwable) { - error(spec.commandLine(), "Failed to update server configuration.", throwable); + executionError(spec.commandLine(), "Failed to update server configuration.", throwable); } finally { cleanTempResources(); } @@ -92,7 +92,7 @@ public final class Build extends AbstractCommand implements Runnable { private void exitWithErrorIfDevProfileIsSetAndNotStartDev() { List userInvokedCliArgs = Environment.getUserInvokedCliArgs(); if(Environment.isDevProfile() && !userInvokedCliArgs.contains(StartDev.NAME)) { - showDevNotAllowedErrorAndExit(Build.NAME); + devProfileNotAllowedError(Build.NAME); } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Main.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Main.java index 477e53f5ad..792afb8f12 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Main.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Main.java @@ -19,9 +19,13 @@ package org.keycloak.quarkus.runtime.cli.command; import static org.keycloak.quarkus.runtime.cli.Picocli.NO_PARAM_LABEL; +import org.keycloak.quarkus.runtime.Environment; +import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler; +import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider; + +import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; -import picocli.CommandLine.ScopeType; @Command(name = "keycloak", header = { @@ -63,6 +67,9 @@ import picocli.CommandLine.ScopeType; }) public final class Main { + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + @Option(names = "-D=", description = "Set a Java system property", order = 0) @@ -80,7 +87,23 @@ public final class Main { @Option(names = { "-v", "--verbose" }, description = "Print out error details when running this command.", - paramLabel = NO_PARAM_LABEL, - scope = ScopeType.INHERIT) - Boolean verbose; + paramLabel = NO_PARAM_LABEL) + public void setVerbose(boolean verbose) { + ExecutionExceptionHandler exceptionHandler = (ExecutionExceptionHandler) spec.commandLine().getExecutionExceptionHandler(); + exceptionHandler.setVerbose(verbose); + } + + @Option(names = {"-pf", "--profile"}, + description = "Set the profile. Use 'dev' profile to enable development mode.") + public void setProfile(String profile) { + Environment.setProfile(profile); + } + + @Option(names = { "-cf", "--config-file" }, + arity = "1", + description = "Set the path to a configuration file. By default, configuration properties are read from the \"keycloak.properties\" file in the \"conf\" directory.", + paramLabel = "file") + public void setConfigFile(String path) { + System.setProperty(KeycloakConfigSourceProvider.KEYCLOAK_CONFIG_FILE_PROP, path); + } } \ No newline at end of file diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Start.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Start.java index fb0ed19708..94323ee2fc 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Start.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/Start.java @@ -18,8 +18,8 @@ package org.keycloak.quarkus.runtime.cli.command; import static org.keycloak.quarkus.runtime.Environment.isDevProfile; +import static org.keycloak.quarkus.runtime.Environment.setProfile; import static org.keycloak.quarkus.runtime.cli.Picocli.NO_PARAM_LABEL; -import static org.keycloak.quarkus.runtime.cli.Picocli.error; import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuiltTimeProperty; import org.keycloak.quarkus.runtime.Environment; @@ -70,7 +70,7 @@ public final class Start extends AbstractStartCommand implements Runnable { setProfile(currentProfile.orElse(persistedProfile.orElse("prod"))); if (isDevProfile() && (!currentCliArgs.contains(AUTO_BUILD_OPTION_LONG) || !currentCliArgs.contains(AUTO_BUILD_OPTION_SHORT))) { - showDevNotAllowedErrorAndExit(Start.NAME); + devProfileNotAllowedError(Start.NAME); } } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/ConfigArgsConfigSource.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/ConfigArgsConfigSource.java index cc96bd3369..f8889d6beb 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/ConfigArgsConfigSource.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/ConfigArgsConfigSource.java @@ -55,13 +55,13 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource { @Override public String getValue(String propertyName) { - String value = super.getValue(propertyName.replace('-', '.')); + String value = super.getValue(propertyName); if (value != null) { return value; } - return null; + return super.getValue(propertyName.replace('-', '.')); } private static Map parseArgument() { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/DatabasePropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/DatabasePropertyMappers.java index ffd6a72b5e..bd1f3cb0c4 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/DatabasePropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/DatabasePropertyMappers.java @@ -7,7 +7,7 @@ import java.util.Optional; import java.util.function.BiFunction; import static java.util.Arrays.asList; -import static org.keycloak.quarkus.runtime.configuration.mappers.Messages.invalidDatabaseVendor; +import static org.keycloak.quarkus.runtime.Messages.invalidDatabaseVendor; import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException; final class DatabasePropertyMappers { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HttpPropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HttpPropertyMappers.java index 20acb07dfe..8b4ac674a3 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HttpPropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HttpPropertyMappers.java @@ -3,6 +3,7 @@ package org.keycloak.quarkus.runtime.configuration.mappers; import io.smallrye.config.ConfigSourceInterceptorContext; import io.smallrye.config.ConfigValue; import org.keycloak.quarkus.runtime.Environment; +import org.keycloak.quarkus.runtime.Messages; import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider; import java.io.File; diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java index a7c1b782ed..edfada635e 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java @@ -7,6 +7,8 @@ import java.util.function.BiFunction; import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException; +import org.keycloak.quarkus.runtime.Messages; + final class ProxyPropertyMappers { private static final String[] possibleProxyValues = {"none", "edge", "reencrypt", "passthrough"}; diff --git a/quarkus/server/src/main/resources/application.properties b/quarkus/server/src/main/resources/application.properties index 3bceeb7d6b..9dd1924f31 100644 --- a/quarkus/server/src/main/resources/application.properties +++ b/quarkus/server/src/main/resources/application.properties @@ -25,3 +25,6 @@ quarkus.arc.ignored-split-packages=org.keycloak.* # No need to generate dependencies list quarkus.package.include-dependency-list=false + +# we do not want running dev services in distribution +quarkus.devservices.enabled=false