This is an automated email from the ASF dual-hosted git repository. davidb pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-modelconverter.git
commit 0e38227cb7de4506eacd622bfb5f9f687fc49021 Author: David Bosschaert <david.bosscha...@gmail.com> AuthorDate: Wed Mar 21 16:24:39 2018 +0000 Write configurations associated with artifacts alongside these --- .../modelconverter/impl/ProvisioningToFeature.java | 73 +++++++++++++++----- .../modelconverter/impl/ModelConverterTest.java | 78 ++++++++++++++++++++-- 2 files changed, 128 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java index a521780..5d0ac7c 100644 --- a/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java +++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java @@ -30,6 +30,7 @@ import org.apache.sling.feature.support.ArtifactManagerConfig; import org.apache.sling.feature.support.FeatureUtil; import org.apache.sling.feature.support.json.ApplicationJSONWriter; import org.apache.sling.feature.support.json.FeatureJSONWriter; +import org.apache.sling.feature.support.json.WriteOption; import org.apache.sling.provisioning.model.Artifact; import org.apache.sling.provisioning.model.ArtifactGroup; import org.apache.sling.provisioning.model.Configuration; @@ -52,6 +53,7 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; @@ -67,7 +69,7 @@ public class ProvisioningToFeature { private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class); public static void convert(File file, String output) { - Model model = createModel(Collections.singletonList(file), null, false); + Model model = createModel(Collections.singletonList(file), null, true, false); final List<org.apache.sling.feature.Feature> features = buildFeatures(model); if (features.size() != 1) throw new IllegalStateException("TODO"); @@ -77,7 +79,7 @@ public class ProvisioningToFeature { public static void convert(List<File> files, String outputFile, String runModes, boolean createApp, boolean includeModelInfo, String propsFile) { - final Model model = createModel(files, runModes, includeModelInfo); + final Model model = createModel(files, runModes, false, includeModelInfo); if ( createApp ) { final Application app = buildApplication(model, propsFile); @@ -99,27 +101,28 @@ public class ProvisioningToFeature { * @param includeModelInfo */ private static Model createModel(final List<File> files, - final String runModes, boolean includeModelInfo) { + final String runModes, boolean allRunModes, boolean includeModelInfo) { LOGGER.info("Assembling model..."); + ResolverOptions variableResolver = new ResolverOptions().variableResolver(new VariableResolver() { + @Override + public String resolve(final Feature feature, final String name) { + // Keep variables as-is in the model + return "${" + name + "}"; + } + }); + Model model = null; for(final File initFile : files) { try { - model = processModel(model, initFile, includeModelInfo, - new ResolverOptions().variableResolver(new VariableResolver() { - @Override - public String resolve(final Feature feature, final String name) { - // Keep variables as-is in the model - return "${" + name + "}"; - } - }) - ); + model = processModel(model, initFile, includeModelInfo, variableResolver); } catch ( final IOException iae) { LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae); System.exit(1); } } - final Map<Traceable, String> errors = ModelUtility.validate(model); + final Model effectiveModel = ModelUtility.getEffectiveModel(model, variableResolver); + final Map<Traceable, String> errors = ModelUtility.validate(effectiveModel); if ( errors != null ) { LOGGER.error("Invalid assembled provisioning model."); for(final Map.Entry<Traceable, String> entry : errors.entrySet()) { @@ -127,11 +130,24 @@ public class ProvisioningToFeature { } System.exit(1); } - final Set<String> modes = calculateRunModes(model, runModes); + final Set<String> modes; + if (allRunModes) { + modes = new HashSet<>(); + for (Feature f : effectiveModel.getFeatures()) { + for (RunMode rm : f.getRunModes()) { + String[] names = rm.getNames(); + if (names != null) { + modes.addAll(Arrays.asList(names)); + } + } + } + } else { + modes = calculateRunModes(effectiveModel, runModes); + } - removeInactiveFeaturesAndRunModes(model, modes); + removeInactiveFeaturesAndRunModes(effectiveModel, modes); - return model; + return effectiveModel; } /** @@ -420,6 +436,29 @@ public class ProvisioningToFeature { final String key = keys.nextElement(); newCfg.getProperties().put(key, cfg.getProperties().get(key)); } + + String[] runModeNames = runMode.getNames(); + if (runModeNames != null) { + // If this configuration is associated with a runmode other than null, attach it to a bundle + // that has the same runmodes + Artifact art = null; + for (ArtifactGroup group : runMode.getArtifactGroups()) { + if (art != null) + break; + + for (Artifact artifact : group) { + art = artifact; + break; + } + } + if (art == null) { + throw new IllegalStateException("Should have at least one artifact in runmodes " + + Arrays.toString(runModeNames) + " to attach configuration to"); + } + + newCfg.getProperties().put(org.apache.sling.feature.Configuration.PROP_ARTIFACT, art.toMvnUrl()); + } + configurations.add(newCfg); } @@ -491,7 +530,7 @@ public class ProvisioningToFeature { final File file = new File(out); try ( final FileWriter writer = new FileWriter(file)) { - FeatureJSONWriter.write(writer, f); + FeatureJSONWriter.write(writer, f, WriteOption.OLD_STYLE_FACTORY_CONFIGS); } catch ( final IOException ioe) { LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe); System.exit(1); diff --git a/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java b/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java index bf35578..6facd22 100644 --- a/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java +++ b/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java @@ -93,6 +93,11 @@ public class ModelConverterTest { testConvertToProvisioningModel("/oak.json", "/oak.txt"); } + @Test + public void testOakToFeature() throws Exception { + testConvertToFeature("/oak.txt", "/oak.json"); + } + public void testConvertToFeature(String originalProvModel, String expectedJSON) throws Exception { File inFile = new File(getClass().getResource(originalProvModel).toURI()); File outFile = new File(tempDir.toFile(), expectedJSON + ".generated"); @@ -133,7 +138,7 @@ public class ModelConverterTest { assertFeatureKVMapEquals(expected.getVariables(), actual.getVariables()); assertBundlesEqual(expected.getBundles(), actual.getBundles()); - assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations()); + assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations(), expected.getBundles(), actual.getBundles()); assertFeatureKVMapEquals(expected.getFrameworkProperties(), actual.getFrameworkProperties()); // Ignore caps and reqs, includes and extensions here since they cannot come from the prov model. @@ -149,26 +154,86 @@ public class ModelConverterTest { if (ac.getId().equals(ex.getId())) { found = true; assertFeatureKVMapEquals(ex.getMetadata(), ac.getMetadata()); + break; } } - assertTrue(found); + assertTrue("Not found: " + ex, found); } } - private void assertConfigurationsEqual(Configurations expected, Configurations actual) { + private void assertConfigurationsEqual(Configurations expected, Configurations actual, Bundles exBundles, Bundles acBundles) { for (Iterator<org.apache.sling.feature.Configuration> it = expected.iterator(); it.hasNext(); ) { org.apache.sling.feature.Configuration ex = it.next(); boolean found = false; for (Iterator<org.apache.sling.feature.Configuration> it2 = actual.iterator(); it2.hasNext(); ) { org.apache.sling.feature.Configuration ac = it2.next(); - if (ac.getPid().equals(ex.getPid())) { + if (ex.getPid() != null) { + if (ex.getPid().equals(ac.getPid())) { + found = true; + assertConfigProps(ex, ac, exBundles, acBundles); + } + } else { + if (ex.getFactoryPid().equals(ac.getFactoryPid())) { + found = true; + assertConfigProps(ex, ac, exBundles, acBundles); + } + } + } + assertTrue(found); + } + } + + private void assertConfigProps(org.apache.sling.feature.Configuration expected, org.apache.sling.feature.Configuration actual, Bundles exBundles, Bundles acBundles) { + // If the configuration is associated with an artifact, it's considered equal + // if both artifacts have the same runmode (as the configuration is really + // associated with the runmode. + Object art = expected.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT); + if (art instanceof String) { + String expectedArtifact = (String) art; + String actualArtifact = (String) actual.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT); + + String expectedRunmodes = null; + for(Iterator<org.apache.sling.feature.Artifact> it = exBundles.iterator(); it.hasNext(); ) { + org.apache.sling.feature.Artifact a = it.next(); + if (a.getId().toMvnId().equals(expectedArtifact)) { + expectedRunmodes = a.getMetadata().get("run-modes"); + } + } + + boolean found = false; + for(Iterator<org.apache.sling.feature.Artifact> it = acBundles.iterator(); it.hasNext(); ) { + org.apache.sling.feature.Artifact a = it.next(); + if (a.getId().toMvnId().equals(actualArtifact)) { found = true; - assertEquals(ex.getProperties(), ac.getProperties()); + assertEquals(expectedRunmodes, a.getMetadata().get("run-modes")); + break; } } assertTrue(found); } + + assertTrue("Configurations not equal: " + expected.getProperties() + " vs " + actual.getProperties(), + configPropsEqual(expected.getProperties(), actual.getProperties())); + } + + private boolean configPropsEqual(Dictionary<String, Object> d1, Dictionary<String, Object> d2) { + if (d1.size() != d2.size()) { + return false; + } + + for (Enumeration<String> e = d1.keys(); e.hasMoreElements(); ) { + String k = e.nextElement(); + Object v = d1.get(k); + if (v instanceof Object[]) { + if (!Arrays.equals((Object[]) v, (Object[]) d2.get(k))) + return false; + } else { + if (!v.equals(d2.get(k))) + return false; + } + } + return true; } private void assertModelsEqual(Model expected, Model actual) { @@ -279,6 +344,7 @@ public class ModelConverterTest { return m1.equals(m2); } + // TODO can this one go? private Map<String, Object> cfgMap(Dictionary<String, Object> properties) { Map<String, Object> m = new HashMap<>(); for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) { @@ -292,7 +358,7 @@ public class ModelConverterTest { String[] kv = line.trim().split("="); if (kv.length >= 2) { - String v = kv[1].trim().replaceAll("[" +Pattern.quote("[") + "]\\s+[\"]", "[\""); + String v = kv[1].trim().replaceAll("[" + Pattern.quote("[") + "]\\s+[\"]", "[\""); v = v.replaceAll("[\"][,]\\s*[]]","\"]"); m.put(kv[0].trim(), v.trim()); } -- To stop receiving notification emails like this one, please contact dav...@apache.org.