[KEYCLOAK-19798] - Move pf,cf,v options to the root command and error handling

This commit is contained in:
Pedro Igor 2021-11-17 19:41:49 -03:00
parent 884471c729
commit f5725cb629
18 changed files with 221 additions and 164 deletions

View file

@ -46,9 +46,10 @@ do
;; ;;
*) *)
if [[ $1 = --* || ! $1 =~ ^-D.* ]]; then if [[ $1 = --* || ! $1 =~ ^-D.* ]]; then
CONFIG_ARGS="$CONFIG_ARGS $1"
if [[ "$1" = "start-dev" ]]; then 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 fi
else else
SERVER_OPTS="$SERVER_OPTS $1" SERVER_OPTS="$SERVER_OPTS $1"

View file

@ -50,13 +50,13 @@ the HTTP port, run the server in development mode as follows:
To run the server in development mode: 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`. You should be able to attach your debugger to port `5005`.
For debugging the build steps, you can suspend the JVM by running: 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. 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.

View file

@ -150,11 +150,6 @@ public final class Environment {
return true; return true;
} }
// if running in quarkus:dev mode
if (ProfileManager.getLaunchMode() == LaunchMode.DEVELOPMENT) {
return true;
}
return DEV_PROFILE_VALUE.equals(getBuiltTimeProperty(PROFILE).orElse(null)); return DEV_PROFILE_VALUE.equals(getBuiltTimeProperty(PROFILE).orElse(null));
} }
@ -194,4 +189,8 @@ public final class Environment {
} }
})).collect(Collectors.toMap(File::getName, Function.identity())); })).collect(Collectors.toMap(File::getName, Function.identity()));
} }
public static boolean isQuarkusDevMode() {
return ProfileManager.getLaunchMode().equals(LaunchMode.DEVELOPMENT);
}
} }

View file

@ -19,10 +19,8 @@ package org.keycloak.quarkus.runtime;
import static org.keycloak.quarkus.runtime.Environment.isDevProfile; import static org.keycloak.quarkus.runtime.Environment.isDevProfile;
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault; 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 static org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun;
import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -31,11 +29,13 @@ import io.quarkus.runtime.ApplicationLifecycleManager;
import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.Quarkus;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
import org.keycloak.quarkus.runtime.cli.Picocli; import org.keycloak.quarkus.runtime.cli.Picocli;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import io.quarkus.runtime.QuarkusApplication; import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain; import io.quarkus.runtime.annotations.QuarkusMain;
import picocli.CommandLine;
/** /**
* <p>The main entry point, responsible for initialize and run the CLI as well as start the server. * <p>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); parseAndRun(cliArgs);
} }
public static void start(List<String> cliArgs, PrintWriter errorWriter) { public static void start(CommandLine cmd) {
try { try {
Quarkus.run(KeycloakMain.class, (integer, cause) -> { Quarkus.run(KeycloakMain.class, (integer, cause) -> {
if (cause != null) { 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")), String.format("Failed to start server using profile (%s)", getProfileOrDefault("prod")),
cause.getCause()); cause.getCause());
} }
}); });
} catch (Throwable cause) { } 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")), String.format("Unexpected error when starting the server using profile (%s)", getProfileOrDefault("prod")),
cause.getCause()); cause.getCause());
} }

View file

@ -15,9 +15,9 @@
* limitations under the License. * 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 { 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) + "."); 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]."); return new IllegalArgumentException("Invalid value [" + mode + "] for configuration property [proxy].");
} }
@ -41,4 +41,8 @@ public final class Messages {
builder.append("."); builder.append(".");
return new IllegalStateException(builder.toString()); return new IllegalStateException(builder.toString());
} }
public static void cliExecutionError(CommandLine cmd, String message, Throwable cause) {
throw new CommandLine.ExecutionException(cmd, message, cause);
}
} }

View file

@ -17,15 +17,131 @@
package org.keycloak.quarkus.runtime.cli; 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;
import picocli.CommandLine.ParseResult; 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 @Override
public int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) { public int handleExecutionException(Exception cause, CommandLine cmd, ParseResult parseResult) {
commandLine.getErr().println(ex.getMessage()); error(cmd.getErr(), "Failed to run '" + parseResult.subcommands().stream()
commandLine.usage(commandLine.getErr()); .map(ParseResult::commandSpec)
return commandLine.getCommandSpec().exitCodeOnExecutionException(); .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;
} }
} }

View file

@ -32,13 +32,19 @@ import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIS
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintWriter; import java.util.ArrayList;
import java.nio.file.FileSystemException; import java.util.Arrays;
import java.util.*; 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.regex.Pattern;
import java.util.stream.Collectors; 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.Build;
import org.keycloak.quarkus.runtime.cli.command.Main; import org.keycloak.quarkus.runtime.cli.command.Main;
import org.keycloak.quarkus.runtime.cli.command.Start; 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.ConfigCategory;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider; 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.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 org.keycloak.quarkus.runtime.Environment;
import io.smallrye.config.ConfigValue; import io.smallrye.config.ConfigValue;
@ -64,8 +66,6 @@ import picocli.CommandLine.Model.ArgGroupSpec;
public final class Picocli { public final class Picocli {
private static final Logger logger = Logger.getLogger(Picocli.class);
private static final String ARG_SEPARATOR = ";;"; private static final String ARG_SEPARATOR = ";;";
public static final String ARG_PREFIX = "--"; public static final String ARG_PREFIX = "--";
public static final String ARG_SHORT_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])); 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 // do not exit if running in dev mode, otherwise quarkus dev mode will exit when running from IDE
return; return;
} }
@ -146,7 +146,7 @@ public final class Picocli {
} }
private static void runReAugmentation(List<String> cliArgs, CommandLine cmd) { private static void runReAugmentation(List<String> cliArgs, CommandLine cmd) {
if (StartDev.NAME.equals(cliArgs.get(0))) { if (cliArgs.contains(StartDev.NAME)) {
String profile = Environment.getProfile(); String profile = Environment.getProfile();
if (profile == null) { if (profile == null) {
@ -159,13 +159,18 @@ public final class Picocli {
List<String> configArgsList = new ArrayList<>(cliArgs); List<String> configArgsList = new ArrayList<>(cliArgs);
if (!configArgsList.get(0).startsWith("--")) {
configArgsList.remove(0);
}
configArgsList.remove(AUTO_BUILD_OPTION_LONG); configArgsList.remove(AUTO_BUILD_OPTION_LONG);
configArgsList.remove(AUTO_BUILD_OPTION_SHORT); configArgsList.remove(AUTO_BUILD_OPTION_SHORT);
configArgsList.add(0, Build.NAME);
configArgsList.replaceAll(new UnaryOperator<String>() {
@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])); cmd.execute(configArgsList.toArray(new String[0]));
@ -421,100 +426,10 @@ public final class Picocli {
return parseResult.expandedArgs(); return parseResult.expandedArgs();
} }
public static void error(List<String> 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) { public static void println(CommandLine cmd, String message) {
cmd.getOut().println(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) { public static String normalizeKey(String key) {
return replaceNonAlphanumericByUnderscores(key).replace('_', '.'); return replaceNonAlphanumericByUnderscores(key).replace('_', '.');
} }

View file

@ -17,16 +17,15 @@
package org.keycloak.quarkus.runtime.cli.command; 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.Environment;
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
import picocli.CommandLine; import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Spec; import picocli.CommandLine.Spec;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
import static org.keycloak.quarkus.runtime.cli.Picocli.error;
public abstract class AbstractCommand { public abstract class AbstractCommand {
@Spec @Spec
@ -37,22 +36,15 @@ public abstract class AbstractCommand {
usageHelp = true) usageHelp = true)
boolean help; boolean help;
@Option(names = {"-pf", "--profile"}, protected void devProfileNotAllowedError(String cmd) {
description = "Set the profile. Use 'dev' profile to enable development mode.") 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=<profile>' with a profile more suitable for production.%n", cmd, Environment.DEV_PROFILE_VALUE));
public void setProfile(String profile) {
Environment.setProfile(profile);
} }
@Option(names = { "-cf", "--config-file" }, protected void executionError(CommandLine cmd, String message) {
arity = "1", executionError(cmd, message, null);
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 showDevNotAllowedErrorAndExit(String cmd) { protected void executionError(CommandLine cmd, String message, Throwable cause) {
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=<profile>' with a profile more suitable for production.%n", cmd)); cliExecutionError(cmd, message, cause);
} }
} }

View file

@ -17,8 +17,6 @@
package org.keycloak.quarkus.runtime.cli.command; package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.cli.Picocli.error;
import org.keycloak.quarkus.runtime.Environment; import org.keycloak.quarkus.runtime.Environment;
import picocli.CommandLine; import picocli.CommandLine;
@ -62,7 +60,7 @@ public abstract class AbstractExportImportCommand extends AbstractCommand implem
System.setProperty("keycloak.migration.provider", "singleFile"); System.setProperty("keycloak.migration.provider", "singleFile");
System.setProperty("keycloak.migration.file", toFile); System.setProperty("keycloak.migration.file", toFile);
} else { } else {
error(spec.commandLine(), "Must specify either --dir or --file options."); executionError(spec.commandLine(), "Must specify either --dir or --file options.");
} }
if (realm != null) { if (realm != null) {

View file

@ -29,8 +29,7 @@ public abstract class AbstractStartCommand extends AbstractCommand implements Ru
@Override @Override
public void run() { public void run() {
doBeforeRun(); doBeforeRun();
CommandLine cmd = spec.commandLine(); KeycloakMain.start(spec.commandLine());
KeycloakMain.start(cmd.getParseResult().expandedArgs(), cmd.getErr());
} }
protected void doBeforeRun() { protected void doBeforeRun() {

View file

@ -17,8 +17,8 @@
package org.keycloak.quarkus.runtime.cli.command; package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.Environment.*; import static org.keycloak.quarkus.runtime.Environment.getHomePath;
import static org.keycloak.quarkus.runtime.cli.Picocli.error; import static org.keycloak.quarkus.runtime.Environment.isDevMode;
import static org.keycloak.quarkus.runtime.cli.Picocli.println; import static org.keycloak.quarkus.runtime.cli.Picocli.println;
import org.keycloak.quarkus.runtime.Environment; 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"); println(spec.commandLine(), "\t" + Environment.getCommand() + " show-config\n");
} }
} catch (Throwable throwable) { } catch (Throwable throwable) {
error(spec.commandLine(), "Failed to update server configuration.", throwable); executionError(spec.commandLine(), "Failed to update server configuration.", throwable);
} finally { } finally {
cleanTempResources(); cleanTempResources();
} }
@ -92,7 +92,7 @@ public final class Build extends AbstractCommand implements Runnable {
private void exitWithErrorIfDevProfileIsSetAndNotStartDev() { private void exitWithErrorIfDevProfileIsSetAndNotStartDev() {
List<String> userInvokedCliArgs = Environment.getUserInvokedCliArgs(); List<String> userInvokedCliArgs = Environment.getUserInvokedCliArgs();
if(Environment.isDevProfile() && !userInvokedCliArgs.contains(StartDev.NAME)) { if(Environment.isDevProfile() && !userInvokedCliArgs.contains(StartDev.NAME)) {
showDevNotAllowedErrorAndExit(Build.NAME); devProfileNotAllowedError(Build.NAME);
} }
} }

View file

@ -19,9 +19,13 @@ package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.cli.Picocli.NO_PARAM_LABEL; 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.Command;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
import picocli.CommandLine.ScopeType;
@Command(name = "keycloak", @Command(name = "keycloak",
header = { header = {
@ -63,6 +67,9 @@ import picocli.CommandLine.ScopeType;
}) })
public final class Main { public final class Main {
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@Option(names = "-D<key>=<value>", @Option(names = "-D<key>=<value>",
description = "Set a Java system property", description = "Set a Java system property",
order = 0) order = 0)
@ -80,7 +87,23 @@ public final class Main {
@Option(names = { "-v", "--verbose" }, @Option(names = { "-v", "--verbose" },
description = "Print out error details when running this command.", description = "Print out error details when running this command.",
paramLabel = NO_PARAM_LABEL, paramLabel = NO_PARAM_LABEL)
scope = ScopeType.INHERIT) public void setVerbose(boolean verbose) {
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);
}
} }

View file

@ -18,8 +18,8 @@
package org.keycloak.quarkus.runtime.cli.command; package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.Environment.isDevProfile; 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.NO_PARAM_LABEL;
import static org.keycloak.quarkus.runtime.cli.Picocli.error;
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuiltTimeProperty; import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuiltTimeProperty;
import org.keycloak.quarkus.runtime.Environment; import org.keycloak.quarkus.runtime.Environment;
@ -70,7 +70,7 @@ public final class Start extends AbstractStartCommand implements Runnable {
setProfile(currentProfile.orElse(persistedProfile.orElse("prod"))); setProfile(currentProfile.orElse(persistedProfile.orElse("prod")));
if (isDevProfile() && (!currentCliArgs.contains(AUTO_BUILD_OPTION_LONG) || !currentCliArgs.contains(AUTO_BUILD_OPTION_SHORT))) { if (isDevProfile() && (!currentCliArgs.contains(AUTO_BUILD_OPTION_LONG) || !currentCliArgs.contains(AUTO_BUILD_OPTION_SHORT))) {
showDevNotAllowedErrorAndExit(Start.NAME); devProfileNotAllowedError(Start.NAME);
} }
} }
} }

View file

@ -55,13 +55,13 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
@Override @Override
public String getValue(String propertyName) { public String getValue(String propertyName) {
String value = super.getValue(propertyName.replace('-', '.')); String value = super.getValue(propertyName);
if (value != null) { if (value != null) {
return value; return value;
} }
return null; return super.getValue(propertyName.replace('-', '.'));
} }
private static Map<String, String> parseArgument() { private static Map<String, String> parseArgument() {

View file

@ -7,7 +7,7 @@ import java.util.Optional;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import static java.util.Arrays.asList; 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; import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException;
final class DatabasePropertyMappers { final class DatabasePropertyMappers {

View file

@ -3,6 +3,7 @@ package org.keycloak.quarkus.runtime.configuration.mappers;
import io.smallrye.config.ConfigSourceInterceptorContext; import io.smallrye.config.ConfigSourceInterceptorContext;
import io.smallrye.config.ConfigValue; import io.smallrye.config.ConfigValue;
import org.keycloak.quarkus.runtime.Environment; import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.Messages;
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider; import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
import java.io.File; import java.io.File;

View file

@ -7,6 +7,8 @@ import java.util.function.BiFunction;
import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException; import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException;
import org.keycloak.quarkus.runtime.Messages;
final class ProxyPropertyMappers { final class ProxyPropertyMappers {
private static final String[] possibleProxyValues = {"none", "edge", "reencrypt", "passthrough"}; private static final String[] possibleProxyValues = {"none", "edge", "reencrypt", "passthrough"};

View file

@ -25,3 +25,6 @@ quarkus.arc.ignored-split-packages=org.keycloak.*
# No need to generate dependencies list # No need to generate dependencies list
quarkus.package.include-dependency-list=false quarkus.package.include-dependency-list=false
# we do not want running dev services in distribution
quarkus.devservices.enabled=false