[KEYCLOAK-19798] - Move pf,cf,v options to the root command and error handling
This commit is contained in:
parent
884471c729
commit
f5725cb629
18 changed files with 221 additions and 164 deletions
|
@ -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"
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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('_', '.');
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"};
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue