From e4aa1b5f95907baa9f9c9cf1a66c80197bd50f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Barto=C5=A1?= Date: Thu, 7 Mar 2024 21:36:43 +0100 Subject: [PATCH] Conditionally enable and disable CLI options (#25333) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Conditionally enable and disable CLI options Closes #13113 Signed-off-by: Martin Bartoš * Support for duplicates in config Signed-off-by: Martin Bartoš * Fix rendering config options in docs Fixes #26515 Signed-off-by: Martin Bartoš * Reorder OptionsDistTest Signed-off-by: Martin Bartoš --------- Signed-off-by: Martin Bartoš --- .../java/org/keycloak/common/Profile.java | 2 +- docs/guides/templates/guide.adoc | 4 +- docs/guides/templates/options.adoc | 4 + .../org/keycloak/guides/maven/Options.java | 120 +++++++-- .../org/keycloak/config/OptionCategory.java | 14 +- .../quarkus/deployment/KeycloakProcessor.java | 6 +- .../keycloak/quarkus/runtime/Environment.java | 19 ++ .../quarkus/runtime/KeycloakMain.java | 35 ++- .../keycloak/quarkus/runtime/cli/Help.java | 15 +- .../keycloak/quarkus/runtime/cli/Picocli.java | 196 +++++++++++--- .../runtime/cli/ShortErrorMessageHandler.java | 32 ++- .../runtime/cli/command/AbstractCommand.java | 4 + .../quarkus/runtime/cli/command/Build.java | 7 +- .../quarkus/runtime/cli/command/Export.java | 7 + .../runtime/cli/command/HelpAllMixin.java | 4 +- .../quarkus/runtime/cli/command/Import.java | 7 + .../runtime/configuration/Configuration.java | 26 +- .../DisabledMappersInterceptor.java | 91 +++++++ .../KcUnmatchedArgumentException.java | 39 +++ .../configuration/PersistedConfigSource.java | 26 +- .../PropertyMappingInterceptor.java | 7 +- .../mappers/ExportPropertyMappers.java | 76 ++++-- .../mappers/ImportPropertyMappers.java | 73 ++++-- .../mappers/LoggingPropertyMappers.java | 39 ++- .../configuration/mappers/PropertyMapper.java | 78 +++++- .../mappers/PropertyMappers.java | 244 +++++++++++++++--- ...io.smallrye.config.ConfigSourceInterceptor | 3 +- .../src/test/resources/META-INF/keycloak.conf | 6 +- .../keycloak/it/cli/OptionValidationTest.java | 4 +- .../keycloak/it/cli/dist/ExportDistTest.java | 2 +- .../keycloak/it/cli/dist/ImportDistTest.java | 3 + .../keycloak/it/cli/dist/LoggingDistTest.java | 3 + .../keycloak/it/cli/dist/OptionsDistTest.java | 94 ++++++- .../resources/OptionsDistTest/keycloak.conf | 9 +- ...dDistTest.testExportHelp.unix.approved.txt | 41 +-- ...stTest.testExportHelpAll.unix.approved.txt | 42 ++- ...dDistTest.testImportHelp.unix.approved.txt | 41 +-- ...stTest.testImportHelpAll.unix.approved.txt | 42 ++- ...istTest.testStartDevHelp.unix.approved.txt | 43 +-- ...Test.testStartDevHelpAll.unix.approved.txt | 44 ++-- ...ndDistTest.testStartHelp.unix.approved.txt | 43 +-- ...istTest.testStartHelpAll.unix.approved.txt | 44 ++-- ...t.testStartOptimizedHelp.unix.approved.txt | 43 +-- ...estStartOptimizedHelpAll.unix.approved.txt | 44 ++-- .../java/org/keycloak/utils/StringUtil.java | 13 +- 45 files changed, 1250 insertions(+), 489 deletions(-) create mode 100644 quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/DisabledMappersInterceptor.java create mode 100644 quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/KcUnmatchedArgumentException.java diff --git a/common/src/main/java/org/keycloak/common/Profile.java b/common/src/main/java/org/keycloak/common/Profile.java index e805836f77..a07c56668c 100755 --- a/common/src/main/java/org/keycloak/common/Profile.java +++ b/common/src/main/java/org/keycloak/common/Profile.java @@ -215,7 +215,7 @@ public class Profile { private static final Logger logger = Logger.getLogger(Profile.class); - private static Profile CURRENT; + private static volatile Profile CURRENT; private final ProfileName profileName; diff --git a/docs/guides/templates/guide.adoc b/docs/guides/templates/guide.adoc index 10481797d9..24c8663c10 100644 --- a/docs/guides/templates/guide.adoc +++ b/docs/guides/templates/guide.adoc @@ -1,6 +1,6 @@ <#import "/templates/options.adoc" as opts> -<#macro guide title summary priority=999 includedOptions="" preview="" tileVisible="true" previewDiscussionLink=""> +<#macro guide title summary priority=999 deniedCategories="" includedOptions="" preview="" tileVisible="true" previewDiscussionLink=""> :guide-id: ${id} :guide-title: ${title} :guide-summary: ${summary} @@ -28,6 +28,6 @@ endif::[] <#if includedOptions?has_content> == Relevant options -<@opts.list options=ctx.options.getOptions(includedOptions) anchor=false> +<@opts.list options=ctx.options.getOptions(includedOptions, deniedCategories) anchor=false> \ No newline at end of file diff --git a/docs/guides/templates/options.adoc b/docs/guides/templates/options.adoc index 9dd410df50..75f8db69c0 100644 --- a/docs/guides/templates/options.adoc +++ b/docs/guides/templates/options.adoc @@ -23,6 +23,10 @@ *Env:* `${option.keyEnv}` -- +<#if option.enabledWhen?has_content> +${option.enabledWhen!} + + <#if option.deprecated?has_content> <#-- Either mark the whole option as deprecated, or just selected values --> <#if !option.deprecated.deprecatedValues?has_content> diff --git a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Options.java b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Options.java index d8ad1b3287..63c88d58d6 100644 --- a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Options.java +++ b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Options.java @@ -15,40 +15,54 @@ import org.keycloak.provider.Spi; import org.keycloak.quarkus.runtime.Providers; import org.keycloak.quarkus.runtime.configuration.Configuration; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers; +import org.keycloak.utils.StringUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.EnumMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.StreamSupport; public class Options { - private final Map options; + private final Map> options; private final Map>> providerOptions = new LinkedHashMap<>(); - @SuppressWarnings("unchecked") public Options() { - options = PropertyMappers.getMappers().stream() + this.options = new EnumMap<>(OptionCategory.class); + PropertyMappers.getMappers().stream() .filter(m -> !m.isHidden()) .filter(propertyMapper -> Objects.nonNull(propertyMapper.getDescription())) - .map(m -> new Option(m.getFrom(), m.getCategory(), m.isBuildTime(), null, m.getDescription(), (String) m.getDefaultValue().map(Object::toString).orElse(null), m.getExpectedValues(), (DeprecatedMetadata) m.getDeprecatedMetadata().orElse(null))) - .sorted(Comparator.comparing(Option::getKey)) - .collect(Collectors.toMap(Option::getKey, o -> o, (o1, o2) -> o1, LinkedHashMap::new)); // Need to ignore duplicate keys?? + .map(m -> new Option(m.getFrom(), + m.getCategory(), + m.isBuildTime(), + null, + m.getDescription(), + m.getDefaultValue().map(Object::toString).orElse(null), + m.getExpectedValues(), + m.getEnabledWhen().orElse(""), + m.getDeprecatedMetadata().orElse(null))) + .forEach(o -> options.computeIfAbsent(o.category, k -> new TreeSet<>(Comparator.comparing(Option::getKey))).add(o)); + ProviderManager providerManager = Providers.getProviderManager(Thread.currentThread().getContextClassLoader()); - options.forEach((s, option) -> { - option.description = option.description.replaceAll("'([^ ]*)'", "`$1`"); - }); + options.values() + .stream() + .flatMap(Collection::stream) + .forEach(option -> option.description = option.description.replaceAll("'([^ ]*)'", "`$1`")); - for (Spi loadSpi : providerManager.loadSpis().stream().sorted(Comparator.comparing(Spi::getName)).collect(Collectors.toList())) { - for (ProviderFactory providerFactory : providerManager.load(loadSpi).stream().sorted(Comparator.comparing(ProviderFactory::getId)).collect(Collectors.toList())) { + for (Spi loadSpi : providerManager.loadSpis().stream().sorted(Comparator.comparing(Spi::getName)).toList()) { + for (ProviderFactory providerFactory : providerManager.load(loadSpi).stream().sorted(Comparator.comparing(ProviderFactory::getId)).toList()) { List configMetadata = providerFactory.getConfigMetadata(); if (configMetadata == null) { @@ -62,6 +76,7 @@ public class Options { m.getHelpText(), m.getDefaultValue() == null ? null : m.getDefaultValue().toString(), m.getOptions() == null ? Collections.emptyList() : m.getOptions(), + "", null)) .sorted(Comparator.comparing(Option::getKey)).collect(Collectors.toList()); @@ -88,39 +103,84 @@ public class Options { .collect(Collectors.toList()); } - public Collection