diff --git a/core/src/main/java/org/jboss/galleon/Constants.java b/core/src/main/java/org/jboss/galleon/Constants.java index de1584c15..1c7a38bc5 100644 --- a/core/src/main/java/org/jboss/galleon/Constants.java +++ b/core/src/main/java/org/jboss/galleon/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -68,6 +68,8 @@ public interface Constants { String CONFIG_ARRANGER_SPEC_ONLY = "spec-only"; // OPTIONS + String IGNORE_NOT_EXCLUDED_LAYERS = "ignore-not-excluded-layers"; + String OPTIONAL_PACKAGES = "optional-packages"; String ALL = "all"; String NONE = "none"; diff --git a/core/src/main/java/org/jboss/galleon/Errors.java b/core/src/main/java/org/jboss/galleon/Errors.java index 130014df2..884464337 100644 --- a/core/src/main/java/org/jboss/galleon/Errors.java +++ b/core/src/main/java/org/jboss/galleon/Errors.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -505,6 +505,18 @@ static String layerNotFound(ConfigId layerId) { return "Failed to locate layer " + layerId + " in the the installation feature-pack layout"; } + static String excludedLayersWouldNotOtherwiseBeInstalled(ConfigId configId, List notExcludedLayers) { + final StringBuilder buf = new StringBuilder(); + buf.append("The following layers configured to be excluded from configuration ") + .append(configId) + .append(" would not have otherwise been installed: "); + StringUtils.append(buf, notExcludedLayers); + buf.append(". Either remove the corresponding exclusions or add ") + .append(ProvisioningOption.IGNORE_NOT_EXCLUDED_LAYERS.getName()) + .append(" option"); + return buf.toString(); + } + static String tookTime(String action, long startTimeNanos) { final long nanos = Math.abs(System.nanoTime() - startTimeNanos); final long timeSec = nanos / 1000000000; diff --git a/core/src/main/java/org/jboss/galleon/ProvisioningOption.java b/core/src/main/java/org/jboss/galleon/ProvisioningOption.java index 30091a446..112424925 100644 --- a/core/src/main/java/org/jboss/galleon/ProvisioningOption.java +++ b/core/src/main/java/org/jboss/galleon/ProvisioningOption.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,7 +44,13 @@ public class ProvisioningOption { .addToValueSet(Constants.FAIL) .build(); - private static final List stdOptions = Arrays.asList(new ProvisioningOption[] {OPTIONAL_PACKAGES, VERSION_CONVERGENCE}); + public static final ProvisioningOption IGNORE_NOT_EXCLUDED_LAYERS = ProvisioningOption.builder(Constants.IGNORE_NOT_EXCLUDED_LAYERS) + .setDefaultValue(Constants.FALSE) + .setBooleanValueSet() + .build(); + + private static final List stdOptions = Arrays + .asList(new ProvisioningOption[] { IGNORE_NOT_EXCLUDED_LAYERS, OPTIONAL_PACKAGES, VERSION_CONVERGENCE }); public static List getStandardList() { return stdOptions; diff --git a/core/src/main/java/org/jboss/galleon/runtime/ConfigModelStack.java b/core/src/main/java/org/jboss/galleon/runtime/ConfigModelStack.java index 7c5a80c00..8bdcddf69 100644 --- a/core/src/main/java/org/jboss/galleon/runtime/ConfigModelStack.java +++ b/core/src/main/java/org/jboss/galleon/runtime/ConfigModelStack.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -27,8 +28,10 @@ import java.util.Set; import org.jboss.galleon.Constants; +import org.jboss.galleon.Errors; import org.jboss.galleon.ProvisioningDescriptionException; import org.jboss.galleon.ProvisioningException; +import org.jboss.galleon.ProvisioningOption; import org.jboss.galleon.config.ConfigId; import org.jboss.galleon.config.ConfigModel; import org.jboss.galleon.config.FeatureGroupSupport; @@ -174,12 +177,17 @@ private boolean isRelevant(ResolvedFeatureGroupConfig resolvedFg) { private List includedLayers; private Map layerDeps; + // layers that were actually excluded from the top config model + private final Set topConfigExcludedLayers = new HashSet<>(0); + private final boolean checkNotExcludedLayers; + ConfigModelStack(ConfigId configId, ProvisioningRuntimeBuilder rt) throws ProvisioningException { this.id = configId; this.rt = rt; lastConfig = new ConfigScope(null); configs.add(lastConfig); newFgScope(); + this.checkNotExcludedLayers = rt.layout.getOptionValue(ProvisioningOption.IGNORE_NOT_EXCLUDED_LAYERS).equals(Constants.FALSE); } int size() { @@ -264,6 +272,18 @@ void pushConfig(ConfigModel model) throws ProvisioningException { ConfigModel popConfig() throws ProvisioningException { lastProcessedScope = lastConfig; final int poppedIndex = configs.size() - 1; + if(checkNotExcludedLayers && poppedIndex == 1 && lastConfig.config.hasExcludedLayers()) { + if(lastConfig.config.getExcludedLayers().size() != topConfigExcludedLayers.size()) { + List notExcluded = new ArrayList<>(); + for(String layer : lastConfig.config.getExcludedLayers()) { + if(!topConfigExcludedLayers.contains(layer)) { + notExcluded.add(layer); + } + } + throw new ProvisioningException(Errors.excludedLayersWouldNotOtherwiseBeInstalled(lastConfig.config.getId(), notExcluded)); + } + topConfigExcludedLayers.clear(); + } configs.remove(poppedIndex); lastConfig = configs.get(poppedIndex - 1); lastProcessedScope.complete(); @@ -377,28 +397,55 @@ boolean isFilteredOut(ResolvedSpecId specId, final ResolvedFeatureId id) { } boolean isLayerFilteredOut(String layerName) { + final int configsTotal = configs.size(); + if(configsTotal == 1) { + return false; + } + if(configsTotal == 2) { + return isFilteredOutFromTopConfig(layerName, lastConfig.config); + } if(lastConfig.isLayerFilteredOut(layerName)) { return true; } - if(configs.size() > 1) { - for (int i = configs.size() - 2; i >= 0; --i) { - if (configs.get(i).isLayerFilteredOut(layerName)) { - return true; + for (int i = configsTotal - 2; i > 1; --i) { + if (configs.get(i).isLayerFilteredOut(layerName)) { + return true; + } + } + return isFilteredOutFromTopConfig(layerName, configs.get(1).config); + } + + private boolean isFilteredOutFromTopConfig(String layerName, final ConfigModel config) { + if(config.isInheritLayers()) { + if(config.isLayerExcluded(layerName)) { + if(checkNotExcludedLayers) { + topConfigExcludedLayers.add(layerName); } + return true; } + } else if(!config.isLayerIncluded(layerName)) { + return true; } return false; } boolean isLayerExcluded(String layerName) { + final int configsTotal = configs.size(); + if(configsTotal == 1) { + return false; + } if(lastConfig.isLayerExcluded(layerName)) { + if(checkNotExcludedLayers && configsTotal == 2) { + topConfigExcludedLayers.add(layerName); + } return true; } - if(configs.size() > 1) { - for (int i = configs.size() - 2; i >= 0; --i) { - if (configs.get(i).isLayerExcluded(layerName)) { - return true; + for (int i = configsTotal - 2; i > 0; --i) { + if (configs.get(i).isLayerExcluded(layerName)) { + if (checkNotExcludedLayers && i == 1) { + topConfigExcludedLayers.add(layerName); } + return true; } } return false; diff --git a/docs/guide/generic-config-model/layers/exclude-layers.adoc b/docs/guide/generic-config-model/layers/exclude-layers.adoc index a6fba029d..7ec246bef 100644 --- a/docs/guide/generic-config-model/layers/exclude-layers.adoc +++ b/docs/guide/generic-config-model/layers/exclude-layers.adoc @@ -18,3 +18,4 @@ Layers that have been included into the configuration can later be excluded from Assuming feature-pack `prod1` included `layer1` and `layer2` into its `model1:name1` configuration (as in the previous example), the resulting `model1:name1` configuration will include only `layer1` and `layer3` (and their dependencies if any). +NOTE: An attempt to exclude a layer that would not have otherwise been installed will result in a provisioning error. The error, however, can be suppressed by adding <<_provisioning_options, provisioning option>> `ignore-not-excluded-layers`. diff --git a/docs/guide/provisioning-options/index.adoc b/docs/guide/provisioning-options/index.adoc index be61eade3..f2383ca5d 100644 --- a/docs/guide/provisioning-options/index.adoc +++ b/docs/guide/provisioning-options/index.adoc @@ -42,8 +42,9 @@ Provisioning options can be provided by the core provisioning mechanism itself a .Built-in provisioning options |=== |Name |Purpose |Value set -|optional-packages |<<_feature_pack_original_effective_package_set,Optional package dependencies inclusion policy>> |`all`, `none`, `passive`, `passive+` -|version-convergence |<<_dependency_version_convergence,Disables or enables the dependency version convergence>> | `first-processed` _(the default one)_, `fail` +|ignore-not-excluded-layers |<<_excluding_layers_from_configuration_models,Suppresses the error when layers configured to be excluded would not have otherwise been installed>> |`false` _(default)_, `true` +|optional-packages |<<_feature_pack_original_effective_package_set,Optional package dependencies inclusion policy>> |`all` _(default)_, `none`, `passive`, `passive+` +|version-convergence |<<_dependency_version_convergence,Disables or enables the dependency version convergence>> | `first-processed` _(default)_, `fail` |=== #### Product provisioning options diff --git a/ide-configs/eclipse/templates.xml b/ide-configs/eclipse/templates.xml index 611d33462..c7badc7ae 100644 --- a/ide-configs/eclipse/templates.xml +++ b/ide-configs/eclipse/templates.xml @@ -1,7 +1,7 @@