Skip to content

Commit

Permalink
Merge pull request #282 from aloubyansky/check-excluded-layers
Browse files Browse the repository at this point in the history
[GAL-306] excluding a layer that wouldn't have been included otherwis…
  • Loading branch information
aloubyansky authored Jan 26, 2020
2 parents 003adff + ec9f931 commit 6ca5d4a
Show file tree
Hide file tree
Showing 15 changed files with 787 additions and 20 deletions.
4 changes: 3 additions & 1 deletion core/src/main/java/org/jboss/galleon/Constants.java
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -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";
Expand Down
14 changes: 13 additions & 1 deletion core/src/main/java/org/jboss/galleon/Errors.java
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -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<String> 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;
Expand Down
10 changes: 8 additions & 2 deletions core/src/main/java/org/jboss/galleon/ProvisioningOption.java
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -44,7 +44,13 @@ public class ProvisioningOption {
.addToValueSet(Constants.FAIL)
.build();

private static final List<ProvisioningOption> 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<ProvisioningOption> stdOptions = Arrays
.asList(new ProvisioningOption[] { IGNORE_NOT_EXCLUDED_LAYERS, OPTIONAL_PACKAGES, VERSION_CONVERGENCE });

public static List<ProvisioningOption> getStandardList() {
return stdOptions;
Expand Down
65 changes: 56 additions & 9 deletions core/src/main/java/org/jboss/galleon/runtime/ConfigModelStack.java
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -20,15 +20,18 @@
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;
import java.util.Map;
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;
Expand Down Expand Up @@ -174,12 +177,17 @@ private boolean isRelevant(ResolvedFeatureGroupConfig resolvedFg) {
private List<ConfigId> includedLayers;
private Map<String, ConfigLayerDependency> layerDeps;

// layers that were actually excluded from the top config model
private final Set<String> 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() {
Expand Down Expand Up @@ -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<String> 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();
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions docs/guide/generic-config-model/layers/exclude-layers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
5 changes: 3 additions & 2 deletions docs/guide/provisioning-options/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions ide-configs/eclipse/templates.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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");
Expand All @@ -18,7 +18,7 @@
-->
<templates><template autoinsert="false" context="filecomment_context" deleted="false" description="Comment for created Java files" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.filecomment" name="filecomment">/*
* 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");
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
Expand Down Expand Up @@ -222,7 +222,7 @@ public void testWithExcludeLayers() throws Exception {
{
Path path = cli.newDir("prod-exclude2", false);
cli.execute("install " + prod + " --dir=" + path
+ " --layers=layerC-" + PRODUCER4 + ",-layerA-" + PRODUCER4 + ",-layerB-" + PRODUCER4);
+ " --layers=layerC-" + PRODUCER4 + ",-layerB-" + PRODUCER4);

ProvisionedState state = ProvisioningManager.builder().setInstallationHome(path).build().getProvisionedState();
assertEquals(1, state.getConfigs().size());
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* 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");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.galleon.provision.config.layers.test;

import org.jboss.galleon.Constants;
import org.jboss.galleon.ProvisioningException;
import org.jboss.galleon.ProvisioningOption;
import org.jboss.galleon.config.ConfigModel;
import org.jboss.galleon.config.FeatureConfig;
import org.jboss.galleon.config.FeaturePackConfig;
import org.jboss.galleon.config.ProvisioningConfig;
import org.jboss.galleon.creator.FeaturePackCreator;
import org.jboss.galleon.spec.ConfigLayerSpec;
import org.jboss.galleon.spec.FeatureParameterSpec;
import org.jboss.galleon.spec.FeatureSpec;
import org.jboss.galleon.state.ProvisionedFeaturePack;
import org.jboss.galleon.state.ProvisionedState;
import org.jboss.galleon.test.util.fs.state.DirState;
import org.jboss.galleon.universe.FeaturePackLocation;
import org.jboss.galleon.universe.MvnUniverse;
import org.jboss.galleon.universe.ProvisionFromUniverseTestBase;
import org.jboss.galleon.xml.ProvisionedConfigBuilder;

/**
*
* @author Alexey Loubyansky
*/
public class ExcludeConfigLayerExcludedAsTransitiveDepIgnoreNotExcludedLayersTestCase extends ProvisionFromUniverseTestBase {

private FeaturePackLocation prod1;

@Override
protected void createProducers(MvnUniverse universe) throws ProvisioningException {
universe.createProducer("prod1");
}

@Override
protected void createFeaturePacks(FeaturePackCreator creator) throws ProvisioningException {

prod1 = newFpl("prod1", "1", "1.0.0.Final");

creator.newFeaturePack()
.setFPID(prod1.getFPID())
.addFeatureSpec(FeatureSpec.builder("specA")
.addParam(FeatureParameterSpec.createId("id"))
.addParam(FeatureParameterSpec.create("p1", "spec"))
.addParam(FeatureParameterSpec.create("p2", "spec"))
.addParam(FeatureParameterSpec.create("p3", "spec"))
.build())
.addConfigLayer(ConfigLayerSpec.builder()
.setModel("model1").setName("base")
.addFeature(new FeatureConfig("specA")
.setParam("id", "base-prod1")
.setParam("p2", "base"))
.addPackageDep("base")
.build())
.addConfigLayer(ConfigLayerSpec.builder()
.setModel("model1").setName("layer1")
.addLayerDep("base", true)
.addFeature(new FeatureConfig("specA")
.setParam("id", "base-prod2")
.setParam("p2", "layer1"))
.build())
.addConfig(ConfigModel.builder("model1", "name1")
.includeLayer("layer1")
.build())
.newPackage("base")
.writeContent("base.txt", "base");

}

@Override
protected ProvisioningConfig provisioningConfig() throws ProvisioningException {
return ProvisioningConfig.builder()
.addFeaturePackDep(FeaturePackConfig.builder(prod1)
.setInheritPackages(false)
.setInheritConfigs(false)
.includeDefaultConfig("model1", "name1")
.build())
.addConfig(ConfigModel.builder("model1", "name1")
.excludeLayer("layer1")
.excludeLayer("base")
.build())
.addOption(ProvisioningOption.IGNORE_NOT_EXCLUDED_LAYERS.getName(), Constants.TRUE)
.build();
}

protected ProvisionedState provisionedState() throws ProvisioningException {
return ProvisionedState.builder()
.addFeaturePack(ProvisionedFeaturePack.builder(prod1.getFPID())
.build())
.addConfig(ProvisionedConfigBuilder.builder()
.setModel("model1")
.setName("name1")
.build())
.build();
}

@Override
protected DirState provisionedHomeDir() {
return newDirBuilder()
.build();
}
}
Loading

0 comments on commit 6ca5d4a

Please sign in to comment.