You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2018/04/27 10:01:18 UTC

[sling-org-apache-sling-feature-modelconverter] branch master created (now deffad0)

This is an automated email from the ASF dual-hosted git repository.

davidb pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-modelconverter.git.


      at deffad0  Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.

This branch includes the following new commits:

     new 8ca0ccb  Move feature model to whiteboard git
     new 3f6643d  Fix converting latest Sling Starter app
     new 2cc2956  Start changing start level handling to start order handling
     new 5775a03  Refactor start order handling
     new 6f0cf99  SLING-7512 Order features based on their dependencies.
     new 75e24a8  Update to parent pom 33
     new b9c87b7  Support the slinstart maven plugin by providing a model converter API
     new 3f388cb  Extra logging
     new 978f1f2  Additional comments for the converter classes.
     new a44574c  Support for special feature names when converting to provisioning model.
     new dac2347  Support variables in converting from features to provisioning model
     new 91f48ed  Support writing variables when converting from provisioning model
     new 9398062  Preserve variables when converting prov model to feature
     new 0e38227  Write configurations associated with artifacts alongside these
     new 6fc7134  Improve test to property unmangle configurations when reading prov model
     new 6fe1aff  Add roundtrip testing prov model -> feature -> prov model
     new c0e97ba  Support comparing extensions in the conversion tests
     new f8d3703  Change how runmodes in configuration are handled in the feature model
     new 767340c  Handle the fact that a single provisioning model can result in multiple features
     new 155663f  Change name of runmodes in configuration
     new 856cd9b  Improve handling of runmodes in provisioning model-feature conversions
     new 83dc4de  Handle runmodes for configurations that have ':' in their name
     new b63fdef  Use model name for feature file name when converting to feature.
     new a21f448  Handle run modes in feature properties similar to configuration
     new 896ebeb  Convert repoinit sections to use JSON array representation
     new 571927a  Small tweak to how files converted from prov model to feature are named
     new 496178b  Add the ability to set groupId and version for generated features
     new a73b2ae  Move the process package from the feature api module to the support one.
     new 60e7e06  Move resolving to separate package
     new feb957c  Move artifact handling to separate package
     new 956cdff  Move Sling specific constants into support module
     new 20184ea  Split feature util into io and assembly parts
     new 399cdbd  Rename to FileUtils and use constants
     new 0844563  Clean up file util
     new ddc06e6  Rename packages
     new 0cc518f  Remove WriteOption from Feature JSON Writer.
     new 1faf0c1  [Sling Feature Model] Split off IO packages into separate module.
     new ac8e761  [Sling Feature Model] Refactor FeatureUtil out of the support module
     new 8efb7c3  [Feature Model] Move constants from support module to feature module
     new deffad0  Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.

The 40 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 08/40: Extra logging

Posted by da...@apache.org.
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 3f388cbbc86695de49565e287d8403e7bd3d146e
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Mon Mar 12 17:29:02 2018 +0000

    Extra logging
---
 .../sling/feature/modelconverter/impl/ProvisioningToFeature.java       | 3 +++
 1 file changed, 3 insertions(+)

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 e3a4a52..59af64d 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
@@ -461,6 +461,9 @@ public class ProvisioningToFeature {
                 out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
             }
         }
+
+        LOGGER.info("to file {}", out);
+
         final File file = new File(out);
         try ( final FileWriter writer = new FileWriter(file)) {
             FeatureJSONWriter.write(writer, f);

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 33/40: Rename to FileUtils and use constants

Posted by da...@apache.org.
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 399cdbda812b06876a3e47329ea027df3b0e358b
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Apr 18 09:55:21 2018 +0200

    Rename to FileUtils and use constants
---
 .../sling/feature/modelconverter/impl/FeatureToProvisioning.java  | 2 +-
 .../sling/feature/modelconverter/impl/ModelConverterTest.java     | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index eb83353..fb565e9 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -62,7 +62,7 @@ public class FeatureToProvisioning {
     static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = org.apache.sling.feature.support.io.FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature feature = org.apache.sling.feature.support.io.FileUtils.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
         Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
         String featureName;
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 87867fb..9f57981 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
@@ -174,8 +174,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FileUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FileUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 
@@ -205,8 +205,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FileUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FileUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 28/40: Move the process package from the feature api module to the support one.

Posted by da...@apache.org.
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 a73b2aed5d9e8565b356d38201c90fa7bbd9a5bb
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 11 16:51:50 2018 +0100

    Move the process package from the feature api module to the support one.
    
    Also move the associated tests.
---
 .../apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 04b8428..4c7089e 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -24,11 +24,11 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.process.FeatureResolver;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
+import org.apache.sling.feature.support.process.FeatureResolver;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 30/40: Move artifact handling to separate package

Posted by da...@apache.org.
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 feb957cb79c12861f470312d742825bbbca59463
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Apr 17 09:51:30 2018 +0200

    Move artifact handling to separate package
---
 .../sling/feature/modelconverter/impl/FeatureToProvisioning.java    | 2 +-
 .../java/org/apache/sling/feature/modelconverter/impl/Main.java     | 4 ++--
 .../sling/feature/modelconverter/impl/ProvisioningToFeature.java    | 6 +++---
 .../sling/feature/modelconverter/impl/ModelConverterTest.java       | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index cf5a3a5..018f99c 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -24,8 +24,8 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.artifact.ArtifactManager;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.support.resolver.FeatureResolver;
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index 81a9e3c..abf7bfb 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -22,8 +22,8 @@ import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
-import org.apache.sling.feature.support.ArtifactManager;
-import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.feature.support.artifact.ArtifactManager;
+import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
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 ce77d76..1f8ce87 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
@@ -24,10 +24,10 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.support.ArtifactHandler;
-import org.apache.sling.feature.support.ArtifactManager;
-import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.artifact.ArtifactHandler;
+import org.apache.sling.feature.support.artifact.ArtifactManager;
+import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.ApplicationJSONWriter;
 import org.apache.sling.feature.support.json.FeatureJSONWriter;
 import org.apache.sling.feature.support.json.WriteOption;
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 1b5f4aa..dfc85ee 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
@@ -21,9 +21,9 @@ import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
-import org.apache.sling.feature.support.ArtifactManager;
-import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.artifact.ArtifactManager;
+import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 24/40: Handle run modes in feature properties similar to configuration

Posted by da...@apache.org.
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 a21f448a23df232b3938130891427301f61e4c77
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 4 13:49:17 2018 +0100

    Handle run modes in feature properties similar to configuration
---
 .../sling/feature/modelconverter/impl/FeatureToProvisioning.java | 9 +++++----
 .../sling/feature/modelconverter/impl/ProvisioningToFeature.java | 4 ++--
 src/test/resources/boot.json                                     | 4 ++--
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 9327df6..3c526c2 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -183,11 +183,12 @@ public class FeatureToProvisioning {
         // framework properties
         for(final Map.Entry<String, String> prop : frameworkProps) {
             String key = prop.getKey();
-            if (key.startsWith(".runmodes:")) {
-                int lastIdx = key.lastIndexOf(':');
-                String rm = key.substring(".runmodes:".length(), lastIdx);
+            int idx = key.indexOf(".runmodes:");
+
+            if (idx > 0) {
+                String rm = key.substring(idx + ".runmodes:".length());
                 String[] runmodes = rm.split(",");
-                key = key.substring(lastIdx + 1);
+                key = key.substring(0, idx);
                 f.getOrCreateRunMode(runmodes).getSettings().put(key, prop.getValue());
             } else {
                 f.getOrCreateRunMode(null).getSettings().put(key, prop.getValue());
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 4693ba8..70a6d76 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
@@ -398,8 +398,8 @@ public class ProvisioningToFeature {
                 if (runModeNames == null) {
                     properties.put(prop.getKey(), prop.getValue());
                 } else {
-                    properties.put(".runmodes:" + String.join(",", runModeNames) + ":" +
-                            prop.getKey(), prop.getValue());
+                    properties.put(prop.getKey() + ".runmodes:" + String.join(",", runModeNames),
+                            prop.getValue());
                 }
             }
         }
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
index 4cc7d40..e535f7b 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot.json
@@ -92,8 +92,8 @@
         "localIndexDir": "${sling.home}/repository/index",
         
         "# we need runmodes here too...": "",
-        ".runmodes:a:something": "else",
-        ".runmodes::b:special": "true", 
+        "something.runmodes:a": "else",
+        "special.runmodes::b": "true", 
         
         "#": "${sling.home} needs to be provided at launch time"
     }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 04/40: Refactor start order handling

Posted by da...@apache.org.
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 5775a03073a53258e0bab9bb623bbe94683c758d
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 19 08:07:53 2018 +0100

    Refactor start order handling
---
 .../org/apache/sling/feature/modelconverter/impl/Main.java   | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index fedd964..9f5aaf9 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -656,13 +656,17 @@ public class Main {
         final Feature f = new Feature("application");
 
         // bundles
-        for(final Map.Entry<Integer, org.apache.sling.feature.Artifact> bundle : app.getBundles().getAllBundles()) {
-            final ArtifactId id = bundle.getValue().getId();
+        for(final org.apache.sling.feature.Artifact bundle : app.getBundles()) {
+            final ArtifactId id = bundle.getId();
             final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
-            for(final Map.Entry<String, String> prop : bundle.getValue().getMetadata()) {
+            for(final Map.Entry<String, String> prop : bundle.getMetadata()) {
                 newBundle.getMetadata().put(prop.getKey(), prop.getValue());
             }
-            f.getOrCreateRunMode(null).getOrCreateArtifactGroup(bundle.getKey()).add(newBundle);
+            int startLevel = bundle.getStartOrder();
+            if ( startLevel == 0 ) {
+                startLevel = 20;
+            }
+            f.getOrCreateRunMode(null).getOrCreateArtifactGroup(startLevel).add(newBundle);
         }
 
         // configurations

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 20/40: Change name of runmodes in configuration

Posted by da...@apache.org.
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 155663f4a77118191360ff127136ec9f97ebdfda
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Fri Mar 23 11:36:07 2018 +0000

    Change name of runmodes in configuration
---
 .../sling/feature/modelconverter/impl/FeatureToProvisioning.java      | 2 +-
 .../sling/feature/modelconverter/impl/ProvisioningToFeature.java      | 2 +-
 src/test/resources/oak.json                                           | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index aded77c..3c904fe 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -163,7 +163,7 @@ public class FeatureToProvisioning {
             }
 
             String[] runModes = null;
-            Object rm = c.getProperties().remove(".runmodes.");
+            Object rm = c.getProperties().remove(".runmodes");
             if (rm instanceof String) {
                 runModes = ((String) rm).split(",");
             }
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 9f88aae..62a4f00 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
@@ -442,7 +442,7 @@ public class ProvisioningToFeature {
 
                 String[] runModeNames = runMode.getNames();
                 if (runModeNames != null) {
-                    newCfg.getProperties().put(".runmodes.", String.join(",", runModeNames));
+                    newCfg.getProperties().put(".runmodes", String.join(",", runModeNames));
                 }
 
                 configurations.add(newCfg);
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
index 4ba64cb..d94aa8d 100644
--- a/src/test/resources/oak.json
+++ b/src/test/resources/oak.json
@@ -87,11 +87,11 @@
             "groupPrivilegeNames": ["jcr:read"]
         },
         "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
-            ".runmodes.": "oak_tar", 
+            ".runmodes": "oak_tar", 
             "name": "Default NodeStore"
         },
         "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
-            ".runmodes.": "oak_mongo", 
+            ".runmodes": "oak_mongo", 
             "mongouri": "mongodb://localhost:27017",
             "db": "sling"
         }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 22/40: Handle runmodes for configurations that have ':' in their name

Posted by da...@apache.org.
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 83dc4de664c6bcfec84b043aabc5cc0698af86c8
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Apr 3 15:22:47 2018 +0100

    Handle runmodes for configurations that have ':' in their name
---
 .../modelconverter/impl/FeatureToProvisioning.java |  2 +-
 .../modelconverter/impl/ProvisioningToFeature.java | 34 ++++++++--------------
 .../modelconverter/impl/ModelConverterTest.java    | 22 ++++++++++----
 src/test/resources/launchpad.json                  |  4 +--
 4 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index dd6d830..9327df6 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -157,7 +157,7 @@ public class FeatureToProvisioning {
                 c = new Configuration(cfg.getName(), cfg.getFactoryPid());
             } else {
                 String pid = cfg.getPid();
-                pid = pid.replaceAll("[.][.](\\S+)", ":$1");
+                pid = pid.replaceAll("[.][.](\\w+)", ":$1");
                 int rmIdx = pid.indexOf(".runmodes.");
                 if (rmIdx > 0) {
                     String rm = pid.substring(rmIdx + ".runmodes.".length());
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 6af4aa3..5f87e1f 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
@@ -427,32 +427,22 @@ public class ProvisioningToFeature {
             }
 
             for(final Configuration cfg : runMode.getConfigurations()) {
-                final org.apache.sling.feature.Configuration newCfg;
-                if ( cfg.getFactoryPid() != null ) {
-                    String pid = cfg.getPid();
-                    if (pid.startsWith(":")) {
-                        // The configurator doesn't accept colons ':' in it's keys, so replace these
-                        pid = ".." + pid.substring(1);
-                    }
+                String pid = cfg.getPid();
+                if (pid.startsWith(":")) {
+                    // The configurator doesn't accept colons ':' in it's keys, so replace these
+                    pid = ".." + pid.substring(1);
+                }
 
-                    String[] runModeNames = runMode.getNames();
-                    if (runModeNames != null) {
-                        pid = pid + ".runmodes." + String.join(".", runModeNames);
-                    }
+                final String[] runModeNames = runMode.getNames();
+                if (runModeNames != null) {
+                    pid = pid + ".runmodes." + String.join(".", runModeNames);
+                    pid = pid.replaceAll("[:]", "..");
+                }
 
+                final org.apache.sling.feature.Configuration newCfg;
+                if ( cfg.getFactoryPid() != null ) {
                     newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), pid);
                 } else {
-                    String pid = cfg.getPid();
-                    if (pid.startsWith(":")) {
-                        // The configurator doesn't accept colons ':' in it's keys, so replace these
-                        pid = ".." + pid.substring(1);
-                    }
-
-                    String[] runModeNames = runMode.getNames();
-                    if (runModeNames != null) {
-                        pid = pid + ".runmodes." + String.join(".", runModeNames);
-                    }
-
                     newCfg = new org.apache.sling.feature.Configuration(pid);
                 }
                 final Enumeration<String> keys = cfg.getProperties().keys();
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 249d9dc..72e0c08 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
@@ -48,6 +48,7 @@ import java.io.IOException;
 import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -70,18 +71,26 @@ public class ModelConverterTest {
 
     @Before
     public void setup() throws Exception {
-        tempDir = Files.createTempDirectory(getClass().getSimpleName());
+        String tmpDir = System.getProperty("test.prov.files.tempdir");
+        if (tmpDir != null) {
+            tempDir = Paths.get(tmpDir);
+            System.out.println("*** Using directory for generated files: " + tempDir);
+        } else {
+            tempDir = Files.createTempDirectory(getClass().getSimpleName());
+        }
         artifactManager = ArtifactManager.getArtifactManager(
                 new ArtifactManagerConfig());
     }
 
     @After
     public void tearDown() throws Exception {
-        // Delete the temp dir again
-        Files.walk(tempDir)
-            .sorted(Comparator.reverseOrder())
-            .map(Path::toFile)
-            .forEach(File::delete);
+        if(System.getProperty("test.prov.files.tempdir") == null) {
+            // Delete the temp dir again
+            Files.walk(tempDir)
+                .sorted(Comparator.reverseOrder())
+                .map(Path::toFile)
+                .forEach(File::delete);
+        }
     }
 
     @Test
@@ -151,6 +160,7 @@ public class ModelConverterTest {
     }
 
     public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
+        System.out.println("*** Roundtrip converting: " + orgProvModel.getName());
         String genJSONPrefix = orgProvModel.getName() + ".json";
         String genTxtPrefix = orgProvModel.getName() + ".txt";
         String genSuffix = ".generated";
diff --git a/src/test/resources/launchpad.json b/src/test/resources/launchpad.json
index 0dd9318..2fa94b3 100644
--- a/src/test/resources/launchpad.json
+++ b/src/test/resources/launchpad.json
@@ -18,10 +18,10 @@
     "..bootstrap":{
       "..bootstrap":"uninstall com.google.guava 15.0.0\n"
     },
-    "..bootstrap.runmodes.:standalone":{
+    "..bootstrap.runmodes...standalone":{
       "..bootstrap":"uninstall org.apache.felix.http.bridge\nuninstall org.apache.felix.http.api\n"
     },
-    "org.apache.testing.ConfigPid.factory-configuration.runmodes.:standalone":{
+    "org.apache.testing.ConfigPid.factory-configuration.runmodes...standalone":{
       "key1":"val1"
     }
   }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 39/40: [Feature Model] Move constants from support module to feature module

Posted by da...@apache.org.
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 8efb7c3aeb4188e5b377294f3bbd6a7423c8d207
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Apr 26 09:50:10 2018 +0100

    [Feature Model] Move constants from support module to feature module
    
    EXTENSION_NAME_REPOINIT and EXTENSION_NAME_CONTENT_PACKAGES were moved
    from SlingConstants in feature-support to FeatureConstants in feature.
---
 .../feature/modelconverter/impl/FeatureToProvisioning.java     |  6 +++---
 .../feature/modelconverter/impl/ProvisioningToFeature.java     | 10 +++++-----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 995d47f..95f1055 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -23,6 +23,7 @@ import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.FeatureConstants;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.io.ArtifactManager;
 import org.apache.sling.feature.io.IOUtils;
@@ -30,7 +31,6 @@ import org.apache.sling.feature.io.json.ApplicationJSONReader;
 import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.resolver.ApplicationResolverAssembler;
 import org.apache.sling.feature.resolver.FeatureResolver;
-import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
@@ -206,7 +206,7 @@ public class FeatureToProvisioning {
 
         // extensions: content packages and repoinit
         for(final Extension ext : extensions) {
-            if ( SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
+            if ( FeatureConstants.EXTENSION_NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
                 for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
                     String[] runmodes = null;
                     final ArtifactId id = cp.getId();
@@ -221,7 +221,7 @@ public class FeatureToProvisioning {
                     f.getOrCreateRunMode(runmodes).getOrCreateArtifactGroup(20).add(newCP);
                 }
 
-            } else if ( SlingConstants.EXTENSION_NAME_REPOINIT.equals(ext.getName()) ) {
+            } else if ( FeatureConstants.EXTENSION_NAME_REPOINIT.equals(ext.getName()) ) {
                 final Section section = new Section("repoinit");
                 if (ext.getType() == ExtensionType.TEXT) {
                     section.setContents(ext.getText());
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 f1e86d0..0cd2311 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
@@ -23,6 +23,7 @@ import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.FeatureConstants;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.io.ArtifactHandler;
 import org.apache.sling.feature.io.ArtifactManager;
@@ -30,7 +31,6 @@ import org.apache.sling.feature.io.ArtifactManagerConfig;
 import org.apache.sling.feature.io.IOUtils;
 import org.apache.sling.feature.io.json.ApplicationJSONWriter;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
-import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;
@@ -335,7 +335,7 @@ public class ProvisioningToFeature {
             variables.put(FeatureToProvisioning.PROVISIONING_MODEL_NAME_VARIABLE, feature.getName());
         }
 
-        Extension cpExtension = extensions.getByName(SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES);
+        Extension cpExtension = extensions.getByName(FeatureConstants.EXTENSION_NAME_CONTENT_PACKAGES);
         for(final RunMode runMode : feature.getRunModes() ) {
             for(final ArtifactGroup group : runMode.getArtifactGroups()) {
                 for(final Artifact artifact : group) {
@@ -348,7 +348,7 @@ public class ProvisioningToFeature {
 
                     if ( newArtifact.getId().getType().equals("zip") ) {
                         if ( cpExtension == null ) {
-                            cpExtension = new Extension(ExtensionType.ARTIFACTS, SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES, true);
+                            cpExtension = new Extension(ExtensionType.ARTIFACTS, FeatureConstants.EXTENSION_NAME_CONTENT_PACKAGES, true);
                             extensions.add(cpExtension);
                         }
                         cpExtension.getArtifacts().add(newArtifact);
@@ -411,7 +411,7 @@ public class ProvisioningToFeature {
                 }
             }
         }
-        Extension repoExtension = extensions.getByName(SlingConstants.EXTENSION_NAME_REPOINIT);
+        Extension repoExtension = extensions.getByName(FeatureConstants.EXTENSION_NAME_REPOINIT);
         for(final Section sect : feature.getAdditionalSections("repoinit")) {
             String text = sect.getContents();
             if ( repoExtension == null ) {
@@ -419,7 +419,7 @@ public class ProvisioningToFeature {
 //                extensions.add(repoExtension);
 //                repoExtension.setJSON(text);
 
-                repoExtension = new Extension(ExtensionType.JSON, SlingConstants.EXTENSION_NAME_REPOINIT, true);
+                repoExtension = new Extension(ExtensionType.JSON, FeatureConstants.EXTENSION_NAME_REPOINIT, true);
                 extensions.add(repoExtension);
                 text = text.replace('\t', ' ');
                 String[] lines = text.split("[\n]");

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 34/40: Clean up file util

Posted by da...@apache.org.
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 08445633c249d525df51e67c83138fcd44b4414b
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Apr 18 10:12:08 2018 +0200

    Clean up file util
---
 .../sling/feature/modelconverter/impl/FeatureToProvisioning.java | 2 +-
 .../sling/feature/modelconverter/impl/ModelConverterTest.java    | 9 +++++----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index fb565e9..fd1d268 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -62,7 +62,7 @@ public class FeatureToProvisioning {
     static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = org.apache.sling.feature.support.io.FileUtils.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
         Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
         String featureName;
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 9f57981..86705da 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
@@ -44,6 +44,7 @@ import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.artifact.ArtifactManager;
 import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
@@ -174,8 +175,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FileUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FileUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 
@@ -205,8 +206,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FileUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FileUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 17/40: Support comparing extensions in the conversion tests

Posted by da...@apache.org.
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 c0e97bad492f89c0390813172c25f0dba5d8a095
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Mar 22 12:03:25 2018 +0000

    Support comparing extensions in the conversion tests
---
 .../modelconverter/impl/ModelConverterTest.java    | 52 ++++++++++++++-
 src/test/resources/repoinit.json                   | 74 ++++++++++++++++++++
 src/test/resources/repoinit.txt                    | 78 ++++++++++++++++++++++
 3 files changed, 201 insertions(+), 3 deletions(-)

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 194d95c..2c0567c 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
@@ -18,6 +18,8 @@ package org.apache.sling.feature.modelconverter.impl;
 
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Configurations;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.FeatureUtil;
@@ -96,7 +98,7 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testOakProvModel() throws Exception {
+    public void testOakToProvModel() throws Exception {
         testConvertToProvisioningModel("/oak.json", "/oak.txt");
     }
 
@@ -110,6 +112,21 @@ public class ModelConverterTest {
         testConvertFromProvModelRoundTrip("/oak.txt");
     }
 
+    @Test
+    public void testRepoinitToProvModel() throws Exception {
+        testConvertToProvisioningModel("/repoinit.json", "/repoinit.txt");
+    }
+
+    @Test
+    public void testRepoinitToFeature() throws Exception {
+        testConvertToFeature("/repoinit.txt", "/repoinit.json");
+    }
+
+    @Test
+    public void testRepoinitRoundtrip() throws Exception {
+        testConvertFromProvModelRoundTrip("/repoinit.txt");
+    }
+
     public void testConvertFromProvModelRoundTrip(String orgProvModel) throws Exception {
         File inFile = new File(getClass().getResource(orgProvModel).toURI());
         File outJSONFile = new File(tempDir.toFile(), orgProvModel + ".json.generated");
@@ -176,8 +193,9 @@ public class ModelConverterTest {
         assertBundlesEqual(expected.getBundles(), actual.getBundles());
         assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations(), expected.getBundles(), actual.getBundles());
         assertFeatureKVMapEquals(expected.getFrameworkProperties(), actual.getFrameworkProperties());
+        assertExtensionEqual(expected.getExtensions(), actual.getExtensions());
 
-        // Ignore caps and reqs, includes and extensions here since they cannot come from the prov model.
+        // Ignore caps and reqs, includes and here since they cannot come from the prov model.
     }
 
     private void assertBundlesEqual(Bundles expected, Bundles actual) {
@@ -440,6 +458,33 @@ public class ModelConverterTest {
         assertEquals(featureKvToMap(expected), featureKvToMap(actual));
     }
 
+    private void assertExtensionEqual(Extensions expected, Extensions actual) {
+        assertEquals(expected.size(), actual.size());
+
+        for (int i=0; i<expected.size(); i++) {
+            // TODO support the fact that they may be out of order
+            Extension ex = expected.get(i);
+            Extension ac = actual.get(i);
+
+            assertEquals(ex.getType(), ac.getType());
+            assertEquals(ex.getName(), ac.getName());
+            assertEquals(ex.isRequired(), ac.isRequired());
+
+            String exTxt = ex.getText().replaceAll("\\s+", "");
+            String acTxt = ac.getText().replaceAll("\\s+", "");
+            assertEquals(exTxt, acTxt);
+
+            /* TODO reinstantiate for Artifacts extentions
+            assertEquals(ex.getArtifacts().size(), ac.getArtifacts().size());
+            for (int j = 0; j<ex.getArtifacts().size(); j++) {
+                org.apache.sling.feature.Artifact exa = ex.getArtifacts().get(j);
+                org.apache.sling.feature.Artifact aca = ac.getArtifacts().get(j);
+                assertEquals(exa.getId().toMvnId(), aca.getId().toMvnId());
+            }
+            */
+        }
+    }
+
     private void assertSectionsEqual(List<Section> expected, List<Section> actual) {
         assertEquals(expected.size(), actual.size());
 
@@ -447,7 +492,8 @@ public class ModelConverterTest {
             Section esec = expected.get(i);
             Section asec = actual.get(i);
             assertEquals(esec.getName(), asec.getName());
-            assertEquals(esec.getContents(), asec.getContents());
+            assertEquals(esec.getContents().replaceAll("\\s+", ""),
+                    asec.getContents().replaceAll("\\s+", ""));
             assertEquals(esec.getAttributes(), asec.getAttributes());
         }
     }
diff --git a/src/test/resources/repoinit.json b/src/test/resources/repoinit.json
new file mode 100644
index 0000000..01d3b16
--- /dev/null
+++ b/src/test/resources/repoinit.json
@@ -0,0 +1,74 @@
+{
+    "#": "this is a comment",
+
+    "id": "org.apache.sling.simple/repoinit/1.0.0",
+    "bundles": [
+        {
+            "id": "org.apache.sling/org.apache.sling.repoinit.parser/1.2.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.jcr.repoinit/1.1.6",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.provisioning.model/1.8.4",
+            "start-level": 20
+        }
+    ],
+    "configurations": {
+        "org.apache.sling.jcr.repoinit.impl.RepositoryInitializer": {
+            "references":"model@repoinit:context:/resources/provisioning/model.txt"
+        }
+    },
+    "repoinit:TEXT|false": [
+        "# general",
+        "create path (sling:OrderedFolder) /content",
+        "set ACL for everyone",
+        "    allow   jcr:read	on /content",
+        "end",
+
+        "# sling-mapping",
+        "create service user sling-mapping",
+
+        "set ACL for sling-mapping",
+        "    allow   jcr:read    on /",
+        "end",
+
+        "# sling-readall",
+        "create service user sling-readall",
+
+        "set ACL for sling-readall",
+        "    allow   jcr:read    on /",
+        "end",
+
+        "# sling-xss",
+        "create service user sling-xss",
+
+        "create path (sling:Folder) /libs/sling/xss",
+        "create path (sling:Folder) /apps/sling/xss",
+
+        "set ACL for sling-xss",
+        "    deny    jcr:all     on /",
+        "    allow   jcr:read    on /libs/sling/xss,/apps/sling/xss",
+        "end",
+
+        "# sling-i18n",
+        "create service user sling-i18n",
+
+        "set ACL for sling-i18n",
+        "    allow   jcr:read    on /",
+        "end",
+
+        "# sling-jcr-install",
+        "create service user sling-jcr-install",
+
+        "# used for config OSGi writeback",
+        "create path (sling:Folder) /apps/sling/install",
+
+        "set ACL for sling-jcr-install",
+        "    allow	jcr:read	on	/",
+        "    allow	rep:write	on /apps/sling/install",
+        "end"
+    ]
+}
diff --git a/src/test/resources/repoinit.txt b/src/test/resources/repoinit.txt
new file mode 100644
index 0000000..9e1227b
--- /dev/null
+++ b/src/test/resources/repoinit.txt
@@ -0,0 +1,78 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+#
+[feature name=repoinit]
+
+[artifacts]
+  org.apache.sling/org.apache.sling.repoinit.parser/1.2.0
+  org.apache.sling/org.apache.sling.jcr.repoinit/1.1.6
+  org.apache.sling/org.apache.sling.provisioning.model/1.8.4
+
+[:repoinit]
+    # general
+    create path (sling:OrderedFolder) /content
+    set ACL for everyone
+        allow   jcr:read	on /content
+    end
+
+    # sling-mapping
+    create service user sling-mapping
+
+    set ACL for sling-mapping
+        allow   jcr:read    on /
+    end
+
+    # sling-readall
+    create service user sling-readall
+
+    set ACL for sling-readall
+        allow   jcr:read    on /
+    end
+
+    # sling-xss
+    create service user sling-xss
+
+    create path (sling:Folder) /libs/sling/xss
+    create path (sling:Folder) /apps/sling/xss
+
+    set ACL for sling-xss
+        deny    jcr:all     on /
+        allow   jcr:read    on /libs/sling/xss,/apps/sling/xss
+    end
+
+    # sling-i18n
+    create service user sling-i18n
+
+    set ACL for sling-i18n
+        allow   jcr:read    on /
+    end
+
+    # sling-jcr-install
+    create service user sling-jcr-install
+
+    # used for config OSGi writeback
+    create path (sling:Folder) /apps/sling/install
+
+    set ACL for sling-jcr-install
+        allow	jcr:read	on	/
+        allow	rep:write	on /apps/sling/install
+    end
+
+[configurations]
+  org.apache.sling.jcr.repoinit.impl.RepositoryInitializer
+    references="model@repoinit:context:/resources/provisioning/model.txt"

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 15/40: Improve test to property unmangle configurations when reading prov model

Posted by da...@apache.org.
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 6fc71349c3d3f91e330b90c8964d0687e03331a6
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Mar 21 16:34:11 2018 +0000

    Improve test to property unmangle configurations when reading prov model
---
 .../modelconverter/impl/ModelConverterTest.java    | 47 ++++++++--------------
 1 file changed, 16 insertions(+), 31 deletions(-)

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 6facd22..8a03fa1 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
@@ -29,6 +29,9 @@ import org.apache.sling.provisioning.model.Feature;
 import org.apache.sling.provisioning.model.KeyValueMap;
 import org.apache.sling.provisioning.model.Model;
 import org.apache.sling.provisioning.model.ModelConstants;
+import org.apache.sling.provisioning.model.ModelUtility;
+import org.apache.sling.provisioning.model.ModelUtility.ResolverOptions;
+import org.apache.sling.provisioning.model.ModelUtility.VariableResolver;
 import org.apache.sling.provisioning.model.RunMode;
 import org.apache.sling.provisioning.model.Section;
 import org.apache.sling.provisioning.model.io.ModelReader;
@@ -52,7 +55,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Pattern;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -126,7 +128,17 @@ public class ModelConverterTest {
 
     private static Model readProvisioningModel(File modelFile) throws IOException {
         try (final FileReader is = new FileReader(modelFile)) {
-            return ModelReader.read(is, modelFile.getAbsolutePath());
+            Model model = ModelReader.read(is, modelFile.getAbsolutePath());
+
+            // Fix the configurations up from the internal format to the Dictionary-based format
+            return ModelUtility.getEffectiveModel(model,
+                    new ResolverOptions().variableResolver(new VariableResolver() {
+                @Override
+                public String resolve(final Feature feature, final String name) {
+                    // Keep variables as-is in the model
+                    return "${" + name + "}";
+                }
+            }));
         }
     }
 
@@ -328,11 +340,10 @@ public class ModelConverterTest {
                     }
                 }
 
-                Map<String, Object> m1 = cfgMap(cfg1.getProperties());
-                Map<String, Object> m2 = cfgMap(cfg2.getProperties());
-                if (!m1.equals(m2)) {
+                if (!configPropsEqual(cfg1.getProperties(), cfg2.getProperties())) {
                     return false;
                 }
+
                 break;
             }
             assertTrue("Configuration with PID " + cfg1.getPid() + " not found", found);
@@ -344,32 +355,6 @@ 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(); ) {
-            String key = e.nextElement();
-            Object value = properties.get(key);
-            if (ModelConstants.CFG_UNPROCESSED.equals(key) && value instanceof String) {
-                String val = (String) value;
-                // Collapse line continuation characters
-                val = val.replaceAll("[\\\\]\\r?\\n", "");
-                for (String line : val.split("\\r?\\n")) {
-
-                    String[] kv = line.trim().split("=");
-                    if (kv.length >= 2) {
-                        String v = kv[1].trim().replaceAll("[" + Pattern.quote("[") + "]\\s+[\"]", "[\"");
-                        v = v.replaceAll("[\"][,]\\s*[]]","\"]");
-                        m.put(kv[0].trim(), v.trim());
-                    }
-                }
-            } else {
-                m.put(key, value);
-            }
-        }
-        return m;
-    }
-
     private Map<String, String> kvToMap(KeyValueMap<String> kvm) {
         Map<String, String> m = new HashMap<>();
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 03/40: Start changing start level handling to start order handling

Posted by da...@apache.org.
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 2cc29564528687dd8156ce74fd1896baa9e1cbda
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Jan 18 16:14:50 2018 +0100

    Start changing start level handling to start order handling
---
 .../org/apache/sling/feature/modelconverter/impl/Main.java    | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index ff88255..fedd964 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -28,7 +28,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
@@ -271,7 +270,7 @@ public class Main {
 
         for(final Feature feature : model.getFeatures() ) {
             final String idString;
-            // use a default name if not present or not usable as a Maven artifactId ( starts with ':') 
+            // use a default name if not present or not usable as a Maven artifactId ( starts with ':')
             if ( feature.getName() != null && !feature.isSpecial() ) {
                 if ( feature.getVersion() != null ) {
                     idString = "generated/" + feature.getName() + "/" + feature.getVersion();
@@ -298,7 +297,8 @@ public class Main {
         }
 
         // hard coded dependency to launchpad api
-        app.getBundles().add(1, new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0")));
+        final org.apache.sling.feature.Artifact a = new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
+        a.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, "1");
         // sling.properties (TODO)
         if ( propsFile == null ) {
             app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");
@@ -340,7 +340,8 @@ public class Main {
                             } else if ( startLevel == 0 ) {
                                 startLevel = 20;
                             }
-                            bundles.add(startLevel, newArtifact);
+                            newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
+                            bundles.add(newArtifact);
                         }
                     }
                 }
@@ -655,7 +656,7 @@ public class Main {
         final Feature f = new Feature("application");
 
         // bundles
-        for(final Map.Entry<Integer, org.apache.sling.feature.Artifact> bundle : app.getBundles()) {
+        for(final Map.Entry<Integer, org.apache.sling.feature.Artifact> bundle : app.getBundles().getAllBundles()) {
             final ArtifactId id = bundle.getValue().getId();
             final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
             for(final Map.Entry<String, String> prop : bundle.getValue().getMetadata()) {

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 37/40: [Sling Feature Model] Split off IO packages into separate module.

Posted by da...@apache.org.
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 1faf0c127d4ec2582b26893b10a9bcdad8ef6c23
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 25 10:58:43 2018 +0100

    [Sling Feature Model] Split off IO packages into separate module.
---
 pom.xml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pom.xml b/pom.xml
index c77652f..8386c38 100644
--- a/pom.xml
+++ b/pom.xml
@@ -131,6 +131,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.io</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature.resolver</artifactId>
             <version>0.0.1-SNAPSHOT</version>
             <scope>provided</scope>

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 18/40: Change how runmodes in configuration are handled in the feature model

Posted by da...@apache.org.
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 f8d3703e0c8ee24bbbb909858febc3ff891731ca
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Mar 22 14:45:20 2018 +0000

    Change how runmodes in configuration are handled in the feature model
    
    With this commit, the runmodes can be specified with a configuration
    using the ".runmodes." property. The value is a comma-separated string.
---
 .../modelconverter/impl/FeatureToProvisioning.java | 14 ++---
 .../modelconverter/impl/ProvisioningToFeature.java | 19 +------
 .../modelconverter/impl/ModelConverterTest.java    | 64 ++++++----------------
 src/test/resources/oak.json                        | 24 ++++----
 4 files changed, 34 insertions(+), 87 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 28cdff9..aded77c 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -162,16 +162,10 @@ public class FeatureToProvisioning {
                 c.getProperties().put(key, cfg.getProperties().get(key));
             }
 
-            // Remove these if they got in
-            c.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT);
-
-            // Check if the configuration has an associated runmode via the bundle that it belongs to
-            org.apache.sling.feature.Artifact bundle = configBundleMap.get(cfg);
-            String[] runModes;
-            if (bundle != null) {
-                runModes = getRunModes(bundle);
-            } else {
-                runModes = null;
+            String[] runModes = null;
+            Object rm = c.getProperties().remove(".runmodes.");
+            if (rm instanceof String) {
+                runModes = ((String) rm).split(",");
             }
             f.getOrCreateRunMode(runModes).getConfigurations().add(c);
         }
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 5d0ac7c..d34d471 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
@@ -439,24 +439,7 @@ public class ProvisioningToFeature {
 
                 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());
+                    newCfg.getProperties().put(".runmodes.", String.join(",", runModeNames));
                 }
 
                 configurations.add(newCfg);
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 2c0567c..fb8b571 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,11 +93,6 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testBootRoundTrip() throws Exception {
-        testConvertFromProvModelRoundTrip("/boot.txt");
-    }
-
-    @Test
     public void testOakToProvModel() throws Exception {
         testConvertToProvisioningModel("/oak.json", "/oak.txt");
     }
@@ -108,11 +103,6 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testOakRoundTrip() throws Exception {
-        testConvertFromProvModelRoundTrip("/oak.txt");
-    }
-
-    @Test
     public void testRepoinitToProvModel() throws Exception {
         testConvertToProvisioningModel("/repoinit.json", "/repoinit.txt");
     }
@@ -123,20 +113,30 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testRepoinitRoundtrip() throws Exception {
-        testConvertFromProvModelRoundTrip("/repoinit.txt");
+    public void testProvModelRoundtripFolder() throws Exception {
+        String dir = System.getProperty("test.prov.files.dir");
+        File filesDir;
+        if (dir != null) {
+            filesDir = new File(dir);
+        } else {
+            filesDir = new File(getClass().getResource("/repoinit.txt").toURI()).
+                getParentFile();
+        }
+
+        for (File f : filesDir.listFiles((d, n) -> n.endsWith(".txt"))) {
+            testConvertFromProvModelRoundTrip(f);
+        }
     }
 
-    public void testConvertFromProvModelRoundTrip(String orgProvModel) throws Exception {
-        File inFile = new File(getClass().getResource(orgProvModel).toURI());
-        File outJSONFile = new File(tempDir.toFile(), orgProvModel + ".json.generated");
-        File outProvFile = new File(tempDir.toFile(), orgProvModel + ".txt.generated");
+    public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
+        File outJSONFile = new File(tempDir.toFile(), orgProvModel.getName() + ".json.generated");
+        File outProvFile = new File(tempDir.toFile(), orgProvModel.getName() + ".txt.generated");
 
-        ProvisioningToFeature.convert(inFile, outJSONFile.getAbsolutePath());
+        ProvisioningToFeature.convert(orgProvModel, outJSONFile.getAbsolutePath());
         FeatureToProvisioning.convert(outJSONFile, outProvFile.getAbsolutePath(),
                 artifactManager);
 
-        Model expected = readProvisioningModel(inFile);
+        Model expected = readProvisioningModel(orgProvModel);
         Model actual = readProvisioningModel(outProvFile);
         assertModelsEqual(expected, actual);
     }
@@ -239,34 +239,6 @@ public class ModelConverterTest {
     }
 
     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(expectedRunmodes, a.getMetadata().get("run-modes"));
-                    break;
-                }
-            }
-            assertTrue(found);
-        }
-
         assertTrue("Configurations not equal: " + expected.getProperties() + " vs " + actual.getProperties(),
                 configPropsEqual(expected.getProperties(), actual.getProperties()));
     }
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
index ab50c29..4ba64cb 100644
--- a/src/test/resources/oak.json
+++ b/src/test/resources/oak.json
@@ -33,23 +33,12 @@
         {
             "id": "org.apache.jackrabbit/oak-segment-tar/${oak.version}",
             "start-level": 15,
-            "run-modes": "oak_tar",
-            "configurations": {
-                "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
-                    "name": "Default NodeStore"
-                }
-            }
+            "run-modes": "oak_tar"
         },
         {
             "id": "org.mongodb/mongo-java-driver/3.4.1",
             "start-level": 15,
-            "run-modes": "oak_mongo",
-            "configurations": {
-                "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
-                    "mongouri": "mongodb://localhost:27017",
-                    "db": "sling"
-                }
-            }
+            "run-modes": "oak_mongo"
         },
         {
             "id": "com.h2database/h2-mvstore/1.4.196",
@@ -96,6 +85,15 @@
             "enabledActions": ["org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction"],
             "userPrivilegeNames": ["jcr:all"],
             "groupPrivilegeNames": ["jcr:read"]
+        },
+        "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
+            ".runmodes.": "oak_tar", 
+            "name": "Default NodeStore"
+        },
+        "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
+            ".runmodes.": "oak_mongo", 
+            "mongouri": "mongodb://localhost:27017",
+            "db": "sling"
         }
     }
 }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 23/40: Use model name for feature file name when converting to feature.

Posted by da...@apache.org.
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 b63fdefe2866d35c48b688d09318ea3a084a4ff3
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 4 13:30:55 2018 +0100

    Use model name for feature file name when converting to feature.
---
 .../modelconverter/impl/ProvisioningToFeature.java | 106 +++++----------------
 .../modelconverter/impl/ModelConverterTest.java    |  22 ++---
 2 files changed, 30 insertions(+), 98 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 5f87e1f..4693ba8 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
@@ -68,16 +68,27 @@ import java.util.Set;
 public class ProvisioningToFeature {
     private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class);
 
-    public static void convert(File file, String output) {
+    public static List<File> convert(File file, File outDir) {
         Model model = createModel(Collections.singletonList(file), null, true, false);
         final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
-        if (features.size() != 1) {
-            for (int i=0; i<features.size(); i++) {
-                writeFeature(features.get(i), output, i+1);
+
+        List<File> files = new ArrayList<>();
+        for (org.apache.sling.feature.Feature f : features) {
+            String id = f.getVariables().get("provisioning.model.name");
+            if (id == null) {
+                id = f.getId().getArtifactId();
             }
-        } else {
-            writeFeature(features.get(0), output, 0);
+
+            File outFile = new File(outDir, id + ".json");
+            int counter = 0;
+            while (outFile.exists()) {
+                outFile = new File(outDir, id + "_" + (++counter) + ".json");
+            }
+
+            files.add(outFile);
+            writeFeature(f, outFile.getAbsolutePath(), 0);
         }
+        return files;
     }
 
     public static void convert(List<File> files,  String outputFile, String runModes, boolean createApp,
@@ -148,8 +159,6 @@ public class ProvisioningToFeature {
             modes = calculateRunModes(effectiveModel, runModes);
         }
 
-        // removeInactiveFeaturesAndRunModes(effectiveModel, modes);
-
         return effectiveModel;
     }
 
@@ -237,81 +246,6 @@ public class ProvisioningToFeature {
         }
     }
 
-    // TODO is this needed for something?
-    private static void removeInactiveFeaturesAndRunModes(final Model m,
-            final Set<String> activeRunModes) {
-        final String[] requiredFeatures = new String[] {ModelConstants.FEATURE_LAUNCHPAD, ModelConstants.FEATURE_BOOT};
-        // first pass:
-        // - remove special features except boot required ones
-        // - remove special run modes and inactive run modes
-        // - remove special configurations (TODO)
-        final Iterator<Feature> i = m.getFeatures().iterator();
-        while ( i.hasNext() ) {
-            final Feature feature = i.next();
-            if ( feature.isSpecial() ) {
-                boolean remove = true;
-                if ( requiredFeatures != null ) {
-                    for(final String name : requiredFeatures) {
-                        if ( feature.getName().equals(name) ) {
-                            remove = false;
-                            break;
-                        }
-                    }
-                }
-                if ( remove ) {
-                    i.remove();
-                    continue;
-                }
-            }
-            feature.setComment(null);
-            final Iterator<RunMode> rmI = feature.getRunModes().iterator();
-            while ( rmI.hasNext() ) {
-                final RunMode rm = rmI.next();
-                if ( rm.isActive(activeRunModes) || rm.isRunMode(ModelConstants.RUN_MODE_STANDALONE) ) {
-                    final Iterator<Configuration> cI = rm.getConfigurations().iterator();
-                    while ( cI.hasNext() ) {
-                        final Configuration config = cI.next();
-                        if ( config.isSpecial() ) {
-                            cI.remove();
-                            continue;
-                        }
-                        config.setComment(null);
-                    }
-                } else {
-                    rmI.remove();
-                    continue;
-                }
-            }
-        }
-
-        // second pass: aggregate the settings and add them to the first required feature
-        final Feature requiredFeature = m.getFeature(requiredFeatures[0]);
-        if ( requiredFeature != null ) {
-            for(final Feature f : m.getFeatures()) {
-                if ( f.getName().equals(requiredFeature.getName()) ) {
-                    continue;
-                }
-                copyAndClearSettings(requiredFeature, f.getRunMode(new String[] {ModelConstants.RUN_MODE_STANDALONE}));
-                copyAndClearSettings(requiredFeature, f.getRunMode());
-            }
-        }
-    }
-
-    private static void copyAndClearSettings(final Feature requiredFeature, final RunMode rm) {
-        if ( rm != null && !rm.getSettings().isEmpty() ) {
-            final RunMode requiredRunMode = requiredFeature.getOrCreateRunMode(null);
-            final Set<String> keys = new HashSet<>();
-            for(final Map.Entry<String, String> entry : rm.getSettings()) {
-                requiredRunMode.getSettings().put(entry.getKey(), entry.getValue());
-                keys.add(entry.getKey());
-            }
-
-            for(final String key : keys) {
-                rm.getSettings().remove(key);
-            }
-        }
-    }
-
     private static Set<String> calculateRunModes(final Model model, final String runModes) {
         final Set<String> modesSet = new HashSet<>();
 
@@ -530,8 +464,12 @@ public class ProvisioningToFeature {
         }
 
         LOGGER.info("to file {}", out);
-
         final File file = new File(out);
+        while (file.exists()) {
+            LOGGER.error("Output file already exists: {}", file.getAbsolutePath());
+            System.exit(1);
+        }
+
         try ( final FileWriter writer = new FileWriter(file)) {
             FeatureJSONWriter.write(writer, f, WriteOption.OLD_STYLE_FACTORY_CONFIGS);
         } catch ( final IOException ioe) {
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 72e0c08..4231489 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
@@ -161,19 +161,13 @@ public class ModelConverterTest {
 
     public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
         System.out.println("*** Roundtrip converting: " + orgProvModel.getName());
-        String genJSONPrefix = orgProvModel.getName() + ".json";
-        String genTxtPrefix = orgProvModel.getName() + ".txt";
-        String genSuffix = ".generated";
-        File outJSONFile = new File(tempDir.toFile(), genJSONPrefix + genSuffix);
         List<File> allGenerateProvisioningModelFiles = new ArrayList<>();
 
-        ProvisioningToFeature.convert(orgProvModel, outJSONFile.getAbsolutePath());
+        List<File> generated = ProvisioningToFeature.convert(orgProvModel, tempDir.toFile());
 
-        for (File f : tempDir.toFile().listFiles((p, n) -> n.startsWith(genJSONPrefix))) {
-            String infix = f.getName().substring(genJSONPrefix.length(),
-                    f.getName().length() - genSuffix.length());
-
-            File genFile = new File(tempDir.toFile(), genTxtPrefix + infix + genSuffix);
+        for (File f : generated) {
+            String baseName = f.getName().substring(0, f.getName().length() - ".json".length());
+            File genFile = new File(tempDir.toFile(), baseName + ".txt");
             allGenerateProvisioningModelFiles.add(genFile);
             FeatureToProvisioning.convert(f, genFile.getAbsolutePath(), artifactManager);
         }
@@ -185,14 +179,14 @@ public class ModelConverterTest {
 
     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");
 
-        String outPath = outFile.getAbsolutePath();
-        ProvisioningToFeature.convert(inFile, outPath);
+        List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile());
+        assertEquals("The testing code expects a single output file here", 1, files.size());
+        File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
         org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outPath, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 02/40: Fix converting latest Sling Starter app

Posted by da...@apache.org.
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 3f6643dc7b5721efa739b0fea3649a1a3f92afa9
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Tue Nov 28 13:34:46 2017 +0200

    Fix converting latest Sling Starter app
---
 .../java/org/apache/sling/feature/modelconverter/impl/Main.java    | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index f030367..ff88255 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -271,7 +271,8 @@ public class Main {
 
         for(final Feature feature : model.getFeatures() ) {
             final String idString;
-            if ( feature.getName() != null ) {
+            // use a default name if not present or not usable as a Maven artifactId ( starts with ':') 
+            if ( feature.getName() != null && !feature.isSpecial() ) {
                 if ( feature.getVersion() != null ) {
                     idString = "generated/" + feature.getName() + "/" + feature.getVersion();
                 } else {
@@ -280,7 +281,7 @@ public class Main {
             } else {
                 idString = "generated/feature/1.0.0";
             }
-            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.fromMvnId(idString));
+            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
             features.add(f);
 
             buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
@@ -297,7 +298,7 @@ public class Main {
         }
 
         // hard coded dependency to launchpad api
-        app.getBundles().add(1, new org.apache.sling.feature.Artifact(ArtifactId.fromMvnId("org.apache.sling/org.apache.sling.launchpad.api/1.2.0")));
+        app.getBundles().add(1, new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0")));
         // sling.properties (TODO)
         if ( propsFile == null ) {
             app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 13/40: Preserve variables when converting prov model to feature

Posted by da...@apache.org.
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 9398062a3c6d447ebb1e89a3847a7adea9a92049
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Mar 20 14:14:05 2018 +0000

    Preserve variables when converting prov model to feature
---
 .../modelconverter/impl/ProvisioningToFeature.java | 70 +++++++--------
 .../modelconverter/impl/ModelConverterTest.java    | 99 ++++++++++++++++++++--
 2 files changed, 129 insertions(+), 40 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 0df66db..a521780 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
@@ -104,24 +104,22 @@ public class ProvisioningToFeature {
         Model model = null;
         for(final File initFile : files) {
             try {
-                model = processModel(model, initFile, includeModelInfo);
+                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 + "}";
+                        }
+                    })
+                );
             } catch ( final IOException iae) {
                 LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae);
                 System.exit(1);
             }
         }
 
-        final Model effectiveModel = ModelUtility.getEffectiveModel(model, new ResolverOptions().variableResolver(new VariableResolver() {
-
-            @Override
-            public String resolve(Feature feature, String name) {
-                if ( "sling.home".equals(name) ) {
-                    return "${sling.home}";
-                }
-                return feature.getVariables().get(name);
-            }
-        }));
-        final Map<Traceable, String> errors = ModelUtility.validate(effectiveModel);
+        final Map<Traceable, String> errors = ModelUtility.validate(model);
         if ( errors != null ) {
             LOGGER.error("Invalid assembled provisioning model.");
             for(final Map.Entry<Traceable, String> entry : errors.entrySet()) {
@@ -129,11 +127,11 @@ public class ProvisioningToFeature {
             }
             System.exit(1);
         }
-        final Set<String> modes = calculateRunModes(effectiveModel, runModes);
+        final Set<String> modes = calculateRunModes(model, runModes);
 
-        removeInactiveFeaturesAndRunModes(effectiveModel, modes);
+        removeInactiveFeaturesAndRunModes(model, modes);
 
-        return effectiveModel;
+        return model;
     }
 
     /**
@@ -145,19 +143,22 @@ public class ProvisioningToFeature {
      * @throws IOException If reading fails
      */
     private static Model processModel(Model model,
-            final File modelFile, boolean includeModelInfo) throws IOException {
+            File modelFile, boolean includeModelInfo) throws IOException {
+        return processModel(model, modelFile, includeModelInfo,
+            new ResolverOptions().variableResolver(new VariableResolver() {
+                @Override
+                public String resolve(final Feature feature, final String name) {
+                    return name;
+                }
+            })
+        );
+    }
+
+    private static Model processModel(Model model,
+            File modelFile, boolean includeModelInfo, ResolverOptions options) throws IOException {
         LOGGER.info("- reading model {}", modelFile);
 
         final Model nextModel = readProvisioningModel(modelFile);
-        // resolve references to other models
-        final ResolverOptions options = new ResolverOptions().variableResolver(new VariableResolver() {
-
-            @Override
-            public String resolve(final Feature feature, final String name) {
-                return name;
-            }
-        });
-
 
         final Model effectiveModel = ModelUtility.getEffectiveModel(nextModel, options);
         for(final Feature feature : effectiveModel.getFeatures()) {
@@ -210,11 +211,10 @@ public class ProvisioningToFeature {
     /**
      * Read the provisioning model
      */
-    public static Model readProvisioningModel(final File file)
+    private static Model readProvisioningModel(final File file)
     throws IOException {
         try (final FileReader is = new FileReader(file)) {
-            final Model m = ModelReader.read(is, file.getAbsolutePath());
-            return m;
+            return ModelReader.read(is, file.getAbsolutePath());
         }
     }
 
@@ -393,14 +393,14 @@ public class ProvisioningToFeature {
                             cpExtension.getArtifacts().add(newArtifact);
                         } else {
                             int startLevel = group.getStartLevel();
-                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
-                                startLevel = 1;
-                            } else if ( startLevel == 0 ) {
-                                startLevel = 20;
+                            if ( startLevel == 0) {
+                                if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
+                                    startLevel = 1;
+                                } else if ( startLevel == 0 ) {
+                                    startLevel = 20;
+                                }
                             }
-
-                            // TODO this is probably not correct
-                            // newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
+                            newArtifact.getMetadata().put("start-level", String.valueOf(startLevel));
 
                             bundles.add(newArtifact);
                         }
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 1572e9a..bf35578 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
@@ -16,8 +16,12 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
+import org.apache.sling.feature.Bundles;
+import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;
@@ -27,11 +31,13 @@ import org.apache.sling.provisioning.model.Model;
 import org.apache.sling.provisioning.model.ModelConstants;
 import org.apache.sling.provisioning.model.RunMode;
 import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.io.ModelReader;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.nio.file.Files;
@@ -43,6 +49,7 @@ import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -76,10 +83,10 @@ public class ModelConverterTest {
         testConvertToProvisioningModel("/boot.json", "/boot.txt");
     }
 
-    /* @Test
+    @Test
     public void testBootToFeature() throws Exception {
         testConvertToFeature("/boot.txt", "/boot.json");
-    } */
+    }
 
     @Test
     public void testOak() throws Exception {
@@ -90,7 +97,13 @@ public class ModelConverterTest {
         File inFile = new File(getClass().getResource(originalProvModel).toURI());
         File outFile = new File(tempDir.toFile(), expectedJSON + ".generated");
 
-        ProvisioningToFeature.convert(inFile, outFile.getAbsolutePath());
+        String outPath = outFile.getAbsolutePath();
+        ProvisioningToFeature.convert(inFile, outPath);
+
+        String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
+        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outPath, artifactManager, SubstituteVariables.NONE);
+        assertFeaturesEqual(expected, actual);
     }
 
     public void testConvertToProvisioningModel(String originalJSON, String expectedProvModel) throws URISyntaxException, IOException {
@@ -101,11 +114,63 @@ public class ModelConverterTest {
                 artifactManager);
 
         File expectedFile = new File(getClass().getResource(expectedProvModel).toURI());
-        Model expected = ProvisioningToFeature.readProvisioningModel(expectedFile);
-        Model actual = ProvisioningToFeature.readProvisioningModel(outFile);
+        Model expected = readProvisioningModel(expectedFile);
+        Model actual = readProvisioningModel(outFile);
         assertModelsEqual(expected, actual);
     }
 
+    private static Model readProvisioningModel(File modelFile) throws IOException {
+        try (final FileReader is = new FileReader(modelFile)) {
+            return ModelReader.read(is, modelFile.getAbsolutePath());
+        }
+    }
+
+    private void assertFeaturesEqual(org.apache.sling.feature.Feature expected, org.apache.sling.feature.Feature actual) {
+        assertEquals(expected.getTitle(), actual.getTitle());
+        assertEquals(expected.getDescription(), actual.getDescription());
+        assertEquals(expected.getVendor(), actual.getVendor());
+        assertEquals(expected.getLicense(), actual.getLicense());
+
+        assertFeatureKVMapEquals(expected.getVariables(), actual.getVariables());
+        assertBundlesEqual(expected.getBundles(), actual.getBundles());
+        assertConfigurationsEqual(expected.getConfigurations(), actual.getConfigurations());
+        assertFeatureKVMapEquals(expected.getFrameworkProperties(), actual.getFrameworkProperties());
+
+        // Ignore caps and reqs, includes and extensions here since they cannot come from the prov model.
+    }
+
+    private void assertBundlesEqual(Bundles expected, Bundles actual) {
+        for (Iterator<org.apache.sling.feature.Artifact> it = expected.iterator(); it.hasNext(); ) {
+            org.apache.sling.feature.Artifact ex = it.next();
+
+            boolean found = false;
+            for (Iterator<org.apache.sling.feature.Artifact> it2 = actual.iterator(); it2.hasNext(); ) {
+                org.apache.sling.feature.Artifact ac = it2.next();
+                if (ac.getId().equals(ex.getId())) {
+                    found = true;
+                    assertFeatureKVMapEquals(ex.getMetadata(), ac.getMetadata());
+                }
+            }
+            assertTrue(found);
+        }
+    }
+
+    private void assertConfigurationsEqual(Configurations expected, Configurations actual) {
+        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())) {
+                    found = true;
+                    assertEquals(ex.getProperties(), ac.getProperties());
+                }
+            }
+            assertTrue(found);
+        }
+    }
+
     private void assertModelsEqual(Model expected, Model actual) {
         for (int i=0; i<expected.getFeatures().size(); i++) {
             Feature expectedFeature = expected.getFeatures().get(i);
@@ -189,6 +254,15 @@ public class ModelConverterTest {
                 }
                 found = true;
 
+                if (cfg1.getFactoryPid() == null) {
+                    if (cfg2.getFactoryPid() != null)
+                        return false;
+                } else {
+                    if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) {
+                        return false;
+                    }
+                }
+
                 Map<String, Object> m1 = cfgMap(cfg1.getProperties());
                 Map<String, Object> m2 = cfgMap(cfg2.getProperties());
                 if (!m1.equals(m2)) {
@@ -240,6 +314,16 @@ public class ModelConverterTest {
         return m;
     }
 
+    private Map<String, String> featureKvToMap(org.apache.sling.feature.KeyValueMap kvm) {
+        Map<String, String> m = new HashMap<>();
+
+        for (Map.Entry<String, String> entry : kvm) {
+            m.put(entry.getKey(), entry.getValue());
+        }
+
+        return m;
+    }
+
     private boolean artifactGroupsEquals(String featureName, ArtifactGroup g1, ArtifactGroup g2) {
         int sl1 = effectiveStartLevel(featureName, g1.getStartLevel());
         int sl2 = effectiveStartLevel(featureName, g2.getStartLevel());
@@ -276,6 +360,11 @@ public class ModelConverterTest {
         assertEquals(kvToMap(expected), kvToMap(actual));
     }
 
+    private void assertFeatureKVMapEquals(org.apache.sling.feature.KeyValueMap expected,
+            org.apache.sling.feature.KeyValueMap actual) {
+        assertEquals(featureKvToMap(expected), featureKvToMap(actual));
+    }
+
     private void assertSectionsEqual(List<Section> expected, List<Section> actual) {
         assertEquals(expected.size(), actual.size());
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 05/40: SLING-7512 Order features based on their dependencies.

Posted by da...@apache.org.
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 6f0cf99e2b3145603b6304255814350a01896c10
Author: David Bosschaert <bo...@adobe.com>
AuthorDate: Fri Feb 23 13:42:28 2018 +0000

    SLING-7512 Order features based on their dependencies.
    
    Very initial implementation which contains the refactoring of
    Requirements and Capabilities to use the OSGi ones.
---
 pom.xml                                                     |  6 ++++++
 .../org/apache/sling/feature/modelconverter/impl/Main.java  | 13 +++++++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 64dbec0..93d619b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.resolver</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature.support</artifactId>
             <version>0.0.1-SNAPSHOT</version>
             <scope>provided</scope>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index 9f5aaf9..ccc3f85 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -43,6 +43,8 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.process.FeatureResolver;
+import org.apache.sling.feature.resolver.FrameworkResolver;
 import org.apache.sling.feature.support.ArtifactHandler;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
@@ -165,6 +167,10 @@ public class Main {
         return null;
     }
 
+    private static FeatureResolver getFeatureResolver(ArtifactManager am) {
+        return new FrameworkResolver(am, Collections.emptyMap());
+    }
+
     public static void main(final String[] args) {
         // setup logging
         System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
@@ -241,7 +247,7 @@ public class Main {
             if ( output == null ) {
                 output = createApp ? "application.txt" : "feature.txt";
             }
-            try {
+            try (FeatureResolver fr = getFeatureResolver(am)) {
                 if ( createApp ) {
                     // each file is an application
                     int index = 1;
@@ -253,7 +259,7 @@ public class Main {
                         index++;
                     }
                 } else {
-                    final Application app = FeatureUtil.assembleApplication(null, am, files.stream()
+                    final Application app = FeatureUtil.assembleApplication(null, am, fr, files.stream()
                             .map(File::getAbsolutePath)
                             .toArray(String[]::new));
                     convert(app, 0);
@@ -261,6 +267,9 @@ public class Main {
             } catch ( final IOException ioe) {
                 LOGGER.error("Unable to read feature/application files " + ioe.getMessage(), ioe);
                 System.exit(1);
+            } catch ( final Exception e) {
+                LOGGER.error("Problem generating application", e);
+                System.exit(1);
             }
         }
     }

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 14/40: Write configurations associated with artifacts alongside these

Posted by da...@apache.org.
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 <da...@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
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 10/40: Support for special feature names when converting to provisioning model.

Posted by da...@apache.org.
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 a44574c5dcdc5aba2aed89b379218d76da5a7e7c
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Mon Mar 19 15:09:52 2018 +0000

    Support for special feature names when converting to provisioning model.
    
    The special feature names must be specified in the variables section
    under the variable name 'provisioning.model.name'.
    This commit also contains the start of a document-based set of tests for
    testing between conversions of the feature model to the provisioning
    model and back.
---
 pom.xml                                            |   9 +
 .../modelconverter/impl/FeatureToProvisioning.java |   9 +-
 .../modelconverter/impl/ProvisioningToFeature.java |   2 +-
 .../modelconverter/impl/ModelConverterTest.java    | 211 +++++++++++++++++++++
 src/test/resources/boot.json                       |  41 ++++
 src/test/resources/boot.txt                        |  26 +++
 6 files changed, 292 insertions(+), 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2e0c607..8d19064 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,6 +72,15 @@
                     </archive>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>src/test/resources/**</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
     
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 6679020..2325549 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -48,15 +48,14 @@ import java.util.Map;
 /** Converter that converts the feature model to the provisioning model.
  */
 public class FeatureToProvisioning {
-    private static Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
+    private static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
         org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am);
 
-        String featureName;
-        if (feature.getTitle() != null) {
-            featureName = feature.getTitle();
-        } else {
+        String featureName = feature.getVariables().get(PROVISIONING_MODEL_NAME_VARIABLE);
+        if (featureName == null) {
             featureName = feature.getId().getArtifactId();
         }
 
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 57f13c6..860de6b 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
@@ -199,7 +199,7 @@ public class ProvisioningToFeature {
     /**
      * Read the provisioning model
      */
-    private static Model readProvisioningModel(final File file)
+    static Model readProvisioningModel(final File file)
     throws IOException {
         try (final FileReader is = new FileReader(file)) {
             final Model m = ModelReader.read(is, file.getAbsolutePath());
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
new file mode 100644
index 0000000..bba43c5
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/modelconverter/impl/ModelConverterTest.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.feature.modelconverter.impl;
+
+import org.apache.sling.feature.support.ArtifactManager;
+import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.KeyValueMap;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.RunMode;
+import org.apache.sling.provisioning.model.Section;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ModelConverterTest {
+    private Path tempDir;
+    private ArtifactManager artifactManager;
+
+    @Before
+    public void setup() throws Exception {
+        tempDir = Files.createTempDirectory(getClass().getSimpleName());
+        artifactManager = ArtifactManager.getArtifactManager(
+                new ArtifactManagerConfig());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Delete the temp dir again
+        Files.walk(tempDir)
+            .sorted(Comparator.reverseOrder())
+            .map(Path::toFile)
+            .forEach(File::delete);
+    }
+
+    @Test
+    public void testBoot() throws Exception {
+        File inFile = new File(getClass().getResource("/boot.json").toURI());
+        File outFile = new File(tempDir.toFile(), "/boot.generated.txt");
+
+        FeatureToProvisioning.convert(inFile, outFile.getAbsolutePath(),
+                artifactManager);
+
+        File expectedFile = new File(getClass().getResource("/boot.txt").toURI());
+        Model expected = ProvisioningToFeature.readProvisioningModel(expectedFile);
+        Model actual = ProvisioningToFeature.readProvisioningModel(outFile);
+        assertModelsEqual(expected, actual);
+    }
+
+    private void assertModelsEqual(Model expected, Model actual) {
+        for (int i=0; i<expected.getFeatures().size(); i++) {
+            Feature expectedFeature = expected.getFeatures().get(i);
+            Feature actualFeature = actual.getFeatures().get(i);
+            assertFeaturesEqual(expectedFeature, actualFeature);
+        }
+    }
+
+    private void assertFeaturesEqual(Feature expected, Feature actual) {
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getVersion(), actual.getVersion());
+        assertEquals(expected.getType(), actual.getType());
+        assertRunModesEqual(expected.getRunModes(), actual.getRunModes());
+        assertKVMapEquals(expected.getVariables(), actual.getVariables());
+        assertSectionsEqual(expected.getAdditionalSections(), actual.getAdditionalSections());
+    }
+
+    private void assertRunModesEqual(List<RunMode> expected, List<RunMode> actual) {
+        assertEquals(expected.size(), actual.size());
+        for (RunMode rm : expected) {
+            boolean found = false;
+            for (RunMode arm : actual) {
+                if (runModesEqual(rm, arm)) {
+                    found = true;
+                    break;
+                }
+
+            }
+            if (!found) {
+                fail("Run Mode " + rm + " not found in actual list " + actual);
+            }
+        }
+    }
+
+    private boolean runModesEqual(RunMode rm1, RunMode rm2) {
+        if (rm1.getNames() == null) {
+            if (rm2.getNames() != null)
+                return false;
+        } else {
+            HashSet<String> names1 = new HashSet<>(Arrays.asList(rm1.getNames()));
+            HashSet<String> names2 = new HashSet<>(Arrays.asList(rm2.getNames()));
+
+            if (!names1.equals(names2))
+                return false;
+        }
+
+        List<ArtifactGroup> ag1 = rm1.getArtifactGroups();
+        List<ArtifactGroup> ag2 = rm2.getArtifactGroups();
+        if (ag1.size() != ag2.size())
+            return false;
+
+        for (ArtifactGroup g1 : ag1) {
+            boolean found = false;
+            for (ArtifactGroup g2 : ag2) {
+                if (artifactGroupsEquals(g1, g2)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+                return false;
+        }
+
+        List<Configuration> configs1 = new ArrayList<>();
+        rm1.getConfigurations().iterator().forEachRemaining(configs1::add);
+        List<Configuration> configs2 = new ArrayList<>();
+        rm2.getConfigurations().iterator().forEachRemaining(configs2::add);
+        if (configs1.size() != configs2.size())
+            return false;
+
+        for (int i=0; i < configs1.size(); i++) {
+            Configuration cfg1 = configs1.get(i);
+            Configuration cfg2 = configs2.get(i);
+            if (!cfg1.getProperties().equals(cfg2.getProperties()))
+                return false;
+        }
+
+        Map<String, String> m1 = kvToMap(rm1.getSettings());
+        Map<String, String> m2 = kvToMap(rm2.getSettings());
+
+        return m1.equals(m2);
+    }
+
+    private Map<String, String> kvToMap(KeyValueMap<String> kvm) {
+        Map<String, String> m = new HashMap<>();
+
+        for (Map.Entry<String, String> entry : kvm) {
+            m.put(entry.getKey(), entry.getValue());
+        }
+
+        return m;
+    }
+
+    private boolean artifactGroupsEquals(ArtifactGroup g1, ArtifactGroup g2) {
+        if (g1.getStartLevel() != g2.getStartLevel())
+            return false;
+
+        List<Artifact> al1 = new ArrayList<>();
+        g1.iterator().forEachRemaining(al1::add);
+
+        List<Artifact> al2 = new ArrayList<>();
+        g2.iterator().forEachRemaining(al2::add);
+
+        for (int i=0; i < al1.size(); i++) {
+            Artifact a1 = al1.get(i);
+            Artifact a2 = al2.get(i);
+            if (a1.compareTo(a2) != 0)
+                return false;
+        }
+        return true;
+    }
+
+    private void assertKVMapEquals(KeyValueMap<String> expected, KeyValueMap<String> actual) {
+        assertEquals(expected.size(), actual.size());
+        for (Map.Entry<String, String> entry : expected) {
+            assertEquals(entry.getValue(), actual.get(entry.getKey()));
+        }
+    }
+
+    private void assertSectionsEqual(List<Section> expected, List<Section> actual) {
+        assertEquals(expected.size(), actual.size());
+
+        for (int i=0; i<expected.size(); i++) {
+            Section esec = expected.get(i);
+            Section asec = actual.get(i);
+            assertEquals(esec.getName(), asec.getName());
+            assertEquals(esec.getContents(), asec.getContents());
+            assertEquals(esec.getAttributes(), asec.getAttributes());
+        }
+    }
+}
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
new file mode 100644
index 0000000..2a17a40
--- /dev/null
+++ b/src/test/resources/boot.json
@@ -0,0 +1,41 @@
+{
+    "#": "The model version defaults to 1 if not specified",
+    "model-version": "1",
+    
+    "id": "org.apache.sling.simple/boot/1.0.0",
+    "variables": {
+        "slf4j.version": "1.7.25",
+        
+        "#": "The model name when transformed to the provisioning model",
+        "provisioning.model.name": ":boot"
+    },
+    "bundles": 
+        ["org.slf4j/slf4j-api/${slf4j.version}",
+        "org.apache.sling/org.apache.sling.commons.log/5.1.0",
+        "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
+        "org.slf4j/jcl-over-slf4j/${slf4j.version}",
+        "org.slf4j/log4j-over-slf4j/${slf4j.version}",
+        "org.apache.sling/org.apache.sling.settings/1.3.8",
+        "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
+        "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
+        "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
+        "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
+        "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
+        "org.apache.sling/org.apache.sling.installer.core/3.8.12",
+        "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
+        "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
+        "org.apache.felix/org.apache.felix.configadmin/1.8.16",
+        "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
+        "org.apache.aries/org.apache.aries.util/1.1.3",
+        "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0"],
+        
+    "framework-properties": {
+        "# oak_tar and oak_mongo run modes are mutually exclusive":
+        "# and cannot be changed after the first startup",
+    
+        "sling.run.mode.install.options": "oak_tar,oak_mongo",
+        "repository.home": "${sling.home}/repository",
+        "localIndexDir": "${sling.home}/repository/index",
+        "#": "${sling.home} needs to be provided at launch time"
+    }
+}
diff --git a/src/test/resources/boot.txt b/src/test/resources/boot.txt
new file mode 100644
index 0000000..b8d2e7f
--- /dev/null
+++ b/src/test/resources/boot.txt
@@ -0,0 +1,26 @@
+[feature name=:boot]
+
+[settings]
+  localIndexDir=${sling.home}/repository/index
+  repository.home=${sling.home}/repository
+  sling.run.mode.install.options=oak_tar,oak_mongo
+
+[artifacts startLevel=20]
+  org.apache.aries/org.apache.aries.util/1.1.3
+  org.apache.felix/org.apache.felix.configadmin/1.8.16
+  org.apache.felix/org.apache.felix.eventadmin/1.4.10
+  org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0
+  org.apache.sling/org.apache.sling.commons.log/5.1.0
+  org.apache.sling/org.apache.sling.commons.logservice/1.0.6
+  org.apache.sling/org.apache.sling.fragment.transaction/1.0.0
+  org.apache.sling/org.apache.sling.fragment.ws/1.0.2
+  org.apache.sling/org.apache.sling.fragment.xml/1.0.2
+  org.apache.sling/org.apache.sling.installer.core/3.8.12
+  org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2
+  org.apache.sling/org.apache.sling.installer.provider.file/1.1.0
+  org.apache.sling/org.apache.sling.javax.activation/0.1.0
+  org.apache.sling/org.apache.sling.launchpad.installer/1.2.2
+  org.apache.sling/org.apache.sling.settings/1.3.8
+  org.slf4j/jcl-over-slf4j/1.7.25
+  org.slf4j/log4j-over-slf4j/1.7.25
+  org.slf4j/slf4j-api/1.7.25

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 32/40: Split feature util into io and assembly parts

Posted by da...@apache.org.
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 20184eaef362e39140fcef74aff574caf48b5d13
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Apr 17 16:56:40 2018 +0200

    Split feature util into io and assembly parts
---
 .../modelconverter/impl/FeatureToProvisioning.java |  2 +-
 .../modelconverter/impl/ModelConverterTest.java    | 55 +++++++++++-----------
 2 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index fd1d268..eb83353 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -62,7 +62,7 @@ public class FeatureToProvisioning {
     static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature feature = org.apache.sling.feature.support.io.FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
         Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
         String featureName;
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 dfc85ee..87867fb 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
@@ -16,12 +16,34 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
-import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.artifact.ArtifactManager;
 import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
@@ -43,29 +65,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 public class ModelConverterTest {
     private Path tempDir;
     private ArtifactManager artifactManager;
@@ -175,8 +174,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 
@@ -206,8 +205,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = org.apache.sling.feature.support.io.FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = org.apache.sling.feature.support.io.FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 38/40: [Sling Feature Model] Refactor FeatureUtil out of the support module

Posted by da...@apache.org.
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 ac8e7616597c6a870eca67cb4d38cbad73938774
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 25 13:40:18 2018 +0100

    [Sling Feature Model] Refactor FeatureUtil out of the support module
    
    Also move the Resolver API to the resolver module.
---
 .../modelconverter/impl/FeatureToProvisioning.java | 45 +++++++++++-----------
 .../modelconverter/impl/ProvisioningToFeature.java |  4 +-
 .../modelconverter/impl/ModelConverterTest.java    | 10 ++---
 3 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 11041f8..995d47f 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -16,24 +16,6 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonReader;
-import javax.json.JsonString;
-import javax.json.JsonValue;
-
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
@@ -43,11 +25,12 @@ import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.IOUtils;
 import org.apache.sling.feature.io.json.ApplicationJSONReader;
 import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
-import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.resolver.ApplicationResolverAssembler;
+import org.apache.sling.feature.resolver.FeatureResolver;
 import org.apache.sling.feature.support.SlingConstants;
-import org.apache.sling.feature.support.resolver.FeatureResolver;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
@@ -57,6 +40,24 @@ import org.apache.sling.provisioning.model.io.ModelWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonReader;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+
 /** Converter that converts the feature model to the provisioning model.
  */
 public class FeatureToProvisioning {
@@ -64,7 +65,7 @@ public class FeatureToProvisioning {
     static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature feature = IOUtils.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
         Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
         String featureName;
@@ -91,7 +92,7 @@ public class FeatureToProvisioning {
                     index++;
                 }
             } else {
-                final Application app = FeatureUtil.assembleApplication(null, am, fr, files.stream()
+                final Application app = ApplicationResolverAssembler.assembleApplication(null, am, fr, files.stream()
                         .map(File::getAbsolutePath)
                         .toArray(String[]::new));
                 FeatureToProvisioning.convert(app, 0, output);
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 cb166a7..f1e86d0 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
@@ -27,9 +27,9 @@ import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.io.ArtifactHandler;
 import org.apache.sling.feature.io.ArtifactManager;
 import org.apache.sling.feature.io.ArtifactManagerConfig;
+import org.apache.sling.feature.io.IOUtils;
 import org.apache.sling.feature.io.json.ApplicationJSONWriter;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
-import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;
@@ -317,7 +317,7 @@ public class ProvisioningToFeature {
 
         }
         // felix framework hard coded for now
-        app.setFramework(FeatureUtil.getFelixFrameworkId(null));
+        app.setFramework(IOUtils.getFelixFrameworkId(null));
         return app;
     }
 
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 98449cf..ac49f3a 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
@@ -23,8 +23,8 @@ import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.io.ArtifactManager;
 import org.apache.sling.feature.io.ArtifactManagerConfig;
+import org.apache.sling.feature.io.IOUtils;
 import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
-import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;
@@ -175,8 +175,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = IOUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = IOUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 
@@ -206,8 +206,8 @@ public class ModelConverterTest {
         File outFile = files.get(0);
 
         String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
-        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
-        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature expected = IOUtils.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = IOUtils.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
         assertFeaturesEqual(expected, actual);
     }
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 19/40: Handle the fact that a single provisioning model can result in multiple features

Posted by da...@apache.org.
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 767340c4ccef0cbc0a09d0484b8b98065ef3e7dc
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Mar 22 16:32:35 2018 +0000

    Handle the fact that a single provisioning model can result in multiple features
    
    Also, allow multiple indentical bundles when they are associated with
    different run modes.
---
 .../modelconverter/impl/ProvisioningToFeature.java | 11 +++--
 .../modelconverter/impl/ModelConverterTest.java    | 57 ++++++++++++++++------
 2 files changed, 48 insertions(+), 20 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 d34d471..9f88aae 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
@@ -71,10 +71,13 @@ public class ProvisioningToFeature {
     public static void convert(File file, String output) {
         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");
-
-        writeFeature(features.get(0), output, 0);
+        if (features.size() != 1) {
+            for (int i=0; i<features.size(); i++) {
+                writeFeature(features.get(i), output, i+1);
+            }
+        } else {
+            writeFeature(features.get(0), output, 0);
+        }
     }
 
     public static void convert(List<File> files,  String outputFile, String runModes, boolean createApp,
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 fb8b571..98f2dbc 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
@@ -29,6 +29,7 @@ import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
 import org.apache.sling.provisioning.model.KeyValueMap;
+import org.apache.sling.provisioning.model.MergeUtility;
 import org.apache.sling.provisioning.model.Model;
 import org.apache.sling.provisioning.model.ModelConstants;
 import org.apache.sling.provisioning.model.ModelUtility;
@@ -49,6 +50,7 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Dictionary;
 import java.util.Enumeration;
@@ -129,15 +131,25 @@ public class ModelConverterTest {
     }
 
     public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
-        File outJSONFile = new File(tempDir.toFile(), orgProvModel.getName() + ".json.generated");
-        File outProvFile = new File(tempDir.toFile(), orgProvModel.getName() + ".txt.generated");
+        String genJSONPrefix = orgProvModel.getName() + ".json";
+        String genTxtPrefix = orgProvModel.getName() + ".txt";
+        String genSuffix = ".generated";
+        File outJSONFile = new File(tempDir.toFile(), genJSONPrefix + genSuffix);
+        List<File> allGenerateProvisioningModelFiles = new ArrayList<>();
 
         ProvisioningToFeature.convert(orgProvModel, outJSONFile.getAbsolutePath());
-        FeatureToProvisioning.convert(outJSONFile, outProvFile.getAbsolutePath(),
-                artifactManager);
+
+        for (File f : tempDir.toFile().listFiles((p, n) -> n.startsWith(genJSONPrefix))) {
+            String infix = f.getName().substring(genJSONPrefix.length(),
+                    f.getName().length() - genSuffix.length());
+
+            File genFile = new File(tempDir.toFile(), genTxtPrefix + infix + genSuffix);
+            allGenerateProvisioningModelFiles.add(genFile);
+            FeatureToProvisioning.convert(f, genFile.getAbsolutePath(), artifactManager);
+        }
 
         Model expected = readProvisioningModel(orgProvModel);
-        Model actual = readProvisioningModel(outProvFile);
+        Model actual = readProvisioningModel(allGenerateProvisioningModelFiles);
         assertModelsEqual(expected, actual);
     }
 
@@ -168,19 +180,32 @@ public class ModelConverterTest {
     }
 
     private static Model readProvisioningModel(File modelFile) throws IOException {
-        try (final FileReader is = new FileReader(modelFile)) {
-            Model model = ModelReader.read(is, modelFile.getAbsolutePath());
-
-            // Fix the configurations up from the internal format to the Dictionary-based format
-            return ModelUtility.getEffectiveModel(model,
-                    new ResolverOptions().variableResolver(new VariableResolver() {
-                @Override
-                public String resolve(final Feature feature, final String name) {
-                    // Keep variables as-is in the model
-                    return "${" + name + "}";
+        return readProvisioningModel(Collections.singletonList(modelFile));
+    }
+
+    private static Model readProvisioningModel(List<File> modelFiles) throws IOException {
+        Model model = null;
+        for (File modelFile : modelFiles) {
+            try (FileReader fr = new FileReader(modelFile)) {
+                Model nextModel = ModelReader.read(fr, modelFile.getAbsolutePath());
+
+                if (model == null) {
+                    model = nextModel;
+                } else {
+                    MergeUtility.merge(model, nextModel);
                 }
-            }));
+            }
         }
+
+        // Fix the configurations up from the internal format to the Dictionary-based format
+        return ModelUtility.getEffectiveModel(model,
+                new ResolverOptions().variableResolver(new VariableResolver() {
+            @Override
+            public String resolve(final Feature feature, final String name) {
+                // Keep variables as-is in the model
+                return "${" + name + "}";
+            }
+        }));
     }
 
     private void assertFeaturesEqual(org.apache.sling.feature.Feature expected, org.apache.sling.feature.Feature actual) {

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 09/40: Additional comments for the converter classes.

Posted by da...@apache.org.
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 978f1f2ed37672fae3eb184301ced79c13c95b1a
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Mar 15 08:45:37 2018 +0100

    Additional comments for the converter classes.
---
 .../apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java | 2 ++
 .../apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 44eaaac..6679020 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -45,6 +45,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+/** Converter that converts the feature model to the provisioning model.
+ */
 public class FeatureToProvisioning {
     private static Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
 
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 59af64d..57f13c6 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
@@ -59,6 +59,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+/** Converter that converts the provisioning model to the feature model.
+ */
 public class ProvisioningToFeature {
     private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class);
 

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 07/40: Support the slinstart maven plugin by providing a model converter API

Posted by da...@apache.org.
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 b9c87b7e46912e24e555e8e2a68f5733c0bfebbb
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Fri Mar 9 10:46:10 2018 +0000

    Support the slinstart maven plugin by providing a model converter API
---
 pom.xml                                            |  26 +-
 .../modelconverter/impl/FeatureToProvisioning.java | 216 ++++++++
 .../sling/feature/modelconverter/impl/Main.java    | 554 +-------------------
 .../impl/{Main.java => ProvisioningToFeature.java} | 562 ++++++---------------
 4 files changed, 393 insertions(+), 965 deletions(-)

diff --git a/pom.xml b/pom.xml
index d5359d5..2e0c607 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.resolver</artifactId>
+            <version>1.0.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
@@ -104,6 +110,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.analyser</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature.resolver</artifactId>
             <version>0.0.1-SNAPSHOT</version>
             <scope>provided</scope>
@@ -126,10 +138,18 @@
             <version>1.0.0</version>
             <scope>provided</scope>
         </dependency>
-      <!-- Testing -->
+        
+        <!-- Testing -->
+        <dependency>
+        	    <groupId>junit</groupId>
+        	    <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
-        	<groupId>junit</groupId>
-        	<artifactId>junit</artifactId>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>5.6.10</version>
+            <!--  <scope>test</scope>  -->
         </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
new file mode 100644
index 0000000..44eaaac
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.feature.modelconverter.impl;
+
+import org.apache.sling.feature.Application;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Bundles;
+import org.apache.sling.feature.Configurations;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.process.FeatureResolver;
+import org.apache.sling.feature.support.ArtifactManager;
+import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.json.ApplicationJSONReader;
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.io.ModelWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FeatureToProvisioning {
+    private static Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
+
+    public static void convert(File file, String output, ArtifactManager am) throws IOException {
+        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am);
+
+        String featureName;
+        if (feature.getTitle() != null) {
+            featureName = feature.getTitle();
+        } else {
+            featureName = feature.getId().getArtifactId();
+        }
+
+        Feature newFeature = new Feature(featureName);
+        convert(newFeature, feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
+    }
+
+    public static void convert(List<File> files, String output, boolean createApp, ArtifactManager am) throws Exception {
+        try (FeatureResolver fr = null) { // TODO we could use the resolver: new FrameworkResolver(am)
+            if ( createApp ) {
+                // each file is an application
+                int index = 1;
+                for(final File appFile : files ) {
+                    try ( final FileReader r = new FileReader(appFile) ) {
+                        final Application app = ApplicationJSONReader.read(r);
+                        FeatureToProvisioning.convert(app, files.size() > 1 ? index : 0, output);
+                    }
+                    index++;
+                }
+            } else {
+                final Application app = FeatureUtil.assembleApplication(null, am, fr, files.stream()
+                        .map(File::getAbsolutePath)
+                        .toArray(String[]::new));
+                FeatureToProvisioning.convert(app, 0, output);
+            }
+        }
+    }
+
+    private static void convert(final Application app, final int index, final String outputFile) {
+        String featureName;
+
+        List<ArtifactId> fids = app.getFeatureIds();
+        if (fids.size() > 0) {
+            featureName = fids.get(0).getArtifactId();
+        } else {
+            featureName = "application";
+        }
+        final Feature feature = new Feature(featureName);
+
+        convert(feature, app.getBundles(), app.getConfigurations(), app.getFrameworkProperties(), app.getExtensions(), outputFile);
+    }
+
+    private static void convert(Feature f, Bundles bundles, Configurations configurations, KeyValueMap frameworkProps,
+            Extensions extensions, String outputFile) {
+        Map<org.apache.sling.feature.Configuration, org.apache.sling.feature.Artifact> configBundleMap = new HashMap<>();
+
+        // bundles
+        for(final org.apache.sling.feature.Artifact bundle : bundles) {
+            final ArtifactId id = bundle.getId();
+            final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
+
+            Object configs = bundle.getMetadata().getObject("configurations");
+            if (configs instanceof List) {
+                for (Object config : (List<?>) configs) {
+                    if (config instanceof org.apache.sling.feature.Configuration) {
+                        configBundleMap.put((org.apache.sling.feature.Configuration) config, bundle);
+                    }
+                }
+            }
+
+            for(final Map.Entry<String, String> prop : bundle.getMetadata()) {
+                switch (prop.getKey()) {
+                    // these are handled separately
+                    case "start-level":
+                    case "run-modes":
+                        break;
+                    default:
+                        newBundle.getMetadata().put(prop.getKey(), prop.getValue());
+                }
+            }
+
+            int startLevel;
+            String sl = bundle.getMetadata().get("start-level");
+            if (sl != null) {
+                startLevel = Integer.parseInt(sl);
+            } else {
+                startLevel = 20;
+            }
+
+            String[] runModes = getRunModes(bundle);
+            f.getOrCreateRunMode(runModes).getOrCreateArtifactGroup(startLevel).add(newBundle);
+        }
+
+        // configurations
+        for(final org.apache.sling.feature.Configuration cfg : configurations) {
+            final Configuration c;
+            if ( cfg.isFactoryConfiguration() ) {
+                c = new Configuration(cfg.getName(), cfg.getFactoryPid());
+            } else {
+                c = new Configuration(cfg.getPid(), null);
+            }
+            final Enumeration<String> keys = cfg.getProperties().keys();
+            while ( keys.hasMoreElements() ) {
+                final String key = keys.nextElement();
+                c.getProperties().put(key, cfg.getProperties().get(key));
+            }
+
+            // Check if the configuration has an associated runmode via the bundle that it belongs to
+            org.apache.sling.feature.Artifact bundle = configBundleMap.get(cfg);
+            String[] runModes;
+            if (bundle != null) {
+                runModes = getRunModes(bundle);
+            } else {
+                runModes = null;
+            }
+            f.getOrCreateRunMode(runModes).getConfigurations().add(c);
+        }
+
+        // framework properties
+        for(final Map.Entry<String, String> prop : frameworkProps) {
+            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
+        }
+
+        // extensions: content packages and repoinit
+        for(final Extension ext : extensions) {
+            if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
+                for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
+                    final ArtifactId id = cp.getId();
+                    final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
+                    for(final Map.Entry<String, String> prop : cp.getMetadata()) {
+                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                    }
+                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
+                }
+
+            } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
+                final Section section = new Section("repoinit");
+                section.setContents(ext.getText());
+                f.getAdditionalSections().add(section);
+            } else if ( ext.isRequired() ) {
+                LOGGER.error("Unable to convert required extension {}", ext.getName());
+                System.exit(1);
+            }
+        }
+
+        LOGGER.info("Writing feature...");
+        final String out = outputFile;
+        final File file = new File(out);
+        final Model m = new Model();
+        m.getFeatures().add(f);
+        try ( final FileWriter writer = new FileWriter(file)) {
+            ModelWriter.write(writer, m);
+        } catch ( final IOException ioe) {
+            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+    }
+
+    private static String[] getRunModes(final org.apache.sling.feature.Artifact bundle) {
+        String runMode = bundle.getMetadata().get("run-modes");
+        String[] runModes;
+        if (runMode != null) {
+            runModes = runMode.split(",");
+        } else {
+            runModes = null;
+        }
+        return runModes;
+    }
+}
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index ccc3f85..81a9e3c 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -16,60 +16,23 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
-import org.apache.sling.feature.Application;
-import org.apache.sling.feature.ArtifactId;
-import org.apache.sling.feature.Bundles;
-import org.apache.sling.feature.Configurations;
-import org.apache.sling.feature.Extension;
-import org.apache.sling.feature.ExtensionType;
-import org.apache.sling.feature.Extensions;
-import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.process.FeatureResolver;
-import org.apache.sling.feature.resolver.FrameworkResolver;
-import org.apache.sling.feature.support.ArtifactHandler;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
-import org.apache.sling.feature.support.FeatureUtil;
-import org.apache.sling.feature.support.json.ApplicationJSONReader;
-import org.apache.sling.feature.support.json.ApplicationJSONWriter;
-import org.apache.sling.feature.support.json.FeatureJSONWriter;
-import org.apache.sling.provisioning.model.Artifact;
-import org.apache.sling.provisioning.model.ArtifactGroup;
-import org.apache.sling.provisioning.model.Configuration;
-import org.apache.sling.provisioning.model.Feature;
-import org.apache.sling.provisioning.model.MergeUtility;
-import org.apache.sling.provisioning.model.Model;
-import org.apache.sling.provisioning.model.ModelConstants;
-import org.apache.sling.provisioning.model.ModelUtility;
-import org.apache.sling.provisioning.model.ModelUtility.ResolverOptions;
-import org.apache.sling.provisioning.model.ModelUtility.VariableResolver;
-import org.apache.sling.provisioning.model.RunMode;
-import org.apache.sling.provisioning.model.Section;
-import org.apache.sling.provisioning.model.Traceable;
-import org.apache.sling.provisioning.model.io.ModelReader;
-import org.apache.sling.provisioning.model.io.ModelWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 public class Main {
 
     private static Logger LOGGER;
@@ -167,10 +130,6 @@ public class Main {
         return null;
     }
 
-    private static FeatureResolver getFeatureResolver(ArtifactManager am) {
-        return new FrameworkResolver(am, Collections.emptyMap());
-    }
-
     public static void main(final String[] args) {
         // setup logging
         System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
@@ -229,41 +188,13 @@ public class Main {
             if ( output == null ) {
                 output = createApp ? "application.json" : "feature.json";
             }
-            final Model model = createModel(files, runModes);
-
-            if ( createApp ) {
-                final Application app = buildApplication(model);
-
-                writeApplication(app, output);
-            } else {
-                final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
-                int index = 1;
-                for(final org.apache.sling.feature.Feature feature : features) {
-                    writeFeature(feature, output, features.size() > 1 ? index : 0);
-                    index++;
-                }
-            }
+            ProvisioningToFeature.convert(files, output, runModes, createApp, includeModelInfo, propsFile);
         } else {
             if ( output == null ) {
                 output = createApp ? "application.txt" : "feature.txt";
             }
-            try (FeatureResolver fr = getFeatureResolver(am)) {
-                if ( createApp ) {
-                    // each file is an application
-                    int index = 1;
-                    for(final File appFile : files ) {
-                        try ( final FileReader r = new FileReader(appFile) ) {
-                            final Application app = ApplicationJSONReader.read(r);
-                            convert(app, files.size() > 1 ? index : 0);
-                        }
-                        index++;
-                    }
-                } else {
-                    final Application app = FeatureUtil.assembleApplication(null, am, fr, files.stream()
-                            .map(File::getAbsolutePath)
-                            .toArray(String[]::new));
-                    convert(app, 0);
-                }
+            try {
+                FeatureToProvisioning.convert(files, output, createApp, am);
             } catch ( final IOException ioe) {
                 LOGGER.error("Unable to read feature/application files " + ioe.getMessage(), ioe);
                 System.exit(1);
@@ -274,471 +205,4 @@ public class Main {
         }
     }
 
-    private static List<org.apache.sling.feature.Feature> buildFeatures(final Model model) {
-        final List<org.apache.sling.feature.Feature> features = new ArrayList<>();
-
-        for(final Feature feature : model.getFeatures() ) {
-            final String idString;
-            // use a default name if not present or not usable as a Maven artifactId ( starts with ':')
-            if ( feature.getName() != null && !feature.isSpecial() ) {
-                if ( feature.getVersion() != null ) {
-                    idString = "generated/" + feature.getName() + "/" + feature.getVersion();
-                } else {
-                    idString = "generated/" + feature.getName() + "/1.0.0";
-                }
-            } else {
-                idString = "generated/feature/1.0.0";
-            }
-            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
-            features.add(f);
-
-            buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
-        }
-
-        return features;
-    }
-
-    private static Application buildApplication(final Model model) {
-        final Application app = new Application();
-
-        for(final Feature feature : model.getFeatures() ) {
-            buildFromFeature(feature, app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
-        }
-
-        // hard coded dependency to launchpad api
-        final org.apache.sling.feature.Artifact a = new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
-        a.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, "1");
-        // sling.properties (TODO)
-        if ( propsFile == null ) {
-            app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");
-        } else {
-
-        }
-        // felix framework hard coded for now
-        app.setFramework(FeatureUtil.getFelixFrameworkId(null));
-        return app;
-    }
-
-    private static void buildFromFeature(final Feature feature,
-            final Bundles bundles,
-            final Configurations configurations,
-            final Extensions extensions,
-            final KeyValueMap properties) {
-        Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
-        for(final RunMode runMode : feature.getRunModes() ) {
-            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
-                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
-                    for(final Artifact artifact : group) {
-                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
-                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
-
-                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
-                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
-                        }
-
-                        if ( newArtifact.getId().getType().equals("zip") ) {
-                            if ( cpExtension == null ) {
-                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
-                                extensions.add(cpExtension);
-                            }
-                            cpExtension.getArtifacts().add(newArtifact);
-                        } else {
-                            int startLevel = group.getStartLevel();
-                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
-                                startLevel = 1;
-                            } else if ( startLevel == 0 ) {
-                                startLevel = 20;
-                            }
-                            newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
-                            bundles.add(newArtifact);
-                        }
-                    }
-                }
-            }
-
-            for(final Configuration cfg : runMode.getConfigurations()) {
-                final org.apache.sling.feature.Configuration newCfg;
-                if ( cfg.getFactoryPid() != null ) {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
-                } else {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
-                }
-                final Enumeration<String> keys = cfg.getProperties().keys();
-                while ( keys.hasMoreElements() ) {
-                    final String key = keys.nextElement();
-                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
-                }
-                configurations.add(newCfg);
-            }
-
-            for(final Map.Entry<String, String> prop : runMode.getSettings()) {
-                properties.put(prop.getKey(), prop.getValue());
-            }
-        }
-        Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
-        for(final Section sect : feature.getAdditionalSections("repoinit")) {
-            final String text = sect.getContents();
-            if ( repoExtension == null ) {
-                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
-                extensions.add(repoExtension);
-                repoExtension.setText(text);
-            } else {
-                repoExtension.setText(repoExtension.getText() + "\n\n" + text);
-            }
-        }
-    }
-
-    private static void writeApplication(final Application app, final String out) {
-        LOGGER.info("Writing application...");
-        final File file = new File(out);
-        try ( final FileWriter writer = new FileWriter(file)) {
-            ApplicationJSONWriter.write(writer, app);
-        } catch ( final IOException ioe) {
-            LOGGER.error("Unable to write application to {} : {}", out, ioe.getMessage(), ioe);
-            System.exit(1);
-        }
-    }
-
-    private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
-        LOGGER.info("Writing feature...");
-        if ( index > 0 ) {
-            final int lastDot = out.lastIndexOf('.');
-            if ( lastDot == -1 ) {
-                out = out + "_" + String.valueOf(index);
-            } else {
-                out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
-            }
-        }
-        final File file = new File(out);
-        try ( final FileWriter writer = new FileWriter(file)) {
-            FeatureJSONWriter.write(writer, f);
-        } catch ( final IOException ioe) {
-            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
-            System.exit(1);
-        }
-    }
-
-    /**
-     * Read the models and prepare the model
-     * @param files The model files
-     */
-    private static Model createModel(final List<File> files,
-            final String runModes) {
-        LOGGER.info("Assembling model...");
-        Model model = null;
-        for(final File initFile : files) {
-            try {
-                model = processModel(model, initFile);
-            } catch ( final IOException iae) {
-                LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae);
-                System.exit(1);
-            }
-        }
-
-        final Model effectiveModel = ModelUtility.getEffectiveModel(model, new ResolverOptions().variableResolver(new VariableResolver() {
-
-            @Override
-            public String resolve(Feature feature, String name) {
-                if ( "sling.home".equals(name) ) {
-                    return "${sling.home}";
-                }
-                return feature.getVariables().get(name);
-            }
-        }));
-        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()) {
-                LOGGER.error("- {} : {}", entry.getKey().getLocation(), entry.getValue());
-            }
-            System.exit(1);
-        }
-        final Set<String> modes = calculateRunModes(effectiveModel, runModes);
-
-        removeInactiveFeaturesAndRunModes(effectiveModel, modes);
-
-        return effectiveModel;
-    }
-
-    /**
-     * Process the given model and merge it into the provided model
-     * @param model The already read model
-     * @param modelFile The model file
-     * @return The merged model
-     * @throws IOException If reading fails
-     */
-    private static Model processModel(Model model,
-            final File modelFile) throws IOException {
-        LOGGER.info("- reading model {}", modelFile);
-
-        final Model nextModel = readProvisioningModel(modelFile);
-        // resolve references to other models
-        final ResolverOptions options = new ResolverOptions().variableResolver(new VariableResolver() {
-
-            @Override
-            public String resolve(final Feature feature, final String name) {
-                return name;
-            }
-        });
-
-
-        final Model effectiveModel = ModelUtility.getEffectiveModel(nextModel, options);
-        for(final Feature feature : effectiveModel.getFeatures()) {
-            for(final RunMode runMode : feature.getRunModes()) {
-                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
-                    final List<org.apache.sling.provisioning.model.Artifact> removeList = new ArrayList<>();
-                    for(final org.apache.sling.provisioning.model.Artifact a : group) {
-                        if ( "slingstart".equals(a.getType())
-                             || "slingfeature".equals(a.getType())) {
-
-                            final ArtifactManagerConfig cfg = new ArtifactManagerConfig();
-                            final ArtifactManager mgr = ArtifactManager.getArtifactManager(cfg);
-
-                            final ArtifactId correctedId = new ArtifactId(a.getGroupId(),
-                                    a.getArtifactId(),
-                                    a.getVersion(),
-                                    "slingstart".equals(a.getType()) ? "slingfeature" : a.getClassifier(),
-                                    "txt");
-
-                            final ArtifactHandler handler = mgr.getArtifactHandler(correctedId.toMvnUrl());
-                            model = processModel(model, handler.getFile());
-
-                            removeList.add(a);
-                        } else {
-                            final org.apache.sling.provisioning.model.Artifact realArtifact = nextModel.getFeature(feature.getName()).getRunMode(runMode.getNames()).getArtifactGroup(group.getStartLevel()).search(a);
-
-                            if ( includeModelInfo ) {
-                                realArtifact.getMetadata().put("model-filename", modelFile.getName());
-                            }
-                            if ( runMode.getNames() != null ) {
-                                realArtifact.getMetadata().put("runmodes", String.join(",", runMode.getNames()));
-                            }
-                        }
-                    }
-                    for(final org.apache.sling.provisioning.model.Artifact r : removeList) {
-                        nextModel.getFeature(feature.getName()).getRunMode(runMode.getNames()).getArtifactGroup(group.getStartLevel()).remove(r);
-                    }
-                }
-            }
-        }
-
-        if ( model == null ) {
-            model = nextModel;
-        } else {
-            MergeUtility.merge(model, nextModel);
-        }
-        return model;
-    }
-
-    /**
-     * Read the provisioning model
-     */
-    private static Model readProvisioningModel(final File file)
-    throws IOException {
-        try (final FileReader is = new FileReader(file)) {
-            final Model m = ModelReader.read(is, file.getAbsolutePath());
-            return m;
-        }
-    }
-
-    private static void removeInactiveFeaturesAndRunModes(final Model m,
-            final Set<String> activeRunModes) {
-        final String[] requiredFeatures = new String[] {ModelConstants.FEATURE_LAUNCHPAD, ModelConstants.FEATURE_BOOT};
-        // first pass:
-        // - remove special features except boot required ones
-        // - remove special run modes and inactive run modes
-        // - remove special configurations (TODO)
-        final Iterator<Feature> i = m.getFeatures().iterator();
-        while ( i.hasNext() ) {
-            final Feature feature = i.next();
-            if ( feature.isSpecial() ) {
-                boolean remove = true;
-                if ( requiredFeatures != null ) {
-                    for(final String name : requiredFeatures) {
-                        if ( feature.getName().equals(name) ) {
-                            remove = false;
-                            break;
-                        }
-                    }
-                }
-                if ( remove ) {
-                    i.remove();
-                    continue;
-                }
-            }
-            feature.setComment(null);
-            final Iterator<RunMode> rmI = feature.getRunModes().iterator();
-            while ( rmI.hasNext() ) {
-                final RunMode rm = rmI.next();
-                if ( rm.isActive(activeRunModes) || rm.isRunMode(ModelConstants.RUN_MODE_STANDALONE) ) {
-                    final Iterator<Configuration> cI = rm.getConfigurations().iterator();
-                    while ( cI.hasNext() ) {
-                        final Configuration config = cI.next();
-                        if ( config.isSpecial() ) {
-                            cI.remove();
-                            continue;
-                        }
-                        config.setComment(null);
-                    }
-                } else {
-                    rmI.remove();
-                    continue;
-                }
-            }
-        }
-
-        // second pass: aggregate the settings and add them to the first required feature
-        final Feature requiredFeature = m.getFeature(requiredFeatures[0]);
-        if ( requiredFeature != null ) {
-            for(final Feature f : m.getFeatures()) {
-                if ( f.getName().equals(requiredFeature.getName()) ) {
-                    continue;
-                }
-                copyAndClearSettings(requiredFeature, f.getRunMode(new String[] {ModelConstants.RUN_MODE_STANDALONE}));
-                copyAndClearSettings(requiredFeature, f.getRunMode());
-            }
-        }
-    }
-
-    private static void copyAndClearSettings(final Feature requiredFeature, final RunMode rm) {
-        if ( rm != null && !rm.getSettings().isEmpty() ) {
-            final RunMode requiredRunMode = requiredFeature.getOrCreateRunMode(null);
-            final Set<String> keys = new HashSet<>();
-            for(final Map.Entry<String, String> entry : rm.getSettings()) {
-                requiredRunMode.getSettings().put(entry.getKey(), entry.getValue());
-                keys.add(entry.getKey());
-            }
-
-            for(final String key : keys) {
-                rm.getSettings().remove(key);
-            }
-        }
-    }
-
-    private static Set<String> calculateRunModes(final Model model, final String runModes) {
-        final Set<String> modesSet = new HashSet<>();
-
-        // check configuration property first
-        if (runModes != null && runModes.trim().length() > 0) {
-            final String[] modes = runModes.split(",");
-            for(int i=0; i < modes.length; i++) {
-                modesSet.add(modes[i].trim());
-            }
-        }
-
-        //  handle configured options
-        final Feature feature = model.getFeature(ModelConstants.FEATURE_BOOT);
-        if ( feature != null ) {
-            handleOptions(modesSet, feature.getRunMode().getSettings().get("sling.run.mode.options"));
-            handleOptions(modesSet, feature.getRunMode().getSettings().get("sling.run.mode.install.options"));
-        }
-
-        return modesSet;
-    }
-
-    private static void handleOptions(final Set<String> modesSet, final String propOptions) {
-        if ( propOptions != null && propOptions.trim().length() > 0 ) {
-
-            final String[] options = propOptions.trim().split("\\|");
-            for(final String opt : options) {
-                String selected = null;
-                final String[] modes = opt.trim().split(",");
-                for(int i=0; i<modes.length; i++) {
-                    modes[i] = modes[i].trim();
-                    if ( selected != null ) {
-                        modesSet.remove(modes[i]);
-                    } else {
-                        if ( modesSet.contains(modes[i]) ) {
-                            selected = modes[i];
-                        }
-                    }
-                }
-                if ( selected == null ) {
-                    selected = modes[0];
-                    modesSet.add(modes[0]);
-                }
-            }
-        }
-    }
-
-    private static void convert(final Application app, final int index) {
-        final Feature f = new Feature("application");
-
-        // bundles
-        for(final org.apache.sling.feature.Artifact bundle : app.getBundles()) {
-            final ArtifactId id = bundle.getId();
-            final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
-            for(final Map.Entry<String, String> prop : bundle.getMetadata()) {
-                newBundle.getMetadata().put(prop.getKey(), prop.getValue());
-            }
-            int startLevel = bundle.getStartOrder();
-            if ( startLevel == 0 ) {
-                startLevel = 20;
-            }
-            f.getOrCreateRunMode(null).getOrCreateArtifactGroup(startLevel).add(newBundle);
-        }
-
-        // configurations
-        for(final org.apache.sling.feature.Configuration cfg : app.getConfigurations()) {
-            final Configuration c;
-            if ( cfg.isFactoryConfiguration() ) {
-                c = new Configuration(cfg.getName(), cfg.getFactoryPid());
-            } else {
-                c = new Configuration(cfg.getPid(), null);
-            }
-            final Enumeration<String> keys = cfg.getProperties().keys();
-            while ( keys.hasMoreElements() ) {
-                final String key = keys.nextElement();
-                c.getProperties().put(key, cfg.getProperties().get(key));
-            }
-            f.getOrCreateRunMode(null).getConfigurations().add(c);
-        }
-
-        // framework properties
-        for(final Map.Entry<String, String> prop : app.getFrameworkProperties()) {
-            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
-        }
-
-        // extensions: content packages and repoinit
-        for(final Extension ext : app.getExtensions()) {
-            if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
-                for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
-                    final ArtifactId id = cp.getId();
-                    final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
-                    for(final Map.Entry<String, String> prop : cp.getMetadata()) {
-                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
-                    }
-                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
-                }
-
-            } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
-                final Section section = new Section("repoinit");
-                section.setContents(ext.getText());
-                f.getAdditionalSections().add(section);
-            } else if ( ext.isRequired() ) {
-                LOGGER.error("Unable to convert required extension {}", ext.getName());
-                System.exit(1);
-            }
-        }
-
-        LOGGER.info("Writing feature...");
-        String out = output;
-        if ( index > 0 ) {
-            final int lastDot = out.lastIndexOf('.');
-            if ( lastDot == -1 ) {
-                out = out + "_" + String.valueOf(index);
-            } else {
-                out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
-            }
-        }
-        final File file = new File(out);
-        final Model m = new Model();
-        m.getFeatures().add(f);
-        try ( final FileWriter writer = new FileWriter(file)) {
-            ModelWriter.write(writer, m);
-        } catch ( final IOException ioe) {
-            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
-            System.exit(1);
-        }
-    }
 }
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
similarity index 61%
copy from src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
copy to src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
index ccc3f85..e3a4a52 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/ProvisioningToFeature.java
@@ -16,25 +16,6 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
@@ -43,13 +24,10 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
-import org.apache.sling.feature.process.FeatureResolver;
-import org.apache.sling.feature.resolver.FrameworkResolver;
 import org.apache.sling.feature.support.ArtifactHandler;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
 import org.apache.sling.feature.support.FeatureUtil;
-import org.apache.sling.feature.support.json.ApplicationJSONReader;
 import org.apache.sling.feature.support.json.ApplicationJSONWriter;
 import org.apache.sling.feature.support.json.FeatureJSONWriter;
 import org.apache.sling.provisioning.model.Artifact;
@@ -66,369 +44,54 @@ import org.apache.sling.provisioning.model.RunMode;
 import org.apache.sling.provisioning.model.Section;
 import org.apache.sling.provisioning.model.Traceable;
 import org.apache.sling.provisioning.model.io.ModelReader;
-import org.apache.sling.provisioning.model.io.ModelWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class Main {
-
-    private static Logger LOGGER;
-
-    private static String runModes;
-
-    private static String output;
-
-    private static String input;
-
-    private static boolean createApp = false;
-
-    private static boolean includeModelInfo = false;
-
-    private static String repoUrls;
-
-    private static String propsFile;
-
-    /**
-     * Parse the command line parameters and update a configuration object.
-     * @param args Command line parameters
-     * @return Configuration object.
-     */
-    private static void parseArgs(final String[] args) {
-        final Option repoOption =  Option.builder("u").hasArg().argName("Set repository url")
-                .desc("repository url").required().build();
-
-        final Option modelOption =  new Option("f", true, "Set feature files/directories");
-        final Option propsOption =  new Option("p", true, "sling.properties file");
-        final Option runModeOption =  new Option("r", true, "Set run modes (comma separated)");
-        final Option createAppOption = new Option("a", false, "If enabled, create application json");
-        createAppOption.setArgs(0);
-        final Option includeModelOption = new Option("i", false, "Include model filename as metadata for artifacts");
-        includeModelOption.setArgs(0);
-
-        final Option outputOption = Option.builder("o").hasArg().argName("Set output file")
-                .desc("output file").build();
-
-        final Options options = new Options();
-        options.addOption(repoOption);
-        options.addOption(modelOption);
-        options.addOption(createAppOption);
-        options.addOption(outputOption);
-        options.addOption(includeModelOption);
-        options.addOption(propsOption);
-        options.addOption(runModeOption);
-
-        final CommandLineParser parser = new DefaultParser();
-        try {
-            final CommandLine cl = parser.parse(options, args);
-
-            if ( cl.hasOption(repoOption.getOpt()) ) {
-                repoUrls = cl.getOptionValue(repoOption.getOpt());
-            }
-            if ( cl.hasOption(modelOption.getOpt()) ) {
-                input = cl.getOptionValue(modelOption.getOpt());
-            }
-            if ( cl.hasOption(createAppOption.getOpt()) ) {
-                createApp = true;
-            }
-            if ( cl.hasOption(includeModelOption.getOpt()) ) {
-                includeModelInfo = true;
-            }
-            if ( cl.hasOption(runModeOption.getOpt()) ) {
-                runModes = cl.getOptionValue(runModeOption.getOpt());
-            }
-            if ( cl.hasOption(outputOption.getOpt()) ) {
-                output = cl.getOptionValue(outputOption.getOpt());
-            }
-            if ( cl.hasOption(propsOption.getOpt()) ) {
-                propsFile = cl.getOptionValue(propsOption.getOpt());
-            }
-        } catch ( final ParseException pe) {
-            LOGGER.error("Unable to parse command line: {}", pe.getMessage(), pe);
-            System.exit(1);
-        }
-        if ( input == null ) {
-            LOGGER.error("Required argument missing: model file or directory");
-            System.exit(1);
-        }
-    }
-
-    private static ArtifactManager getArtifactManager() {
-        final ArtifactManagerConfig amConfig = new ArtifactManagerConfig();
-        if ( repoUrls != null ) {
-            amConfig.setRepositoryUrls(repoUrls.split(","));
-        }
-        try {
-            return ArtifactManager.getArtifactManager(amConfig);
-        } catch ( IOException ioe) {
-            LOGGER.error("Unable to create artifact manager " + ioe.getMessage(), ioe);
-            System.exit(1);
-        }
-        // we never reach this, but have to keep the compiler happy
-        return null;
-    }
-
-    private static FeatureResolver getFeatureResolver(ArtifactManager am) {
-        return new FrameworkResolver(am, Collections.emptyMap());
-    }
-
-    public static void main(final String[] args) {
-        // setup logging
-        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
-        System.setProperty("org.slf4j.simpleLogger.showThreadName", "false");
-        System.setProperty("org.slf4j.simpleLogger.levelInBrackets", "true");
-        System.setProperty("org.slf4j.simpleLogger.showLogName", "false");
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
-        LOGGER = LoggerFactory.getLogger("modelconverter");
+public class ProvisioningToFeature {
+    private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class);
 
-        LOGGER.info("Apache Sling Provisiong Model to Feature Application Converter");
-        LOGGER.info("");
+    public static void convert(List<File> files,  String outputFile, String runModes, boolean createApp,
+            boolean includeModelInfo, String propsFile) {
+        final Model model = createModel(files, runModes, includeModelInfo);
 
-        parseArgs(args);
+        if ( createApp ) {
+            final Application app = buildApplication(model, propsFile);
 
-        final ArtifactManagerConfig amConfig = new ArtifactManagerConfig();
-        if ( repoUrls != null ) {
-            amConfig.setRepositoryUrls(repoUrls.split(","));
-        }
-        final ArtifactManager am = getArtifactManager();
-
-        final File f = new File(input);
-        final List<File> files = new ArrayList<>();
-        if ( f.isDirectory() ) {
-            for(final File file : f.listFiles()) {
-                if ( file.isFile() && !file.getName().startsWith(".") ) {
-                    files.add(file);
-                }
-            }
-            if ( files.isEmpty() ) {
-                LOGGER.error("No files found in {}", f);
-                System.exit(1);
-            }
-            Collections.sort(files);
+            writeApplication(app, outputFile);
         } else {
-            files.add(f);
-        }
-        boolean isJson = false;
-        boolean isTxt = false;
-        for(final File t : files) {
-            if ( t.getName().endsWith(".json") ) {
-                if ( isTxt ) {
-                    LOGGER.error("Input files are a mixture of JSON and txt");
-                    System.exit(1);
-                }
-                isJson = true;
-            } else {
-                if ( isJson ) {
-                    LOGGER.error("Input files are a mixture of JSON and txt");
-                    System.exit(1);
-                }
-                isTxt = true;
-            }
-        }
-
-        if ( isTxt ) {
-            if ( output == null ) {
-                output = createApp ? "application.json" : "feature.json";
-            }
-            final Model model = createModel(files, runModes);
-
-            if ( createApp ) {
-                final Application app = buildApplication(model);
-
-                writeApplication(app, output);
-            } else {
-                final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
-                int index = 1;
-                for(final org.apache.sling.feature.Feature feature : features) {
-                    writeFeature(feature, output, features.size() > 1 ? index : 0);
-                    index++;
-                }
-            }
-        } else {
-            if ( output == null ) {
-                output = createApp ? "application.txt" : "feature.txt";
-            }
-            try (FeatureResolver fr = getFeatureResolver(am)) {
-                if ( createApp ) {
-                    // each file is an application
-                    int index = 1;
-                    for(final File appFile : files ) {
-                        try ( final FileReader r = new FileReader(appFile) ) {
-                            final Application app = ApplicationJSONReader.read(r);
-                            convert(app, files.size() > 1 ? index : 0);
-                        }
-                        index++;
-                    }
-                } else {
-                    final Application app = FeatureUtil.assembleApplication(null, am, fr, files.stream()
-                            .map(File::getAbsolutePath)
-                            .toArray(String[]::new));
-                    convert(app, 0);
-                }
-            } catch ( final IOException ioe) {
-                LOGGER.error("Unable to read feature/application files " + ioe.getMessage(), ioe);
-                System.exit(1);
-            } catch ( final Exception e) {
-                LOGGER.error("Problem generating application", e);
-                System.exit(1);
-            }
-        }
-    }
-
-    private static List<org.apache.sling.feature.Feature> buildFeatures(final Model model) {
-        final List<org.apache.sling.feature.Feature> features = new ArrayList<>();
-
-        for(final Feature feature : model.getFeatures() ) {
-            final String idString;
-            // use a default name if not present or not usable as a Maven artifactId ( starts with ':')
-            if ( feature.getName() != null && !feature.isSpecial() ) {
-                if ( feature.getVersion() != null ) {
-                    idString = "generated/" + feature.getName() + "/" + feature.getVersion();
-                } else {
-                    idString = "generated/" + feature.getName() + "/1.0.0";
-                }
-            } else {
-                idString = "generated/feature/1.0.0";
+            final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
+            int index = 1;
+            for(final org.apache.sling.feature.Feature feature : features) {
+                writeFeature(feature, outputFile, features.size() > 1 ? index : 0);
+                index++;
             }
-            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
-            features.add(f);
-
-            buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
-        }
-
-        return features;
-    }
-
-    private static Application buildApplication(final Model model) {
-        final Application app = new Application();
-
-        for(final Feature feature : model.getFeatures() ) {
-            buildFromFeature(feature, app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
-        }
-
-        // hard coded dependency to launchpad api
-        final org.apache.sling.feature.Artifact a = new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
-        a.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, "1");
-        // sling.properties (TODO)
-        if ( propsFile == null ) {
-            app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");
-        } else {
-
-        }
-        // felix framework hard coded for now
-        app.setFramework(FeatureUtil.getFelixFrameworkId(null));
-        return app;
-    }
-
-    private static void buildFromFeature(final Feature feature,
-            final Bundles bundles,
-            final Configurations configurations,
-            final Extensions extensions,
-            final KeyValueMap properties) {
-        Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
-        for(final RunMode runMode : feature.getRunModes() ) {
-            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
-                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
-                    for(final Artifact artifact : group) {
-                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
-                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
-
-                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
-                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
-                        }
-
-                        if ( newArtifact.getId().getType().equals("zip") ) {
-                            if ( cpExtension == null ) {
-                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
-                                extensions.add(cpExtension);
-                            }
-                            cpExtension.getArtifacts().add(newArtifact);
-                        } else {
-                            int startLevel = group.getStartLevel();
-                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
-                                startLevel = 1;
-                            } else if ( startLevel == 0 ) {
-                                startLevel = 20;
-                            }
-                            newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
-                            bundles.add(newArtifact);
-                        }
-                    }
-                }
-            }
-
-            for(final Configuration cfg : runMode.getConfigurations()) {
-                final org.apache.sling.feature.Configuration newCfg;
-                if ( cfg.getFactoryPid() != null ) {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
-                } else {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
-                }
-                final Enumeration<String> keys = cfg.getProperties().keys();
-                while ( keys.hasMoreElements() ) {
-                    final String key = keys.nextElement();
-                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
-                }
-                configurations.add(newCfg);
-            }
-
-            for(final Map.Entry<String, String> prop : runMode.getSettings()) {
-                properties.put(prop.getKey(), prop.getValue());
-            }
-        }
-        Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
-        for(final Section sect : feature.getAdditionalSections("repoinit")) {
-            final String text = sect.getContents();
-            if ( repoExtension == null ) {
-                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
-                extensions.add(repoExtension);
-                repoExtension.setText(text);
-            } else {
-                repoExtension.setText(repoExtension.getText() + "\n\n" + text);
-            }
-        }
-    }
-
-    private static void writeApplication(final Application app, final String out) {
-        LOGGER.info("Writing application...");
-        final File file = new File(out);
-        try ( final FileWriter writer = new FileWriter(file)) {
-            ApplicationJSONWriter.write(writer, app);
-        } catch ( final IOException ioe) {
-            LOGGER.error("Unable to write application to {} : {}", out, ioe.getMessage(), ioe);
-            System.exit(1);
-        }
-    }
-
-    private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
-        LOGGER.info("Writing feature...");
-        if ( index > 0 ) {
-            final int lastDot = out.lastIndexOf('.');
-            if ( lastDot == -1 ) {
-                out = out + "_" + String.valueOf(index);
-            } else {
-                out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
-            }
-        }
-        final File file = new File(out);
-        try ( final FileWriter writer = new FileWriter(file)) {
-            FeatureJSONWriter.write(writer, f);
-        } catch ( final IOException ioe) {
-            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
-            System.exit(1);
         }
     }
 
     /**
      * Read the models and prepare the model
      * @param files The model files
+     * @param includeModelInfo
      */
     private static Model createModel(final List<File> files,
-            final String runModes) {
+            final String runModes, boolean includeModelInfo) {
         LOGGER.info("Assembling model...");
         Model model = null;
         for(final File initFile : files) {
             try {
-                model = processModel(model, initFile);
+                model = processModel(model, initFile, includeModelInfo);
             } catch ( final IOException iae) {
                 LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae);
                 System.exit(1);
@@ -464,11 +127,12 @@ public class Main {
      * Process the given model and merge it into the provided model
      * @param model The already read model
      * @param modelFile The model file
+     * @param includeModelInfo
      * @return The merged model
      * @throws IOException If reading fails
      */
     private static Model processModel(Model model,
-            final File modelFile) throws IOException {
+            final File modelFile, boolean includeModelInfo) throws IOException {
         LOGGER.info("- reading model {}", modelFile);
 
         final Model nextModel = readProvisioningModel(modelFile);
@@ -501,7 +165,7 @@ public class Main {
                                     "txt");
 
                             final ArtifactHandler handler = mgr.getArtifactHandler(correctedId.toMvnUrl());
-                            model = processModel(model, handler.getFile());
+                            model = processModel(model, handler.getFile(), includeModelInfo);
 
                             removeList.add(a);
                         } else {
@@ -661,68 +325,134 @@ public class Main {
         }
     }
 
-    private static void convert(final Application app, final int index) {
-        final Feature f = new Feature("application");
+    private static Application buildApplication(final Model model, String propsFile) {
+        final Application app = new Application();
+
+        for(final Feature feature : model.getFeatures() ) {
+            buildFromFeature(feature, app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
+        }
+
+        // hard coded dependency to launchpad api
+        final org.apache.sling.feature.Artifact a = new org.apache.sling.feature.Artifact(ArtifactId.parse("org.apache.sling/org.apache.sling.launchpad.api/1.2.0"));
+        a.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, "1");
+        // sling.properties (TODO)
+        if ( propsFile == null ) {
+            app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");
+        } else {
 
-        // bundles
-        for(final org.apache.sling.feature.Artifact bundle : app.getBundles()) {
-            final ArtifactId id = bundle.getId();
-            final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
-            for(final Map.Entry<String, String> prop : bundle.getMetadata()) {
-                newBundle.getMetadata().put(prop.getKey(), prop.getValue());
+        }
+        // felix framework hard coded for now
+        app.setFramework(FeatureUtil.getFelixFrameworkId(null));
+        return app;
+    }
+
+    private static void buildFromFeature(final Feature feature,
+            final Bundles bundles,
+            final Configurations configurations,
+            final Extensions extensions,
+            final KeyValueMap properties) {
+        Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
+        for(final RunMode runMode : feature.getRunModes() ) {
+            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
+                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
+                    for(final Artifact artifact : group) {
+                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
+                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
+
+                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
+                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
+                        }
+
+                        if ( newArtifact.getId().getType().equals("zip") ) {
+                            if ( cpExtension == null ) {
+                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
+                                extensions.add(cpExtension);
+                            }
+                            cpExtension.getArtifacts().add(newArtifact);
+                        } else {
+                            int startLevel = group.getStartLevel();
+                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
+                                startLevel = 1;
+                            } else if ( startLevel == 0 ) {
+                                startLevel = 20;
+                            }
+                            newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
+                            bundles.add(newArtifact);
+                        }
+                    }
+                }
             }
-            int startLevel = bundle.getStartOrder();
-            if ( startLevel == 0 ) {
-                startLevel = 20;
+
+            for(final Configuration cfg : runMode.getConfigurations()) {
+                final org.apache.sling.feature.Configuration newCfg;
+                if ( cfg.getFactoryPid() != null ) {
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
+                } else {
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
+                }
+                final Enumeration<String> keys = cfg.getProperties().keys();
+                while ( keys.hasMoreElements() ) {
+                    final String key = keys.nextElement();
+                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
+                }
+                configurations.add(newCfg);
             }
-            f.getOrCreateRunMode(null).getOrCreateArtifactGroup(startLevel).add(newBundle);
-        }
 
-        // configurations
-        for(final org.apache.sling.feature.Configuration cfg : app.getConfigurations()) {
-            final Configuration c;
-            if ( cfg.isFactoryConfiguration() ) {
-                c = new Configuration(cfg.getName(), cfg.getFactoryPid());
-            } else {
-                c = new Configuration(cfg.getPid(), null);
+            for(final Map.Entry<String, String> prop : runMode.getSettings()) {
+                properties.put(prop.getKey(), prop.getValue());
             }
-            final Enumeration<String> keys = cfg.getProperties().keys();
-            while ( keys.hasMoreElements() ) {
-                final String key = keys.nextElement();
-                c.getProperties().put(key, cfg.getProperties().get(key));
+        }
+        Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
+        for(final Section sect : feature.getAdditionalSections("repoinit")) {
+            final String text = sect.getContents();
+            if ( repoExtension == null ) {
+                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
+                extensions.add(repoExtension);
+                repoExtension.setText(text);
+            } else {
+                repoExtension.setText(repoExtension.getText() + "\n\n" + text);
             }
-            f.getOrCreateRunMode(null).getConfigurations().add(c);
         }
+    }
 
-        // framework properties
-        for(final Map.Entry<String, String> prop : app.getFrameworkProperties()) {
-            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
-        }
 
-        // extensions: content packages and repoinit
-        for(final Extension ext : app.getExtensions()) {
-            if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
-                for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
-                    final ArtifactId id = cp.getId();
-                    final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
-                    for(final Map.Entry<String, String> prop : cp.getMetadata()) {
-                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
-                    }
-                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
-                }
+    private static List<org.apache.sling.feature.Feature> buildFeatures(final Model model) {
+        final List<org.apache.sling.feature.Feature> features = new ArrayList<>();
 
-            } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
-                final Section section = new Section("repoinit");
-                section.setContents(ext.getText());
-                f.getAdditionalSections().add(section);
-            } else if ( ext.isRequired() ) {
-                LOGGER.error("Unable to convert required extension {}", ext.getName());
-                System.exit(1);
+        for(final Feature feature : model.getFeatures() ) {
+            final String idString;
+            // use a default name if not present or not usable as a Maven artifactId ( starts with ':')
+            if ( feature.getName() != null && !feature.isSpecial() ) {
+                if ( feature.getVersion() != null ) {
+                    idString = "generated/" + feature.getName() + "/" + feature.getVersion();
+                } else {
+                    idString = "generated/" + feature.getName() + "/1.0.0";
+                }
+            } else {
+                idString = "generated/feature/1.0.0";
             }
+            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
+            features.add(f);
+
+            buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
         }
 
+        return features;
+    }
+
+    private static void writeApplication(final Application app, final String out) {
+        LOGGER.info("Writing application...");
+        final File file = new File(out);
+        try ( final FileWriter writer = new FileWriter(file)) {
+            ApplicationJSONWriter.write(writer, app);
+        } catch ( final IOException ioe) {
+            LOGGER.error("Unable to write application to {} : {}", out, ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+    }
+
+    private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
         LOGGER.info("Writing feature...");
-        String out = output;
         if ( index > 0 ) {
             final int lastDot = out.lastIndexOf('.');
             if ( lastDot == -1 ) {
@@ -732,10 +462,8 @@ public class Main {
             }
         }
         final File file = new File(out);
-        final Model m = new Model();
-        m.getFeatures().add(f);
         try ( final FileWriter writer = new FileWriter(file)) {
-            ModelWriter.write(writer, m);
+            FeatureJSONWriter.write(writer, f);
         } catch ( final IOException ioe) {
             LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
             System.exit(1);

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 12/40: Support writing variables when converting from provisioning model

Posted by da...@apache.org.
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 91f48ed50625802d6ddf219f9a77e5f522b14fb0
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Mar 20 12:02:58 2018 +0000

    Support writing variables when converting from provisioning model
---
 .../modelconverter/impl/FeatureToProvisioning.java |  2 +-
 .../modelconverter/impl/ProvisioningToFeature.java | 31 +++++++++++++---
 .../modelconverter/impl/ModelConverterTest.java    | 41 +++++++++++++++++-----
 src/test/resources/boot.json                       | 36 +++++++++----------
 src/test/resources/boot.txt                        |  2 +-
 5 files changed, 80 insertions(+), 32 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index ed0bd38..28cdff9 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -50,7 +50,7 @@ import java.util.Map;
  */
 public class FeatureToProvisioning {
     private static final Logger LOGGER = LoggerFactory.getLogger(FeatureToProvisioning.class);
-    private static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
+    static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
         org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
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 860de6b..0df66db 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
@@ -52,11 +52,13 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 /** Converter that converts the provisioning model to the feature model.
@@ -64,6 +66,15 @@ import java.util.Set;
 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);
+        final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
+        if (features.size() != 1)
+            throw new IllegalStateException("TODO");
+
+        writeFeature(features.get(0), output, 0);
+    }
+
     public static void convert(List<File> files,  String outputFile, String runModes, boolean createApp,
             boolean includeModelInfo, String propsFile) {
         final Model model = createModel(files, runModes, includeModelInfo);
@@ -199,7 +210,7 @@ public class ProvisioningToFeature {
     /**
      * Read the provisioning model
      */
-    static Model readProvisioningModel(final File file)
+    public static Model readProvisioningModel(final File file)
     throws IOException {
         try (final FileReader is = new FileReader(file)) {
             final Model m = ModelReader.read(is, file.getAbsolutePath());
@@ -331,7 +342,7 @@ public class ProvisioningToFeature {
         final Application app = new Application();
 
         for(final Feature feature : model.getFeatures() ) {
-            buildFromFeature(feature, app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
+            buildFromFeature(feature, app.getVariables(), app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
         }
 
         // hard coded dependency to launchpad api
@@ -349,10 +360,19 @@ public class ProvisioningToFeature {
     }
 
     private static void buildFromFeature(final Feature feature,
+            final KeyValueMap variables,
             final Bundles bundles,
             final Configurations configurations,
             final Extensions extensions,
             final KeyValueMap properties) {
+        for (Iterator<Map.Entry<String, String>> it = feature.getVariables().iterator(); it.hasNext(); ) {
+            Entry<String, String> entry = it.next();
+            variables.put(entry.getKey(), entry.getValue());
+        }
+        if (feature.getName().startsWith(":")) {
+            variables.put(FeatureToProvisioning.PROVISIONING_MODEL_NAME_VARIABLE, feature.getName());
+        }
+
         Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
         for(final RunMode runMode : feature.getRunModes() ) {
             if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
@@ -378,7 +398,10 @@ public class ProvisioningToFeature {
                             } else if ( startLevel == 0 ) {
                                 startLevel = 20;
                             }
-                            newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
+
+                            // TODO this is probably not correct
+                            // newArtifact.getMetadata().put(org.apache.sling.feature.Artifact.KEY_START_ORDER, String.valueOf(startLevel));
+
                             bundles.add(newArtifact);
                         }
                     }
@@ -436,7 +459,7 @@ public class ProvisioningToFeature {
             final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
             features.add(f);
 
-            buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
+            buildFromFeature(feature, f.getVariables(), f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
         }
 
         return features;
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 46dc48b..1572e9a 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
@@ -76,12 +76,24 @@ public class ModelConverterTest {
         testConvertToProvisioningModel("/boot.json", "/boot.txt");
     }
 
+    /* @Test
+    public void testBootToFeature() throws Exception {
+        testConvertToFeature("/boot.txt", "/boot.json");
+    } */
+
     @Test
     public void testOak() throws Exception {
         testConvertToProvisioningModel("/oak.json", "/oak.txt");
     }
 
-    private void testConvertToProvisioningModel(String originalJSON, String expectedProvModel) throws URISyntaxException, IOException {
+    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");
+
+        ProvisioningToFeature.convert(inFile, outFile.getAbsolutePath());
+    }
+
+    public void testConvertToProvisioningModel(String originalJSON, String expectedProvModel) throws URISyntaxException, IOException {
         File inFile = new File(getClass().getResource(originalJSON).toURI());
         File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
 
@@ -106,17 +118,17 @@ public class ModelConverterTest {
         assertEquals(expected.getName(), actual.getName());
         assertEquals(expected.getVersion(), actual.getVersion());
         assertEquals(expected.getType(), actual.getType());
-        assertRunModesEqual(expected.getRunModes(), actual.getRunModes());
+        assertRunModesEqual(expected.getName(), expected.getRunModes(), actual.getRunModes());
         assertKVMapEquals(expected.getVariables(), actual.getVariables());
         assertSectionsEqual(expected.getAdditionalSections(), actual.getAdditionalSections());
     }
 
-    private void assertRunModesEqual(List<RunMode> expected, List<RunMode> actual) {
+    private void assertRunModesEqual(String featureName, List<RunMode> expected, List<RunMode> actual) {
         assertEquals(expected.size(), actual.size());
         for (RunMode rm : expected) {
             boolean found = false;
             for (RunMode arm : actual) {
-                if (runModesEqual(rm, arm)) {
+                if (runModesEqual(featureName, rm, arm)) {
                     found = true;
                     break;
                 }
@@ -128,7 +140,7 @@ public class ModelConverterTest {
         }
     }
 
-    private boolean runModesEqual(RunMode rm1, RunMode rm2) {
+    private boolean runModesEqual(String featureName, RunMode rm1, RunMode rm2) {
         if (rm1.getNames() == null) {
             if (rm2.getNames() != null)
                 return false;
@@ -151,7 +163,7 @@ public class ModelConverterTest {
         for (ArtifactGroup g1 : ag1) {
             boolean found = false;
             for (ArtifactGroup g2 : ag2) {
-                if (artifactGroupsEquals(g1, g2)) {
+                if (artifactGroupsEquals(featureName, g1, g2)) {
                     found = true;
                     break;
                 }
@@ -228,8 +240,10 @@ public class ModelConverterTest {
         return m;
     }
 
-    private boolean artifactGroupsEquals(ArtifactGroup g1, ArtifactGroup g2) {
-        if (g1.getStartLevel() != g2.getStartLevel())
+    private boolean artifactGroupsEquals(String featureName, ArtifactGroup g1, ArtifactGroup g2) {
+        int sl1 = effectiveStartLevel(featureName, g1.getStartLevel());
+        int sl2 = effectiveStartLevel(featureName, g2.getStartLevel());
+        if (sl1 != sl2)
             return false;
 
         List<Artifact> al1 = new ArrayList<>();
@@ -247,6 +261,17 @@ public class ModelConverterTest {
         return true;
     }
 
+    private int effectiveStartLevel(String featureName, int startLevel) {
+        if (startLevel != 0)
+            return startLevel;
+
+        if (ModelConstants.FEATURE_BOOT.equals(featureName)) {
+            return 1;
+        } else {
+            return 20;
+        }
+    }
+
     private void assertKVMapEquals(KeyValueMap<String> expected, KeyValueMap<String> actual) {
         assertEquals(kvToMap(expected), kvToMap(actual));
     }
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
index 8d0634a..c267b67 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot.json
@@ -12,75 +12,75 @@
     "bundles": [
         {
             "id": "org.slf4j/slf4j-api/${slf4j.version}",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.log/5.1.0",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.slf4j/jcl-over-slf4j/${slf4j.version}",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.slf4j/log4j-over-slf4j/${slf4j.version}",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.settings/1.3.8",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.installer.core/3.8.12",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.felix/org.apache.felix.configadmin/1.8.16",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.aries/org.apache.aries.util/1.1.3",
-            "start-level": 20
+            "start-level": 1
         },
         {
             "id": "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0",
-            "start-level": 20
+            "start-level": 1
         }],
         
     "framework-properties": {
diff --git a/src/test/resources/boot.txt b/src/test/resources/boot.txt
index 7e22e39..df5a947 100644
--- a/src/test/resources/boot.txt
+++ b/src/test/resources/boot.txt
@@ -32,7 +32,7 @@
 [variables]
     slf4j.version=1.7.25
 
-[artifacts startLevel=20]
+[artifacts]
     org.slf4j/slf4j-api/${slf4j.version}
     org.apache.sling/org.apache.sling.commons.log/5.1.0
     org.apache.sling/org.apache.sling.commons.logservice/1.0.6

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 35/40: Rename packages

Posted by da...@apache.org.
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 ddc06e69187f5af101d2435f475d945cb9527443
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Apr 18 10:26:45 2018 +0200

    Rename packages
---
 .../feature/modelconverter/impl/FeatureToProvisioning.java   |  6 +++---
 .../org/apache/sling/feature/modelconverter/impl/Main.java   |  4 ++--
 .../feature/modelconverter/impl/ProvisioningToFeature.java   | 12 ++++++------
 .../feature/modelconverter/impl/ModelConverterTest.java      |  6 +++---
 4 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index fd1d268..e6ce8a8 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -40,11 +40,11 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.json.ApplicationJSONReader;
+import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.SlingConstants;
-import org.apache.sling.feature.support.artifact.ArtifactManager;
-import org.apache.sling.feature.support.json.ApplicationJSONReader;
-import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.support.resolver.FeatureResolver;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
index abf7bfb..a21791d 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -22,8 +22,8 @@ import org.apache.commons.cli.DefaultParser;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
-import org.apache.sling.feature.support.artifact.ArtifactManager;
-import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
+import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.ArtifactManagerConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
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 1be7c02..466e961 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
@@ -39,14 +39,14 @@ import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.io.ArtifactHandler;
+import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.ArtifactManagerConfig;
+import org.apache.sling.feature.io.json.ApplicationJSONWriter;
+import org.apache.sling.feature.io.json.FeatureJSONWriter;
+import org.apache.sling.feature.io.json.WriteOption;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.SlingConstants;
-import org.apache.sling.feature.support.artifact.ArtifactHandler;
-import org.apache.sling.feature.support.artifact.ArtifactManager;
-import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
-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;
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 86705da..4f17c1b 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
@@ -44,10 +44,10 @@ import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.io.ArtifactManager;
+import org.apache.sling.feature.io.ArtifactManagerConfig;
+import org.apache.sling.feature.io.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.feature.support.FeatureUtil;
-import org.apache.sling.feature.support.artifact.ArtifactManager;
-import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
-import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.ArtifactGroup;
 import org.apache.sling.provisioning.model.Configuration;

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 25/40: Convert repoinit sections to use JSON array representation

Posted by da...@apache.org.
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 896ebeb805582a63c986d1ddf46f886881d05712
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 4 14:57:26 2018 +0100

    Convert repoinit sections to use JSON array representation
---
 .../modelconverter/impl/FeatureToProvisioning.java | 23 ++++++++++++++++-
 .../modelconverter/impl/ProvisioningToFeature.java | 29 +++++++++++++++++++---
 .../modelconverter/impl/ModelConverterTest.java    | 13 +++++++---
 src/test/resources/repoinit.json                   |  2 +-
 4 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 3c526c2..04b8428 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -21,6 +21,7 @@ import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.process.FeatureResolver;
@@ -41,11 +42,18 @@ import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.StringReader;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonReader;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+
 /** Converter that converts the feature model to the provisioning model.
  */
 public class FeatureToProvisioning {
@@ -214,7 +222,20 @@ public class FeatureToProvisioning {
 
             } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
                 final Section section = new Section("repoinit");
-                section.setContents(ext.getText());
+                if (ext.getType() == ExtensionType.TEXT) {
+                    section.setContents(ext.getText());
+                } else if (ext.getType() == ExtensionType.JSON) {
+                    JsonReader reader = Json.createReader(new StringReader(ext.getJSON()));
+                    JsonArray arr = reader.readArray();
+                    StringBuilder sb = new StringBuilder();
+                    for (JsonValue v : arr) {
+                        if (v instanceof JsonString) {
+                            sb.append(((JsonString) v).getString());
+                            sb.append('\n');
+                        }
+                    }
+                    section.setContents(sb.toString());
+                }
                 f.getAdditionalSections().add(section);
             } else if ( ext.isRequired() ) {
                 LOGGER.error("Unable to convert required extension {}", ext.getName());
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 70a6d76..cf1a973 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
@@ -405,11 +405,34 @@ public class ProvisioningToFeature {
         }
         Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
         for(final Section sect : feature.getAdditionalSections("repoinit")) {
-            final String text = sect.getContents();
+            String text = sect.getContents();
             if ( repoExtension == null ) {
-                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
+//                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
+//                extensions.add(repoExtension);
+//                repoExtension.setJSON(text);
+
+                repoExtension = new Extension(ExtensionType.JSON, Extension.NAME_REPOINIT, true);
                 extensions.add(repoExtension);
-                repoExtension.setText(text);
+                text = text.replace('\t', ' ');
+                String[] lines = text.split("[\n]");
+
+                StringBuilder sb = new StringBuilder();
+                sb.append('[');
+
+                boolean first = true;
+                for (String t : lines) {
+                    if (first)
+                        first = false;
+                    else
+                        sb.append(',');
+
+                    sb.append('"');
+                    sb.append(t);
+                    sb.append('"');
+                }
+                sb.append(']');
+
+                repoExtension.setJSON(sb.toString());
             } else {
                 repoExtension.setText(repoExtension.getText() + "\n\n" + text);
             }
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 4231489..df0eacf 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
@@ -19,6 +19,7 @@ package org.apache.sling.feature.modelconverter.impl;
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.ArtifactManagerConfig;
@@ -505,9 +506,15 @@ public class ModelConverterTest {
             assertEquals(ex.getName(), ac.getName());
             assertEquals(ex.isRequired(), ac.isRequired());
 
-            String exTxt = ex.getText().replaceAll("\\s+", "");
-            String acTxt = ac.getText().replaceAll("\\s+", "");
-            assertEquals(exTxt, acTxt);
+            if (ex.getType() == ExtensionType.TEXT) {
+                String exTxt = ex.getText().replaceAll("\\s+", "");
+                String acTxt = ac.getText().replaceAll("\\s+", "");
+                assertEquals(exTxt, acTxt);
+            } else if (ex.getType() == ExtensionType.JSON) {
+                String exJson = ex.getJSON().replaceAll("\\s+", "").replaceAll("\"\",", "");
+                String acJson = ac.getJSON().replaceAll("\\s+", "").replaceAll("\"\",", "");
+                assertEquals(exJson, acJson);
+            }
 
             /* TODO reinstantiate for Artifacts extentions
             assertEquals(ex.getArtifacts().size(), ac.getArtifacts().size());
diff --git a/src/test/resources/repoinit.json b/src/test/resources/repoinit.json
index 01d3b16..1fe41f3 100644
--- a/src/test/resources/repoinit.json
+++ b/src/test/resources/repoinit.json
@@ -21,7 +21,7 @@
             "references":"model@repoinit:context:/resources/provisioning/model.txt"
         }
     },
-    "repoinit:TEXT|false": [
+    "repoinit:JSON|false": [
         "# general",
         "create path (sling:OrderedFolder) /content",
         "set ACL for everyone",

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 01/40: Move feature model to whiteboard git

Posted by da...@apache.org.
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 8ca0ccbf5a2efac4a09df847d86c3d4e4c55317a
Author: Carsten Ziegeler <cz...@adobe.com>
AuthorDate: Fri Nov 3 15:06:50 2017 +0100

    Move feature model to whiteboard git
---
 pom.xml                                            | 127 ++++
 .../sling/feature/modelconverter/impl/Main.java    | 729 +++++++++++++++++++++
 2 files changed, 856 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..64dbec0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+    <!--
+        Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+        agreements. See the NOTICE file distributed with this work for additional information
+        regarding copyright ownership. The ASF licenses this file to you 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.
+    -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>32</version>
+        <relativePath />
+    </parent>
+
+    <artifactId>org.apache.sling.feature.modelconverter</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <name>Apache Sling Feature Model Converter</name>
+    <description>
+        A feature describes an OSGi system
+    </description>
+
+    <properties>
+        <sling.java.version>8</sling.java.version>
+    </properties>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/tooling/support/feature-modelconverter</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/tooling/support/feature-modelconverter</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/tooling/support/feature-modelconverter</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                <execution>
+                    <id>unpack-dependencies</id>
+                    <phase>prepare-package</phase>
+                    <goals>
+                        <goal>unpack-dependencies</goal>
+                    </goals>
+                    <configuration>
+                        <excludes>META-INF/**</excludes>
+                        <outputDirectory>${project.build.directory}/classes</outputDirectory>
+                        <overWriteReleases>false</overWriteReleases>
+                        <overWriteSnapshots>true</overWriteSnapshots>
+                        <includeArtifactIds>commons-cli,org.apache.sling.feature,org.apache.sling.feature.support,org.apache.sling.commons.johnzon,org.apache.sling.provisioning.model,slf4j-api,slf4j-simple,osgi.core</includeArtifactIds>
+                    </configuration>
+                </execution>
+            </executions>
+            </plugin>
+                <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.apache.sling.feature.modelconverter.impl.Main</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+             <groupId>commons-cli</groupId>
+             <artifactId>commons-cli</artifactId>
+             <version>1.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.feature.support</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.provisioning.model</artifactId>
+            <version>1.8.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.johnzon</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+      <!-- Testing -->
+        <dependency>
+        	<groupId>junit</groupId>
+        	<artifactId>junit</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
new file mode 100644
index 0000000..f030367
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/Main.java
@@ -0,0 +1,729 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.feature.modelconverter.impl;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.sling.feature.Application;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Bundles;
+import org.apache.sling.feature.Configurations;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Extensions;
+import org.apache.sling.feature.KeyValueMap;
+import org.apache.sling.feature.support.ArtifactHandler;
+import org.apache.sling.feature.support.ArtifactManager;
+import org.apache.sling.feature.support.ArtifactManagerConfig;
+import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.json.ApplicationJSONReader;
+import org.apache.sling.feature.support.json.ApplicationJSONWriter;
+import org.apache.sling.feature.support.json.FeatureJSONWriter;
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.MergeUtility;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelConstants;
+import org.apache.sling.provisioning.model.ModelUtility;
+import org.apache.sling.provisioning.model.ModelUtility.ResolverOptions;
+import org.apache.sling.provisioning.model.ModelUtility.VariableResolver;
+import org.apache.sling.provisioning.model.RunMode;
+import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.Traceable;
+import org.apache.sling.provisioning.model.io.ModelReader;
+import org.apache.sling.provisioning.model.io.ModelWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Main {
+
+    private static Logger LOGGER;
+
+    private static String runModes;
+
+    private static String output;
+
+    private static String input;
+
+    private static boolean createApp = false;
+
+    private static boolean includeModelInfo = false;
+
+    private static String repoUrls;
+
+    private static String propsFile;
+
+    /**
+     * Parse the command line parameters and update a configuration object.
+     * @param args Command line parameters
+     * @return Configuration object.
+     */
+    private static void parseArgs(final String[] args) {
+        final Option repoOption =  Option.builder("u").hasArg().argName("Set repository url")
+                .desc("repository url").required().build();
+
+        final Option modelOption =  new Option("f", true, "Set feature files/directories");
+        final Option propsOption =  new Option("p", true, "sling.properties file");
+        final Option runModeOption =  new Option("r", true, "Set run modes (comma separated)");
+        final Option createAppOption = new Option("a", false, "If enabled, create application json");
+        createAppOption.setArgs(0);
+        final Option includeModelOption = new Option("i", false, "Include model filename as metadata for artifacts");
+        includeModelOption.setArgs(0);
+
+        final Option outputOption = Option.builder("o").hasArg().argName("Set output file")
+                .desc("output file").build();
+
+        final Options options = new Options();
+        options.addOption(repoOption);
+        options.addOption(modelOption);
+        options.addOption(createAppOption);
+        options.addOption(outputOption);
+        options.addOption(includeModelOption);
+        options.addOption(propsOption);
+        options.addOption(runModeOption);
+
+        final CommandLineParser parser = new DefaultParser();
+        try {
+            final CommandLine cl = parser.parse(options, args);
+
+            if ( cl.hasOption(repoOption.getOpt()) ) {
+                repoUrls = cl.getOptionValue(repoOption.getOpt());
+            }
+            if ( cl.hasOption(modelOption.getOpt()) ) {
+                input = cl.getOptionValue(modelOption.getOpt());
+            }
+            if ( cl.hasOption(createAppOption.getOpt()) ) {
+                createApp = true;
+            }
+            if ( cl.hasOption(includeModelOption.getOpt()) ) {
+                includeModelInfo = true;
+            }
+            if ( cl.hasOption(runModeOption.getOpt()) ) {
+                runModes = cl.getOptionValue(runModeOption.getOpt());
+            }
+            if ( cl.hasOption(outputOption.getOpt()) ) {
+                output = cl.getOptionValue(outputOption.getOpt());
+            }
+            if ( cl.hasOption(propsOption.getOpt()) ) {
+                propsFile = cl.getOptionValue(propsOption.getOpt());
+            }
+        } catch ( final ParseException pe) {
+            LOGGER.error("Unable to parse command line: {}", pe.getMessage(), pe);
+            System.exit(1);
+        }
+        if ( input == null ) {
+            LOGGER.error("Required argument missing: model file or directory");
+            System.exit(1);
+        }
+    }
+
+    private static ArtifactManager getArtifactManager() {
+        final ArtifactManagerConfig amConfig = new ArtifactManagerConfig();
+        if ( repoUrls != null ) {
+            amConfig.setRepositoryUrls(repoUrls.split(","));
+        }
+        try {
+            return ArtifactManager.getArtifactManager(amConfig);
+        } catch ( IOException ioe) {
+            LOGGER.error("Unable to create artifact manager " + ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+        // we never reach this, but have to keep the compiler happy
+        return null;
+    }
+
+    public static void main(final String[] args) {
+        // setup logging
+        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "info");
+        System.setProperty("org.slf4j.simpleLogger.showThreadName", "false");
+        System.setProperty("org.slf4j.simpleLogger.levelInBrackets", "true");
+        System.setProperty("org.slf4j.simpleLogger.showLogName", "false");
+
+        LOGGER = LoggerFactory.getLogger("modelconverter");
+
+        LOGGER.info("Apache Sling Provisiong Model to Feature Application Converter");
+        LOGGER.info("");
+
+        parseArgs(args);
+
+        final ArtifactManagerConfig amConfig = new ArtifactManagerConfig();
+        if ( repoUrls != null ) {
+            amConfig.setRepositoryUrls(repoUrls.split(","));
+        }
+        final ArtifactManager am = getArtifactManager();
+
+        final File f = new File(input);
+        final List<File> files = new ArrayList<>();
+        if ( f.isDirectory() ) {
+            for(final File file : f.listFiles()) {
+                if ( file.isFile() && !file.getName().startsWith(".") ) {
+                    files.add(file);
+                }
+            }
+            if ( files.isEmpty() ) {
+                LOGGER.error("No files found in {}", f);
+                System.exit(1);
+            }
+            Collections.sort(files);
+        } else {
+            files.add(f);
+        }
+        boolean isJson = false;
+        boolean isTxt = false;
+        for(final File t : files) {
+            if ( t.getName().endsWith(".json") ) {
+                if ( isTxt ) {
+                    LOGGER.error("Input files are a mixture of JSON and txt");
+                    System.exit(1);
+                }
+                isJson = true;
+            } else {
+                if ( isJson ) {
+                    LOGGER.error("Input files are a mixture of JSON and txt");
+                    System.exit(1);
+                }
+                isTxt = true;
+            }
+        }
+
+        if ( isTxt ) {
+            if ( output == null ) {
+                output = createApp ? "application.json" : "feature.json";
+            }
+            final Model model = createModel(files, runModes);
+
+            if ( createApp ) {
+                final Application app = buildApplication(model);
+
+                writeApplication(app, output);
+            } else {
+                final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
+                int index = 1;
+                for(final org.apache.sling.feature.Feature feature : features) {
+                    writeFeature(feature, output, features.size() > 1 ? index : 0);
+                    index++;
+                }
+            }
+        } else {
+            if ( output == null ) {
+                output = createApp ? "application.txt" : "feature.txt";
+            }
+            try {
+                if ( createApp ) {
+                    // each file is an application
+                    int index = 1;
+                    for(final File appFile : files ) {
+                        try ( final FileReader r = new FileReader(appFile) ) {
+                            final Application app = ApplicationJSONReader.read(r);
+                            convert(app, files.size() > 1 ? index : 0);
+                        }
+                        index++;
+                    }
+                } else {
+                    final Application app = FeatureUtil.assembleApplication(null, am, files.stream()
+                            .map(File::getAbsolutePath)
+                            .toArray(String[]::new));
+                    convert(app, 0);
+                }
+            } catch ( final IOException ioe) {
+                LOGGER.error("Unable to read feature/application files " + ioe.getMessage(), ioe);
+                System.exit(1);
+            }
+        }
+    }
+
+    private static List<org.apache.sling.feature.Feature> buildFeatures(final Model model) {
+        final List<org.apache.sling.feature.Feature> features = new ArrayList<>();
+
+        for(final Feature feature : model.getFeatures() ) {
+            final String idString;
+            if ( feature.getName() != null ) {
+                if ( feature.getVersion() != null ) {
+                    idString = "generated/" + feature.getName() + "/" + feature.getVersion();
+                } else {
+                    idString = "generated/" + feature.getName() + "/1.0.0";
+                }
+            } else {
+                idString = "generated/feature/1.0.0";
+            }
+            final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.fromMvnId(idString));
+            features.add(f);
+
+            buildFromFeature(feature, f.getBundles(), f.getConfigurations(), f.getExtensions(), f.getFrameworkProperties());
+        }
+
+        return features;
+    }
+
+    private static Application buildApplication(final Model model) {
+        final Application app = new Application();
+
+        for(final Feature feature : model.getFeatures() ) {
+            buildFromFeature(feature, app.getBundles(), app.getConfigurations(), app.getExtensions(), app.getFrameworkProperties());
+        }
+
+        // hard coded dependency to launchpad api
+        app.getBundles().add(1, new org.apache.sling.feature.Artifact(ArtifactId.fromMvnId("org.apache.sling/org.apache.sling.launchpad.api/1.2.0")));
+        // sling.properties (TODO)
+        if ( propsFile == null ) {
+            app.getFrameworkProperties().put("org.osgi.framework.bootdelegation", "sun.*,com.sun.*");
+        } else {
+
+        }
+        // felix framework hard coded for now
+        app.setFramework(FeatureUtil.getFelixFrameworkId(null));
+        return app;
+    }
+
+    private static void buildFromFeature(final Feature feature,
+            final Bundles bundles,
+            final Configurations configurations,
+            final Extensions extensions,
+            final KeyValueMap properties) {
+        Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
+        for(final RunMode runMode : feature.getRunModes() ) {
+            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
+                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
+                    for(final Artifact artifact : group) {
+                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
+                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
+
+                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
+                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
+                        }
+
+                        if ( newArtifact.getId().getType().equals("zip") ) {
+                            if ( cpExtension == null ) {
+                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
+                                extensions.add(cpExtension);
+                            }
+                            cpExtension.getArtifacts().add(newArtifact);
+                        } else {
+                            int startLevel = group.getStartLevel();
+                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
+                                startLevel = 1;
+                            } else if ( startLevel == 0 ) {
+                                startLevel = 20;
+                            }
+                            bundles.add(startLevel, newArtifact);
+                        }
+                    }
+                }
+            }
+
+            for(final Configuration cfg : runMode.getConfigurations()) {
+                final org.apache.sling.feature.Configuration newCfg;
+                if ( cfg.getFactoryPid() != null ) {
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
+                } else {
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
+                }
+                final Enumeration<String> keys = cfg.getProperties().keys();
+                while ( keys.hasMoreElements() ) {
+                    final String key = keys.nextElement();
+                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
+                }
+                configurations.add(newCfg);
+            }
+
+            for(final Map.Entry<String, String> prop : runMode.getSettings()) {
+                properties.put(prop.getKey(), prop.getValue());
+            }
+        }
+        Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
+        for(final Section sect : feature.getAdditionalSections("repoinit")) {
+            final String text = sect.getContents();
+            if ( repoExtension == null ) {
+                repoExtension = new Extension(ExtensionType.TEXT, Extension.NAME_REPOINIT, true);
+                extensions.add(repoExtension);
+                repoExtension.setText(text);
+            } else {
+                repoExtension.setText(repoExtension.getText() + "\n\n" + text);
+            }
+        }
+    }
+
+    private static void writeApplication(final Application app, final String out) {
+        LOGGER.info("Writing application...");
+        final File file = new File(out);
+        try ( final FileWriter writer = new FileWriter(file)) {
+            ApplicationJSONWriter.write(writer, app);
+        } catch ( final IOException ioe) {
+            LOGGER.error("Unable to write application to {} : {}", out, ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+    }
+
+    private static void writeFeature(final org.apache.sling.feature.Feature f, String out, final int index) {
+        LOGGER.info("Writing feature...");
+        if ( index > 0 ) {
+            final int lastDot = out.lastIndexOf('.');
+            if ( lastDot == -1 ) {
+                out = out + "_" + String.valueOf(index);
+            } else {
+                out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
+            }
+        }
+        final File file = new File(out);
+        try ( final FileWriter writer = new FileWriter(file)) {
+            FeatureJSONWriter.write(writer, f);
+        } catch ( final IOException ioe) {
+            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Read the models and prepare the model
+     * @param files The model files
+     */
+    private static Model createModel(final List<File> files,
+            final String runModes) {
+        LOGGER.info("Assembling model...");
+        Model model = null;
+        for(final File initFile : files) {
+            try {
+                model = processModel(model, initFile);
+            } catch ( final IOException iae) {
+                LOGGER.error("Unable to read provisioning model {} : {}", initFile, iae.getMessage(), iae);
+                System.exit(1);
+            }
+        }
+
+        final Model effectiveModel = ModelUtility.getEffectiveModel(model, new ResolverOptions().variableResolver(new VariableResolver() {
+
+            @Override
+            public String resolve(Feature feature, String name) {
+                if ( "sling.home".equals(name) ) {
+                    return "${sling.home}";
+                }
+                return feature.getVariables().get(name);
+            }
+        }));
+        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()) {
+                LOGGER.error("- {} : {}", entry.getKey().getLocation(), entry.getValue());
+            }
+            System.exit(1);
+        }
+        final Set<String> modes = calculateRunModes(effectiveModel, runModes);
+
+        removeInactiveFeaturesAndRunModes(effectiveModel, modes);
+
+        return effectiveModel;
+    }
+
+    /**
+     * Process the given model and merge it into the provided model
+     * @param model The already read model
+     * @param modelFile The model file
+     * @return The merged model
+     * @throws IOException If reading fails
+     */
+    private static Model processModel(Model model,
+            final File modelFile) throws IOException {
+        LOGGER.info("- reading model {}", modelFile);
+
+        final Model nextModel = readProvisioningModel(modelFile);
+        // resolve references to other models
+        final ResolverOptions options = new ResolverOptions().variableResolver(new VariableResolver() {
+
+            @Override
+            public String resolve(final Feature feature, final String name) {
+                return name;
+            }
+        });
+
+
+        final Model effectiveModel = ModelUtility.getEffectiveModel(nextModel, options);
+        for(final Feature feature : effectiveModel.getFeatures()) {
+            for(final RunMode runMode : feature.getRunModes()) {
+                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
+                    final List<org.apache.sling.provisioning.model.Artifact> removeList = new ArrayList<>();
+                    for(final org.apache.sling.provisioning.model.Artifact a : group) {
+                        if ( "slingstart".equals(a.getType())
+                             || "slingfeature".equals(a.getType())) {
+
+                            final ArtifactManagerConfig cfg = new ArtifactManagerConfig();
+                            final ArtifactManager mgr = ArtifactManager.getArtifactManager(cfg);
+
+                            final ArtifactId correctedId = new ArtifactId(a.getGroupId(),
+                                    a.getArtifactId(),
+                                    a.getVersion(),
+                                    "slingstart".equals(a.getType()) ? "slingfeature" : a.getClassifier(),
+                                    "txt");
+
+                            final ArtifactHandler handler = mgr.getArtifactHandler(correctedId.toMvnUrl());
+                            model = processModel(model, handler.getFile());
+
+                            removeList.add(a);
+                        } else {
+                            final org.apache.sling.provisioning.model.Artifact realArtifact = nextModel.getFeature(feature.getName()).getRunMode(runMode.getNames()).getArtifactGroup(group.getStartLevel()).search(a);
+
+                            if ( includeModelInfo ) {
+                                realArtifact.getMetadata().put("model-filename", modelFile.getName());
+                            }
+                            if ( runMode.getNames() != null ) {
+                                realArtifact.getMetadata().put("runmodes", String.join(",", runMode.getNames()));
+                            }
+                        }
+                    }
+                    for(final org.apache.sling.provisioning.model.Artifact r : removeList) {
+                        nextModel.getFeature(feature.getName()).getRunMode(runMode.getNames()).getArtifactGroup(group.getStartLevel()).remove(r);
+                    }
+                }
+            }
+        }
+
+        if ( model == null ) {
+            model = nextModel;
+        } else {
+            MergeUtility.merge(model, nextModel);
+        }
+        return model;
+    }
+
+    /**
+     * Read the provisioning model
+     */
+    private static Model readProvisioningModel(final File file)
+    throws IOException {
+        try (final FileReader is = new FileReader(file)) {
+            final Model m = ModelReader.read(is, file.getAbsolutePath());
+            return m;
+        }
+    }
+
+    private static void removeInactiveFeaturesAndRunModes(final Model m,
+            final Set<String> activeRunModes) {
+        final String[] requiredFeatures = new String[] {ModelConstants.FEATURE_LAUNCHPAD, ModelConstants.FEATURE_BOOT};
+        // first pass:
+        // - remove special features except boot required ones
+        // - remove special run modes and inactive run modes
+        // - remove special configurations (TODO)
+        final Iterator<Feature> i = m.getFeatures().iterator();
+        while ( i.hasNext() ) {
+            final Feature feature = i.next();
+            if ( feature.isSpecial() ) {
+                boolean remove = true;
+                if ( requiredFeatures != null ) {
+                    for(final String name : requiredFeatures) {
+                        if ( feature.getName().equals(name) ) {
+                            remove = false;
+                            break;
+                        }
+                    }
+                }
+                if ( remove ) {
+                    i.remove();
+                    continue;
+                }
+            }
+            feature.setComment(null);
+            final Iterator<RunMode> rmI = feature.getRunModes().iterator();
+            while ( rmI.hasNext() ) {
+                final RunMode rm = rmI.next();
+                if ( rm.isActive(activeRunModes) || rm.isRunMode(ModelConstants.RUN_MODE_STANDALONE) ) {
+                    final Iterator<Configuration> cI = rm.getConfigurations().iterator();
+                    while ( cI.hasNext() ) {
+                        final Configuration config = cI.next();
+                        if ( config.isSpecial() ) {
+                            cI.remove();
+                            continue;
+                        }
+                        config.setComment(null);
+                    }
+                } else {
+                    rmI.remove();
+                    continue;
+                }
+            }
+        }
+
+        // second pass: aggregate the settings and add them to the first required feature
+        final Feature requiredFeature = m.getFeature(requiredFeatures[0]);
+        if ( requiredFeature != null ) {
+            for(final Feature f : m.getFeatures()) {
+                if ( f.getName().equals(requiredFeature.getName()) ) {
+                    continue;
+                }
+                copyAndClearSettings(requiredFeature, f.getRunMode(new String[] {ModelConstants.RUN_MODE_STANDALONE}));
+                copyAndClearSettings(requiredFeature, f.getRunMode());
+            }
+        }
+    }
+
+    private static void copyAndClearSettings(final Feature requiredFeature, final RunMode rm) {
+        if ( rm != null && !rm.getSettings().isEmpty() ) {
+            final RunMode requiredRunMode = requiredFeature.getOrCreateRunMode(null);
+            final Set<String> keys = new HashSet<>();
+            for(final Map.Entry<String, String> entry : rm.getSettings()) {
+                requiredRunMode.getSettings().put(entry.getKey(), entry.getValue());
+                keys.add(entry.getKey());
+            }
+
+            for(final String key : keys) {
+                rm.getSettings().remove(key);
+            }
+        }
+    }
+
+    private static Set<String> calculateRunModes(final Model model, final String runModes) {
+        final Set<String> modesSet = new HashSet<>();
+
+        // check configuration property first
+        if (runModes != null && runModes.trim().length() > 0) {
+            final String[] modes = runModes.split(",");
+            for(int i=0; i < modes.length; i++) {
+                modesSet.add(modes[i].trim());
+            }
+        }
+
+        //  handle configured options
+        final Feature feature = model.getFeature(ModelConstants.FEATURE_BOOT);
+        if ( feature != null ) {
+            handleOptions(modesSet, feature.getRunMode().getSettings().get("sling.run.mode.options"));
+            handleOptions(modesSet, feature.getRunMode().getSettings().get("sling.run.mode.install.options"));
+        }
+
+        return modesSet;
+    }
+
+    private static void handleOptions(final Set<String> modesSet, final String propOptions) {
+        if ( propOptions != null && propOptions.trim().length() > 0 ) {
+
+            final String[] options = propOptions.trim().split("\\|");
+            for(final String opt : options) {
+                String selected = null;
+                final String[] modes = opt.trim().split(",");
+                for(int i=0; i<modes.length; i++) {
+                    modes[i] = modes[i].trim();
+                    if ( selected != null ) {
+                        modesSet.remove(modes[i]);
+                    } else {
+                        if ( modesSet.contains(modes[i]) ) {
+                            selected = modes[i];
+                        }
+                    }
+                }
+                if ( selected == null ) {
+                    selected = modes[0];
+                    modesSet.add(modes[0]);
+                }
+            }
+        }
+    }
+
+    private static void convert(final Application app, final int index) {
+        final Feature f = new Feature("application");
+
+        // bundles
+        for(final Map.Entry<Integer, org.apache.sling.feature.Artifact> bundle : app.getBundles()) {
+            final ArtifactId id = bundle.getValue().getId();
+            final Artifact newBundle = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
+            for(final Map.Entry<String, String> prop : bundle.getValue().getMetadata()) {
+                newBundle.getMetadata().put(prop.getKey(), prop.getValue());
+            }
+            f.getOrCreateRunMode(null).getOrCreateArtifactGroup(bundle.getKey()).add(newBundle);
+        }
+
+        // configurations
+        for(final org.apache.sling.feature.Configuration cfg : app.getConfigurations()) {
+            final Configuration c;
+            if ( cfg.isFactoryConfiguration() ) {
+                c = new Configuration(cfg.getName(), cfg.getFactoryPid());
+            } else {
+                c = new Configuration(cfg.getPid(), null);
+            }
+            final Enumeration<String> keys = cfg.getProperties().keys();
+            while ( keys.hasMoreElements() ) {
+                final String key = keys.nextElement();
+                c.getProperties().put(key, cfg.getProperties().get(key));
+            }
+            f.getOrCreateRunMode(null).getConfigurations().add(c);
+        }
+
+        // framework properties
+        for(final Map.Entry<String, String> prop : app.getFrameworkProperties()) {
+            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
+        }
+
+        // extensions: content packages and repoinit
+        for(final Extension ext : app.getExtensions()) {
+            if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
+                for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
+                    final ArtifactId id = cp.getId();
+                    final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
+                    for(final Map.Entry<String, String> prop : cp.getMetadata()) {
+                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                    }
+                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
+                }
+
+            } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
+                final Section section = new Section("repoinit");
+                section.setContents(ext.getText());
+                f.getAdditionalSections().add(section);
+            } else if ( ext.isRequired() ) {
+                LOGGER.error("Unable to convert required extension {}", ext.getName());
+                System.exit(1);
+            }
+        }
+
+        LOGGER.info("Writing feature...");
+        String out = output;
+        if ( index > 0 ) {
+            final int lastDot = out.lastIndexOf('.');
+            if ( lastDot == -1 ) {
+                out = out + "_" + String.valueOf(index);
+            } else {
+                out = out.substring(0, lastDot) + "_" + String.valueOf(index) + out.substring(lastDot);
+            }
+        }
+        final File file = new File(out);
+        final Model m = new Model();
+        m.getFeatures().add(f);
+        try ( final FileWriter writer = new FileWriter(file)) {
+            ModelWriter.write(writer, m);
+        } catch ( final IOException ioe) {
+            LOGGER.error("Unable to write feature to {} : {}", out, ioe.getMessage(), ioe);
+            System.exit(1);
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 31/40: Move Sling specific constants into support module

Posted by da...@apache.org.
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 956cdff950394e3454079cd4a264f43736b8c266
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Apr 17 10:31:04 2018 +0200

    Move Sling specific constants into support module
---
 .../modelconverter/impl/FeatureToProvisioning.java | 37 ++++++++++----------
 .../modelconverter/impl/ProvisioningToFeature.java | 39 +++++++++++-----------
 2 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 018f99c..fd1d268 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -16,6 +16,22 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonReader;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
@@ -25,6 +41,7 @@ import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.feature.support.artifact.ArtifactManager;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
@@ -38,22 +55,6 @@ import org.apache.sling.provisioning.model.io.ModelWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonReader;
-import javax.json.JsonString;
-import javax.json.JsonValue;
-
 /** Converter that converts the feature model to the provisioning model.
  */
 public class FeatureToProvisioning {
@@ -205,7 +206,7 @@ public class FeatureToProvisioning {
 
         // extensions: content packages and repoinit
         for(final Extension ext : extensions) {
-            if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
+            if ( SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
                 for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
                     String[] runmodes = null;
                     final ArtifactId id = cp.getId();
@@ -220,7 +221,7 @@ public class FeatureToProvisioning {
                     f.getOrCreateRunMode(runmodes).getOrCreateArtifactGroup(20).add(newCP);
                 }
 
-            } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
+            } else if ( SlingConstants.EXTENSION_NAME_REPOINIT.equals(ext.getName()) ) {
                 final Section section = new Section("repoinit");
                 if (ext.getType() == ExtensionType.TEXT) {
                     section.setContents(ext.getText());
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 1f8ce87..1be7c02 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
@@ -16,6 +16,21 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
+import java.io.File;
+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;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
@@ -25,6 +40,7 @@ import org.apache.sling.feature.ExtensionType;
 import org.apache.sling.feature.Extensions;
 import org.apache.sling.feature.KeyValueMap;
 import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.feature.support.artifact.ArtifactHandler;
 import org.apache.sling.feature.support.artifact.ArtifactManager;
 import org.apache.sling.feature.support.artifact.ArtifactManagerConfig;
@@ -48,21 +64,6 @@ import org.apache.sling.provisioning.model.io.ModelReader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-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;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
 /** Converter that converts the provisioning model to the feature model.
  */
 public class ProvisioningToFeature {
@@ -335,7 +336,7 @@ public class ProvisioningToFeature {
             variables.put(FeatureToProvisioning.PROVISIONING_MODEL_NAME_VARIABLE, feature.getName());
         }
 
-        Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
+        Extension cpExtension = extensions.getByName(SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES);
         for(final RunMode runMode : feature.getRunModes() ) {
             for(final ArtifactGroup group : runMode.getArtifactGroups()) {
                 for(final Artifact artifact : group) {
@@ -348,7 +349,7 @@ public class ProvisioningToFeature {
 
                     if ( newArtifact.getId().getType().equals("zip") ) {
                         if ( cpExtension == null ) {
-                            cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
+                            cpExtension = new Extension(ExtensionType.ARTIFACTS, SlingConstants.EXTENSION_NAME_CONTENT_PACKAGES, true);
                             extensions.add(cpExtension);
                         }
                         cpExtension.getArtifacts().add(newArtifact);
@@ -411,7 +412,7 @@ public class ProvisioningToFeature {
                 }
             }
         }
-        Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
+        Extension repoExtension = extensions.getByName(SlingConstants.EXTENSION_NAME_REPOINIT);
         for(final Section sect : feature.getAdditionalSections("repoinit")) {
             String text = sect.getContents();
             if ( repoExtension == null ) {
@@ -419,7 +420,7 @@ public class ProvisioningToFeature {
 //                extensions.add(repoExtension);
 //                repoExtension.setJSON(text);
 
-                repoExtension = new Extension(ExtensionType.JSON, Extension.NAME_REPOINIT, true);
+                repoExtension = new Extension(ExtensionType.JSON, SlingConstants.EXTENSION_NAME_REPOINIT, true);
                 extensions.add(repoExtension);
                 text = text.replace('\t', ' ');
                 String[] lines = text.split("[\n]");

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 06/40: Update to parent pom 33

Posted by da...@apache.org.
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 75e24a8b966856ee8d786d08ca7e081a130aab4e
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Feb 26 13:24:32 2018 +0100

    Update to parent pom 33
---
 pom.xml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 93d619b..d5359d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>32</version>
+        <version>33</version>
         <relativePath />
     </parent>
 
@@ -79,6 +79,8 @@
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>osgi.core</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 16/40: Add roundtrip testing prov model -> feature -> prov model

Posted by da...@apache.org.
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 6fe1aff24f453dd390fe1d7014042c4f906b71a3
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Thu Mar 22 10:39:03 2018 +0000

    Add roundtrip testing prov model -> feature -> prov model
---
 .../modelconverter/impl/ModelConverterTest.java    | 28 ++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

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 8a03fa1..194d95c 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
@@ -81,7 +81,7 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testBoot() throws Exception {
+    public void testBootToProvModel() throws Exception {
         testConvertToProvisioningModel("/boot.json", "/boot.txt");
     }
 
@@ -91,7 +91,12 @@ public class ModelConverterTest {
     }
 
     @Test
-    public void testOak() throws Exception {
+    public void testBootRoundTrip() throws Exception {
+        testConvertFromProvModelRoundTrip("/boot.txt");
+    }
+
+    @Test
+    public void testOakProvModel() throws Exception {
         testConvertToProvisioningModel("/oak.json", "/oak.txt");
     }
 
@@ -100,6 +105,25 @@ public class ModelConverterTest {
         testConvertToFeature("/oak.txt", "/oak.json");
     }
 
+    @Test
+    public void testOakRoundTrip() throws Exception {
+        testConvertFromProvModelRoundTrip("/oak.txt");
+    }
+
+    public void testConvertFromProvModelRoundTrip(String orgProvModel) throws Exception {
+        File inFile = new File(getClass().getResource(orgProvModel).toURI());
+        File outJSONFile = new File(tempDir.toFile(), orgProvModel + ".json.generated");
+        File outProvFile = new File(tempDir.toFile(), orgProvModel + ".txt.generated");
+
+        ProvisioningToFeature.convert(inFile, outJSONFile.getAbsolutePath());
+        FeatureToProvisioning.convert(outJSONFile, outProvFile.getAbsolutePath(),
+                artifactManager);
+
+        Model expected = readProvisioningModel(inFile);
+        Model actual = readProvisioningModel(outProvFile);
+        assertModelsEqual(expected, actual);
+    }
+
     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");

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 11/40: Support variables in converting from features to provisioning model

Posted by da...@apache.org.
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 dac2347464ec6c47ed58b944a3dffb8697fa5764
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Mar 20 10:46:52 2018 +0000

    Support variables in converting from features to provisioning model
---
 pom.xml                                            |  18 +++-
 .../modelconverter/impl/FeatureToProvisioning.java |  24 +++--
 .../modelconverter/impl/ModelConverterTest.java    |  74 +++++++++++++--
 src/test/resources/boot.json                       |  92 +++++++++++++++----
 src/test/resources/boot.txt                        |  70 +++++++++-----
 src/test/resources/oak.json                        | 101 +++++++++++++++++++++
 src/test/resources/oak.txt                         |  91 +++++++++++++++++++
 7 files changed, 411 insertions(+), 59 deletions(-)

diff --git a/pom.xml b/pom.xml
index 8d19064..c77652f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,6 +112,12 @@
              <version>1.3.1</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+            <version>5.6.10</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.feature</artifactId>
             <version>0.0.1-SNAPSHOT</version>
@@ -156,9 +162,15 @@
         </dependency>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.framework</artifactId>
-            <version>5.6.10</version>
-            <!--  <scope>test</scope>  -->
+            <artifactId>org.apache.felix.converter</artifactId>
+            <version>0.1.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configurator</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 2325549..ed0bd38 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -27,6 +27,7 @@ import org.apache.sling.feature.process.FeatureResolver;
 import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
+import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
@@ -52,15 +53,18 @@ public class FeatureToProvisioning {
     private static final String PROVISIONING_MODEL_NAME_VARIABLE = "provisioning.model.name";
 
     public static void convert(File file, String output, ArtifactManager am) throws IOException {
-        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am);
+        org.apache.sling.feature.Feature feature = FeatureUtil.getFeature(file.getAbsolutePath(), am, SubstituteVariables.NONE);
 
-        String featureName = feature.getVariables().get(PROVISIONING_MODEL_NAME_VARIABLE);
-        if (featureName == null) {
+        Object featureNameVar = feature.getVariables().remove(PROVISIONING_MODEL_NAME_VARIABLE);
+        String featureName;
+        if (featureNameVar instanceof String) {
+            featureName = (String) featureNameVar;
+        } else {
             featureName = feature.getId().getArtifactId();
         }
 
         Feature newFeature = new Feature(featureName);
-        convert(newFeature, feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
+        convert(newFeature, feature.getVariables(), feature.getBundles(), feature.getConfigurations(), feature.getFrameworkProperties(), feature.getExtensions(), output);
     }
 
     public static void convert(List<File> files, String output, boolean createApp, ArtifactManager am) throws Exception {
@@ -95,11 +99,16 @@ public class FeatureToProvisioning {
         }
         final Feature feature = new Feature(featureName);
 
-        convert(feature, app.getBundles(), app.getConfigurations(), app.getFrameworkProperties(), app.getExtensions(), outputFile);
+        convert(feature, app.getVariables(), app.getBundles(), app.getConfigurations(), app.getFrameworkProperties(), app.getExtensions(), outputFile);
     }
 
-    private static void convert(Feature f, Bundles bundles, Configurations configurations, KeyValueMap frameworkProps,
+    private static void convert(Feature f, KeyValueMap variables, Bundles bundles, Configurations configurations, KeyValueMap frameworkProps,
             Extensions extensions, String outputFile) {
+        org.apache.sling.provisioning.model.KeyValueMap<String> vars = f.getVariables();
+        for (Map.Entry<String, String> entry : variables) {
+            vars.put(entry.getKey(), entry.getValue());
+        }
+
         Map<org.apache.sling.feature.Configuration, org.apache.sling.feature.Artifact> configBundleMap = new HashMap<>();
 
         // bundles
@@ -153,6 +162,9 @@ public class FeatureToProvisioning {
                 c.getProperties().put(key, cfg.getProperties().get(key));
             }
 
+            // Remove these if they got in
+            c.getProperties().remove(org.apache.sling.feature.Configuration.PROP_ARTIFACT);
+
             // Check if the configuration has an associated runmode via the bundle that it belongs to
             org.apache.sling.feature.Artifact bundle = configBundleMap.get(cfg);
             String[] runModes;
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 bba43c5..46dc48b 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
@@ -24,6 +24,7 @@ import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;
 import org.apache.sling.provisioning.model.KeyValueMap;
 import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelConstants;
 import org.apache.sling.provisioning.model.RunMode;
 import org.apache.sling.provisioning.model.Section;
 import org.junit.After;
@@ -31,17 +32,23 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class ModelConverterTest {
@@ -66,13 +73,22 @@ public class ModelConverterTest {
 
     @Test
     public void testBoot() throws Exception {
-        File inFile = new File(getClass().getResource("/boot.json").toURI());
-        File outFile = new File(tempDir.toFile(), "/boot.generated.txt");
+        testConvertToProvisioningModel("/boot.json", "/boot.txt");
+    }
+
+    @Test
+    public void testOak() throws Exception {
+        testConvertToProvisioningModel("/oak.json", "/oak.txt");
+    }
+
+    private void testConvertToProvisioningModel(String originalJSON, String expectedProvModel) throws URISyntaxException, IOException {
+        File inFile = new File(getClass().getResource(originalJSON).toURI());
+        File outFile = new File(tempDir.toFile(), expectedProvModel + ".generated");
 
         FeatureToProvisioning.convert(inFile, outFile.getAbsolutePath(),
                 artifactManager);
 
-        File expectedFile = new File(getClass().getResource("/boot.txt").toURI());
+        File expectedFile = new File(getClass().getResource(expectedProvModel).toURI());
         Model expected = ProvisioningToFeature.readProvisioningModel(expectedFile);
         Model actual = ProvisioningToFeature.readProvisioningModel(outFile);
         assertModelsEqual(expected, actual);
@@ -117,6 +133,9 @@ public class ModelConverterTest {
             if (rm2.getNames() != null)
                 return false;
         } else {
+            if (rm2.getNames() == null)
+                return false;
+
             HashSet<String> names1 = new HashSet<>(Arrays.asList(rm1.getNames()));
             HashSet<String> names2 = new HashSet<>(Arrays.asList(rm2.getNames()));
 
@@ -150,9 +169,22 @@ public class ModelConverterTest {
 
         for (int i=0; i < configs1.size(); i++) {
             Configuration cfg1 = configs1.get(i);
-            Configuration cfg2 = configs2.get(i);
-            if (!cfg1.getProperties().equals(cfg2.getProperties()))
-                return false;
+
+            boolean found = false;
+            for (Configuration cfg2 : configs2) {
+                if (!cfg2.getPid().equals(cfg1.getPid())) {
+                    continue;
+                }
+                found = true;
+
+                Map<String, Object> m1 = cfgMap(cfg1.getProperties());
+                Map<String, Object> m2 = cfgMap(cfg2.getProperties());
+                if (!m1.equals(m2)) {
+                    return false;
+                }
+                break;
+            }
+            assertTrue("Configuration with PID " + cfg1.getPid() + " not found", found);
         }
 
         Map<String, String> m1 = kvToMap(rm1.getSettings());
@@ -161,6 +193,31 @@ public class ModelConverterTest {
         return m1.equals(m2);
     }
 
+    private Map<String, Object> cfgMap(Dictionary<String, Object> properties) {
+        Map<String, Object> m = new HashMap<>();
+        for (Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
+            String key = e.nextElement();
+            Object value = properties.get(key);
+            if (ModelConstants.CFG_UNPROCESSED.equals(key) && value instanceof String) {
+                String val = (String) value;
+                // Collapse line continuation characters
+                val = val.replaceAll("[\\\\]\\r?\\n", "");
+                for (String line : val.split("\\r?\\n")) {
+
+                    String[] kv = line.trim().split("=");
+                    if (kv.length >= 2) {
+                        String v = kv[1].trim().replaceAll("[" +Pattern.quote("[") + "]\\s+[\"]", "[\"");
+                        v = v.replaceAll("[\"][,]\\s*[]]","\"]");
+                        m.put(kv[0].trim(), v.trim());
+                    }
+                }
+            } else {
+                m.put(key, value);
+            }
+        }
+        return m;
+    }
+
     private Map<String, String> kvToMap(KeyValueMap<String> kvm) {
         Map<String, String> m = new HashMap<>();
 
@@ -191,10 +248,7 @@ public class ModelConverterTest {
     }
 
     private void assertKVMapEquals(KeyValueMap<String> expected, KeyValueMap<String> actual) {
-        assertEquals(expected.size(), actual.size());
-        for (Map.Entry<String, String> entry : expected) {
-            assertEquals(entry.getValue(), actual.get(entry.getKey()));
-        }
+        assertEquals(kvToMap(expected), kvToMap(actual));
     }
 
     private void assertSectionsEqual(List<Section> expected, List<Section> actual) {
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
index 2a17a40..8d0634a 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot.json
@@ -9,25 +9,79 @@
         "#": "The model name when transformed to the provisioning model",
         "provisioning.model.name": ":boot"
     },
-    "bundles": 
-        ["org.slf4j/slf4j-api/${slf4j.version}",
-        "org.apache.sling/org.apache.sling.commons.log/5.1.0",
-        "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
-        "org.slf4j/jcl-over-slf4j/${slf4j.version}",
-        "org.slf4j/log4j-over-slf4j/${slf4j.version}",
-        "org.apache.sling/org.apache.sling.settings/1.3.8",
-        "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
-        "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
-        "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
-        "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
-        "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
-        "org.apache.sling/org.apache.sling.installer.core/3.8.12",
-        "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
-        "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
-        "org.apache.felix/org.apache.felix.configadmin/1.8.16",
-        "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
-        "org.apache.aries/org.apache.aries.util/1.1.3",
-        "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0"],
+    "bundles": [
+        {
+            "id": "org.slf4j/slf4j-api/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.commons.log/5.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.commons.logservice/1.0.6",
+            "start-level": 20
+        },
+        {
+            "id": "org.slf4j/jcl-over-slf4j/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.slf4j/log4j-over-slf4j/${slf4j.version}",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.settings/1.3.8",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.xml/1.0.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.transaction/1.0.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.javax.activation/0.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.fragment.ws/1.0.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.launchpad.installer/1.2.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.core/3.8.12",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.provider.file/1.1.0",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.felix/org.apache.felix.configadmin/1.8.16",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.felix/org.apache.felix.eventadmin/1.4.10",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.aries/org.apache.aries.util/1.1.3",
+            "start-level": 20
+        },
+        {
+            "id": "org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0",
+            "start-level": 20
+        }],
         
     "framework-properties": {
         "# oak_tar and oak_mongo run modes are mutually exclusive":
diff --git a/src/test/resources/boot.txt b/src/test/resources/boot.txt
index b8d2e7f..7e22e39 100644
--- a/src/test/resources/boot.txt
+++ b/src/test/resources/boot.txt
@@ -1,26 +1,54 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+#
+# The :boot feature contains all things to bootstrap the installation.
+#
 [feature name=:boot]
 
+# additional entries for sling.properties
+# ---------------------------------------
+# oak_tar and oak_mongo run modes are mutually exclusive,
+# and cannot be changed after the first startup
 [settings]
-  localIndexDir=${sling.home}/repository/index
-  repository.home=${sling.home}/repository
-  sling.run.mode.install.options=oak_tar,oak_mongo
+    sling.run.mode.install.options=oak_tar,oak_mongo
+    repository.home=${sling.home}/repository
+    localIndexDir=${sling.home}/repository/index
+
+[variables]
+    slf4j.version=1.7.25
 
 [artifacts startLevel=20]
-  org.apache.aries/org.apache.aries.util/1.1.3
-  org.apache.felix/org.apache.felix.configadmin/1.8.16
-  org.apache.felix/org.apache.felix.eventadmin/1.4.10
-  org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0
-  org.apache.sling/org.apache.sling.commons.log/5.1.0
-  org.apache.sling/org.apache.sling.commons.logservice/1.0.6
-  org.apache.sling/org.apache.sling.fragment.transaction/1.0.0
-  org.apache.sling/org.apache.sling.fragment.ws/1.0.2
-  org.apache.sling/org.apache.sling.fragment.xml/1.0.2
-  org.apache.sling/org.apache.sling.installer.core/3.8.12
-  org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2
-  org.apache.sling/org.apache.sling.installer.provider.file/1.1.0
-  org.apache.sling/org.apache.sling.javax.activation/0.1.0
-  org.apache.sling/org.apache.sling.launchpad.installer/1.2.2
-  org.apache.sling/org.apache.sling.settings/1.3.8
-  org.slf4j/jcl-over-slf4j/1.7.25
-  org.slf4j/log4j-over-slf4j/1.7.25
-  org.slf4j/slf4j-api/1.7.25
+    org.slf4j/slf4j-api/${slf4j.version}
+    org.apache.sling/org.apache.sling.commons.log/5.1.0
+    org.apache.sling/org.apache.sling.commons.logservice/1.0.6
+    org.slf4j/jcl-over-slf4j/${slf4j.version}
+    org.slf4j/log4j-over-slf4j/${slf4j.version}
+    org.apache.sling/org.apache.sling.settings/1.3.8
+    org.apache.sling/org.apache.sling.fragment.xml/1.0.2
+    org.apache.sling/org.apache.sling.fragment.transaction/1.0.0
+    org.apache.sling/org.apache.sling.javax.activation/0.1.0
+    org.apache.sling/org.apache.sling.fragment.ws/1.0.2
+    org.apache.sling/org.apache.sling.launchpad.installer/1.2.2
+    org.apache.sling/org.apache.sling.installer.core/3.8.12
+    org.apache.sling/org.apache.sling.installer.provider.file/1.1.0
+    org.apache.sling/org.apache.sling.installer.factory.configuration/1.1.2
+    org.apache.felix/org.apache.felix.configadmin/1.8.16
+    org.apache.felix/org.apache.felix.eventadmin/1.4.10
+    org.apache.aries/org.apache.aries.util/1.1.3
+    # dependency with javax.inject - required for Sling Models (SLING-4710)
+    org.apache.geronimo.specs/geronimo-atinject_1.0_spec/1.0
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
new file mode 100644
index 0000000..ab50c29
--- /dev/null
+++ b/src/test/resources/oak.json
@@ -0,0 +1,101 @@
+{
+    "id": "org.apache.sling.simple/oak/1.0.0",
+    
+    "variables": {
+        "oak.version": "1.6.8"
+    },
+    
+    "bundles": [
+        {
+            "id": "org.apache.felix/org.apache.felix.jaas/1.0.2",
+            "start-level": 10
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-core/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-commons/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-lucene/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-blob/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-jcr/${oak.version}",
+            "start-level": 15
+        },
+        {
+            "id": "org.apache.jackrabbit/oak-segment-tar/${oak.version}",
+            "start-level": 15,
+            "run-modes": "oak_tar",
+            "configurations": {
+                "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
+                    "name": "Default NodeStore"
+                }
+            }
+        },
+        {
+            "id": "org.mongodb/mongo-java-driver/3.4.1",
+            "start-level": 15,
+            "run-modes": "oak_mongo",
+            "configurations": {
+                "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
+                    "mongouri": "mongodb://localhost:27017",
+                    "db": "sling"
+                }
+            }
+        },
+        {
+            "id": "com.h2database/h2-mvstore/1.4.196",
+            "start-level": 15,
+            "run-modes": "oak_mongo"
+        },
+        {
+            "id": "org.apache.sling/org.apache.sling.jcr.oak.server/1.1.4",
+            "start-level": 16
+        }
+    ],
+    "configurations": {
+        "org.apache.felix.jaas.Configuration.factory-GuestLoginModule": {
+            "jaas.controlFlag": "optional",
+            "jaas.classname": "org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule",
+            "jaas.ranking:Integer": 300
+        }, 
+        "org.apache.felix.jaas.Configuration.factory-LoginModuleImpl" : {
+            "jaas.controlFlag": "required",
+            "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl"
+        },
+        "org.apache.felix.jaas.Configuration.factory-TokenLoginModule" : {
+            "jaas.controlFlag": "sufficient",
+            "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule",
+            "jaas.ranking:Integer": 200
+        },
+        "org.apache.felix.jaas.ConfigurationSpi": {
+            "jaas.defaultRealmName": "jackrabbit.oak",
+            "jaas.configProviderName": "FelixJaasProvider"
+        },
+        "org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl" : {
+            "org.apache.jackrabbit.oak.authentication.configSpiName": "FelixJaasProvider"
+        },
+        "org.apache.jackrabbit.oak.security.user.UserConfigurationImpl": {
+            "groupsPath": "/home/groups",
+            "usersPath": "/home/users",
+            "defaultDepth": "1",
+            "importBehavior": "besteffort"
+        },
+        "org.apache.jackrabbit.oak.security.user.RandomAuthorizableNodeName": {
+            "length:Integer": 21
+        },
+        "org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider": {
+            "enabledActions": ["org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction"],
+            "userPrivilegeNames": ["jcr:all"],
+            "groupPrivilegeNames": ["jcr:read"]
+        }
+    }
+}
diff --git a/src/test/resources/oak.txt b/src/test/resources/oak.txt
new file mode 100644
index 0000000..5d2675c
--- /dev/null
+++ b/src/test/resources/oak.txt
@@ -0,0 +1,91 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+#
+# This is the OAK feature.
+[feature name=oak]
+
+[variables]
+    oak.version=1.6.8
+
+# The segment node store is used via a configuration
+[artifacts startLevel=10]
+    org.apache.felix/org.apache.felix.jaas/1.0.2
+
+[artifacts startLevel=15]
+    org.apache.jackrabbit/oak-core/${oak.version}
+    org.apache.jackrabbit/oak-commons/${oak.version}
+    org.apache.jackrabbit/oak-lucene/${oak.version}
+    org.apache.jackrabbit/oak-blob/${oak.version}
+    org.apache.jackrabbit/oak-jcr/${oak.version}
+
+[artifacts startLevel=15 runModes=oak_tar]
+    org.apache.jackrabbit/oak-segment-tar/${oak.version}
+
+[artifacts startLevel=15 runModes=oak_mongo]
+    org.mongodb/mongo-java-driver/3.4.1
+    com.h2database/h2-mvstore/1.4.196
+
+# start the Oak server instance after all components have been configured
+# and started to avoid restarting that component ( see SLING-4556 )
+[artifacts startLevel=16]
+    org.apache.sling/org.apache.sling.jcr.oak.server/1.1.4
+
+[configurations]
+  org.apache.felix.jaas.Configuration.factory-GuestLoginModule
+    jaas.controlFlag="optional"
+    jaas.classname="org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule"
+    jaas.ranking=I"300"
+
+  org.apache.felix.jaas.Configuration.factory-LoginModuleImpl
+    jaas.controlFlag="required"
+    jaas.classname="org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl"
+
+  org.apache.felix.jaas.Configuration.factory-TokenLoginModule
+    jaas.controlFlag="sufficient"
+    jaas.classname="org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule"
+    jaas.ranking=I"200"
+
+  org.apache.felix.jaas.ConfigurationSpi
+    jaas.defaultRealmName="jackrabbit.oak"
+    jaas.configProviderName="FelixJaasProvider"
+
+  org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl
+    org.apache.jackrabbit.oak.authentication.configSpiName="FelixJaasProvider"
+
+  org.apache.jackrabbit.oak.security.user.UserConfigurationImpl
+    groupsPath="/home/groups"
+    usersPath="/home/users"
+    defaultDepth="1"
+    importBehavior="besteffort"
+
+  org.apache.jackrabbit.oak.security.user.RandomAuthorizableNodeName
+    length=I"21"
+
+  org.apache.jackrabbit.oak.spi.security.user.action.DefaultAuthorizableActionProvider
+    enabledActions=["org.apache.jackrabbit.oak.spi.security.user.action.AccessControlAction"]
+    userPrivilegeNames=["jcr:all"]
+    groupPrivilegeNames=["jcr:read"]
+
+[configurations runModes=oak_tar]
+  org.apache.jackrabbit.oak.segment.SegmentNodeStoreService
+    name="Default\ NodeStore"
+
+[configurations runModes=oak_mongo]
+  org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService
+    mongouri="mongodb://localhost:27017"
+    db="sling"

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 40/40: Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.

Posted by da...@apache.org.
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 deffad0ce615ffd26ca286eea631c3233374df82
Author: Karl Pauls <kp...@adobe.com>
AuthorDate: Thu Apr 26 12:00:25 2018 +0200

    Use felix utils ResourceBuilder and Parser instead of the ManifestParser and ManifestUtil. As with that the feature-support module is empty, remove it.
---
 pom.xml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index 8386c38..62547a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,12 +143,6 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.feature.support</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.provisioning.model</artifactId>
             <version>1.8.2</version>
             <scope>provided</scope>

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 36/40: Remove WriteOption from Feature JSON Writer.

Posted by da...@apache.org.
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 0cc518fce797e9097c8c3c3bb08165d3f1af20f9
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Apr 18 20:42:07 2018 +0300

    Remove WriteOption from Feature JSON Writer.
---
 .../modelconverter/impl/FeatureToProvisioning.java | 30 ++++++++-----
 .../modelconverter/impl/ProvisioningToFeature.java | 33 +++++++--------
 .../modelconverter/impl/ModelConverterTest.java    | 49 +++++++++++-----------
 src/test/resources/launchpad.json                  |  2 +-
 src/test/resources/oak.json                        |  6 +--
 5 files changed, 65 insertions(+), 55 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index e6ce8a8..11041f8 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -21,6 +21,8 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
@@ -161,18 +163,12 @@ public class FeatureToProvisioning {
         for(final org.apache.sling.feature.Configuration cfg : configurations) {
             final Configuration c;
 
-            String[] runModes = null;
+            List<String> runModeList = new ArrayList<>();
             if ( cfg.isFactoryConfiguration() ) {
-                c = new Configuration(cfg.getName(), cfg.getFactoryPid());
+                String name = decodeRunModes(cfg.getName(), runModeList);
+                c = new Configuration(name, cfg.getFactoryPid());
             } else {
-                String pid = cfg.getPid();
-                pid = pid.replaceAll("[.][.](\\w+)", ":$1");
-                int rmIdx = pid.indexOf(".runmodes.");
-                if (rmIdx > 0) {
-                    String rm = pid.substring(rmIdx + ".runmodes.".length());
-                    pid = pid.substring(0, rmIdx);
-                    runModes = rm.split("[.]");
-                }
+                String pid = decodeRunModes(cfg.getPid(), runModeList);
                 c = new Configuration(pid, null);
             }
             final Enumeration<String> keys = cfg.getProperties().keys();
@@ -186,6 +182,9 @@ public class FeatureToProvisioning {
                 c.getProperties().put(key, val);
             }
 
+            String[] runModes = runModeList.toArray(new String[] {});
+            if (runModes.length == 0)
+                runModes = null;
             f.getOrCreateRunMode(runModes).getConfigurations().add(c);
         }
 
@@ -257,6 +256,17 @@ public class FeatureToProvisioning {
         }
     }
 
+    private static String decodeRunModes(String pid, List<String> runModes) {
+        pid = pid.replaceAll("[.][.](\\w+)", ":$1");
+        int rmIdx = pid.indexOf(".runmodes.");
+        if (rmIdx > 0) {
+            String rm = pid.substring(rmIdx + ".runmodes.".length());
+            pid = pid.substring(0, rmIdx);
+            runModes.addAll(Arrays.asList(rm.split("[.]")));
+        }
+        return pid;
+    }
+
     private static String[] getRunModes(final org.apache.sling.feature.Artifact bundle) {
         String runMode = bundle.getMetadata().get("run-modes");
         String[] runModes;
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 466e961..cb166a7 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
@@ -16,21 +16,6 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
-import java.io.File;
-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;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
 import org.apache.sling.feature.Application;
 import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Bundles;
@@ -44,7 +29,6 @@ import org.apache.sling.feature.io.ArtifactManager;
 import org.apache.sling.feature.io.ArtifactManagerConfig;
 import org.apache.sling.feature.io.json.ApplicationJSONWriter;
 import org.apache.sling.feature.io.json.FeatureJSONWriter;
-import org.apache.sling.feature.io.json.WriteOption;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.SlingConstants;
 import org.apache.sling.provisioning.model.Artifact;
@@ -64,6 +48,21 @@ import org.apache.sling.provisioning.model.io.ModelReader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+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;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 /** Converter that converts the provisioning model to the feature model.
  */
 public class ProvisioningToFeature {
@@ -516,7 +515,7 @@ public class ProvisioningToFeature {
         }
 
         try ( final FileWriter writer = new FileWriter(file)) {
-            FeatureJSONWriter.write(writer, f, WriteOption.OLD_STYLE_FACTORY_CONFIGS);
+            FeatureJSONWriter.write(writer, f);
         } 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 4f17c1b..98449cf 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
@@ -16,29 +16,6 @@
  */
 package org.apache.sling.feature.modelconverter.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.sling.feature.Bundles;
 import org.apache.sling.feature.Configurations;
 import org.apache.sling.feature.Extension;
@@ -66,6 +43,29 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 public class ModelConverterTest {
     private Path tempDir;
     private ArtifactManager artifactManager;
@@ -299,7 +299,8 @@ public class ModelConverterTest {
                         assertConfigProps(ex, ac, exBundles, acBundles);
                     }
                 } else {
-                    if (ex.getFactoryPid().equals(ac.getFactoryPid())) {
+                    if (ex.getFactoryPid().equals(ac.getFactoryPid()) &&
+                            ex.getName().equals(ac.getName())) {
                         found = true;
                         assertConfigProps(ex, ac, exBundles, acBundles);
                     }
diff --git a/src/test/resources/launchpad.json b/src/test/resources/launchpad.json
index 0c103ba..d9e7193 100644
--- a/src/test/resources/launchpad.json
+++ b/src/test/resources/launchpad.json
@@ -21,7 +21,7 @@
     "..bootstrap.runmodes...standalone":{
       "..bootstrap":"uninstall org.apache.felix.http.bridge\nuninstall org.apache.felix.http.api\n"
     },
-    "org.apache.testing.ConfigPid.factory-configuration.runmodes...standalone":{
+    "org.apache.testing.ConfigPid.factory~configuration.runmodes...standalone":{
       "key1":"val1"
     }
   }
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
index 0db7923..f054113 100644
--- a/src/test/resources/oak.json
+++ b/src/test/resources/oak.json
@@ -51,16 +51,16 @@
         }
     ],
     "configurations": {
-        "org.apache.felix.jaas.Configuration.factory-GuestLoginModule": {
+        "org.apache.felix.jaas.Configuration.factory~GuestLoginModule": {
             "jaas.controlFlag": "optional",
             "jaas.classname": "org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule",
             "jaas.ranking:Integer": 300
         }, 
-        "org.apache.felix.jaas.Configuration.factory-LoginModuleImpl" : {
+        "org.apache.felix.jaas.Configuration.factory~LoginModuleImpl" : {
             "jaas.controlFlag": "required",
             "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl"
         },
-        "org.apache.felix.jaas.Configuration.factory-TokenLoginModule" : {
+        "org.apache.felix.jaas.Configuration.factory~TokenLoginModule" : {
             "jaas.controlFlag": "sufficient",
             "jaas.classname": "org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule",
             "jaas.ranking:Integer": 200

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 26/40: Small tweak to how files converted from prov model to feature are named

Posted by da...@apache.org.
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 571927a4204c8c5aa0c8774ff92619a5adab0ca4
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Mon Apr 9 13:57:14 2018 +0100

    Small tweak to how files converted from prov model to feature are named
    
    When converting a provisioning model to a feature, include the name of
    the original provisioning model file and name of the original feature in
    the filename.
---
 .../sling/feature/modelconverter/impl/ProvisioningToFeature.java  | 8 ++++++++
 1 file changed, 8 insertions(+)

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 cf1a973..0db9c2b 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
@@ -72,6 +72,12 @@ public class ProvisioningToFeature {
         Model model = createModel(Collections.singletonList(file), null, true, false);
         final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
 
+        String bareFileName = file.getName();
+        int idx = bareFileName.lastIndexOf('.');
+        if (idx > 0) {
+            bareFileName = bareFileName.substring(0, idx);
+        }
+
         List<File> files = new ArrayList<>();
         for (org.apache.sling.feature.Feature f : features) {
             String id = f.getVariables().get("provisioning.model.name");
@@ -79,6 +85,8 @@ public class ProvisioningToFeature {
                 id = f.getId().getArtifactId();
             }
 
+            id = bareFileName + "_" + id;
+
             File outFile = new File(outDir, id + ".json");
             int counter = 0;
             while (outFile.exists()) {

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 27/40: Add the ability to set groupId and version for generated features

Posted by da...@apache.org.
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 496178b037e8dba952e012733ac66ef6153322c2
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Apr 10 11:31:00 2018 +0100

    Add the ability to set groupId and version for generated features
---
 .../modelconverter/impl/ProvisioningToFeature.java | 31 +++++++++++++++-------
 .../modelconverter/impl/ModelConverterTest.java    | 25 +++++++++++++++--
 src/test/resources/boot.json                       |  2 +-
 src/test/resources/{boot.json => boot_gav.json}    |  2 +-
 src/test/resources/launchpad.json                  |  2 +-
 src/test/resources/oak.json                        |  2 +-
 src/test/resources/repoinit.json                   |  2 +-
 7 files changed, 50 insertions(+), 16 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 0db9c2b..ce77d76 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
@@ -68,9 +68,9 @@ import java.util.Set;
 public class ProvisioningToFeature {
     private static Logger LOGGER = LoggerFactory.getLogger(ProvisioningToFeature.class);
 
-    public static List<File> convert(File file, File outDir) {
+    public static List<File> convert(File file, File outDir, Map<String, Object> options) {
         Model model = createModel(Collections.singletonList(file), null, true, false);
-        final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
+        final List<org.apache.sling.feature.Feature> features = buildFeatures(model, options);
 
         String bareFileName = file.getName();
         int idx = bareFileName.lastIndexOf('.');
@@ -108,7 +108,7 @@ public class ProvisioningToFeature {
 
             writeApplication(app, outputFile);
         } else {
-            final List<org.apache.sling.feature.Feature> features = buildFeatures(model);
+            final List<org.apache.sling.feature.Feature> features = buildFeatures(model, Collections.emptyMap());
             int index = 1;
             for(final org.apache.sling.feature.Feature feature : features) {
                 writeFeature(feature, outputFile, features.size() > 1 ? index : 0);
@@ -448,20 +448,24 @@ public class ProvisioningToFeature {
     }
 
 
-    private static List<org.apache.sling.feature.Feature> buildFeatures(final Model model) {
+    private static List<org.apache.sling.feature.Feature> buildFeatures(Model model, Map<String, Object> options) {
         final List<org.apache.sling.feature.Feature> features = new ArrayList<>();
 
+        String groupId = getOption(options, "groupId", "generated");
+        String version = getOption(options, "version", "1.0.0");
+
         for(final Feature feature : model.getFeatures() ) {
             final String idString;
-            // use a default name if not present or not usable as a Maven artifactId ( starts with ':')
-            if ( feature.getName() != null && !feature.isSpecial() ) {
+            String name = feature.getName();
+            if ( name != null ) {
+                name = name.replaceAll("[:]", "");
                 if ( feature.getVersion() != null ) {
-                    idString = "generated/" + feature.getName() + "/" + feature.getVersion();
+                    idString = groupId + "/" + name + "/" + feature.getVersion();
                 } else {
-                    idString = "generated/" + feature.getName() + "/1.0.0";
+                    idString = groupId + "/" + name + "/" + version;
                 }
             } else {
-                idString = "generated/feature/1.0.0";
+                idString = groupId + "/feature/" + version;
             }
             final org.apache.sling.feature.Feature f = new org.apache.sling.feature.Feature(ArtifactId.parse(idString));
             features.add(f);
@@ -472,6 +476,15 @@ public class ProvisioningToFeature {
         return features;
     }
 
+    @SuppressWarnings("unchecked")
+    private static <T> T getOption(Map<String, Object> options, String name, T defaultValue) {
+        if (options.containsKey(name)) {
+            return (T) options.get(name);
+        } else {
+            return defaultValue;
+        }
+    }
+
     private static void writeApplication(final Application app, final String out) {
         LOGGER.info("Writing application...");
         final File file = new File(out);
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 df0eacf..1b5f4aa 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
@@ -160,11 +160,31 @@ public class ModelConverterTest {
         }
     }
 
+    @Test
+    public void testModelGAV() throws Exception {
+        String originalProvModel = "/boot.txt";
+        String expectedJSON = "/boot_gav.json";
+
+        File inFile = new File(getClass().getResource(originalProvModel).toURI());
+
+        Map<String, Object> options = new HashMap<>();
+        options.put("groupId", "testing123");
+        options.put("version", "4.5.6");
+        List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), options);
+        assertEquals("The testing code expects a single output file here", 1, files.size());
+        File outFile = files.get(0);
+
+        String expectedFile = new File(getClass().getResource(expectedJSON).toURI()).getAbsolutePath();
+        org.apache.sling.feature.Feature expected = FeatureUtil.getFeature(expectedFile, artifactManager, SubstituteVariables.NONE);
+        org.apache.sling.feature.Feature actual = FeatureUtil.getFeature(outFile.getAbsolutePath(), artifactManager, SubstituteVariables.NONE);
+        assertFeaturesEqual(expected, actual);
+    }
+
     public void testConvertFromProvModelRoundTrip(File orgProvModel) throws Exception {
         System.out.println("*** Roundtrip converting: " + orgProvModel.getName());
         List<File> allGenerateProvisioningModelFiles = new ArrayList<>();
 
-        List<File> generated = ProvisioningToFeature.convert(orgProvModel, tempDir.toFile());
+        List<File> generated = ProvisioningToFeature.convert(orgProvModel, tempDir.toFile(), Collections.emptyMap());
 
         for (File f : generated) {
             String baseName = f.getName().substring(0, f.getName().length() - ".json".length());
@@ -181,7 +201,7 @@ public class ModelConverterTest {
     public void testConvertToFeature(String originalProvModel, String expectedJSON) throws Exception {
         File inFile = new File(getClass().getResource(originalProvModel).toURI());
 
-        List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile());
+        List<File> files = ProvisioningToFeature.convert(inFile, tempDir.toFile(), Collections.emptyMap());
         assertEquals("The testing code expects a single output file here", 1, files.size());
         File outFile = files.get(0);
 
@@ -234,6 +254,7 @@ public class ModelConverterTest {
     }
 
     private void assertFeaturesEqual(org.apache.sling.feature.Feature expected, org.apache.sling.feature.Feature actual) {
+        assertEquals(expected.getId(), actual.getId());
         assertEquals(expected.getTitle(), actual.getTitle());
         assertEquals(expected.getDescription(), actual.getDescription());
         assertEquals(expected.getVendor(), actual.getVendor());
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
index e535f7b..313fec9 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot.json
@@ -2,7 +2,7 @@
     "#": "The model version defaults to 1 if not specified",
     "model-version": "1",
     
-    "id": "org.apache.sling.simple/boot/1.0.0",
+    "id": "generated/boot/1.0.0",
     "variables": {
         "slf4j.version": "1.7.25",
         
diff --git a/src/test/resources/boot.json b/src/test/resources/boot_gav.json
similarity index 98%
copy from src/test/resources/boot.json
copy to src/test/resources/boot_gav.json
index e535f7b..1d997f8 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot_gav.json
@@ -2,7 +2,7 @@
     "#": "The model version defaults to 1 if not specified",
     "model-version": "1",
     
-    "id": "org.apache.sling.simple/boot/1.0.0",
+    "id": "testing123/boot/4.5.6",
     "variables": {
         "slf4j.version": "1.7.25",
         
diff --git a/src/test/resources/launchpad.json b/src/test/resources/launchpad.json
index 2fa94b3..0c103ba 100644
--- a/src/test/resources/launchpad.json
+++ b/src/test/resources/launchpad.json
@@ -1,5 +1,5 @@
 {
-  "id":"generated:feature:1.0.0",
+  "id":"generated:launchpad:1.0.0",
   "variables":{
     "provisioning.model.name":":launchpad"
   },
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
index 03f64c3..0db7923 100644
--- a/src/test/resources/oak.json
+++ b/src/test/resources/oak.json
@@ -1,5 +1,5 @@
 {
-    "id": "org.apache.sling.simple/oak/1.0.0",
+    "id": "generated/oak/1.0.0",
     
     "variables": {
         "oak.version": "1.6.8"
diff --git a/src/test/resources/repoinit.json b/src/test/resources/repoinit.json
index 1fe41f3..06d179e 100644
--- a/src/test/resources/repoinit.json
+++ b/src/test/resources/repoinit.json
@@ -1,7 +1,7 @@
 {
     "#": "this is a comment",
 
-    "id": "org.apache.sling.simple/repoinit/1.0.0",
+    "id": "generated/repoinit/1.0.0",
     "bundles": [
         {
             "id": "org.apache.sling/org.apache.sling.repoinit.parser/1.2.0",

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 29/40: Move resolving to separate package

Posted by da...@apache.org.
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 60e7e0609b282ba49679199b54550f69504a7f92
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Apr 17 09:25:12 2018 +0200

    Move resolving to separate package
---
 .../apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 4c7089e..cf5a3a5 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -28,7 +28,7 @@ import org.apache.sling.feature.support.ArtifactManager;
 import org.apache.sling.feature.support.FeatureUtil;
 import org.apache.sling.feature.support.json.ApplicationJSONReader;
 import org.apache.sling.feature.support.json.FeatureJSONReader.SubstituteVariables;
-import org.apache.sling.feature.support.process.FeatureResolver;
+import org.apache.sling.feature.support.resolver.FeatureResolver;
 import org.apache.sling.provisioning.model.Artifact;
 import org.apache.sling.provisioning.model.Configuration;
 import org.apache.sling.provisioning.model.Feature;

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.

[sling-org-apache-sling-feature-modelconverter] 21/40: Improve handling of runmodes in provisioning model-feature conversions

Posted by da...@apache.org.
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 856cd9b207111496acf68e218f5821864d3563ca
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Apr 3 14:43:49 2018 +0100

    Improve handling of runmodes in provisioning model-feature conversions
    
    Also handle cases where ':' is used in configuration keys, something
    that the OSGi configurator doesn't allow.
---
 .../modelconverter/impl/FeatureToProvisioning.java | 46 +++++++---
 .../modelconverter/impl/ProvisioningToFeature.java | 97 ++++++++++++++--------
 .../modelconverter/impl/ModelConverterTest.java    | 62 ++++++++++----
 src/test/resources/boot.json                       |  5 ++
 src/test/resources/boot.txt                        |  6 ++
 src/test/resources/launchpad.json                  | 28 +++++++
 src/test/resources/launchpad.txt                   | 20 +++++
 src/test/resources/oak.json                        |  6 +-
 src/test/resources/simple.json                     |  9 ++
 src/test/resources/simple.txt                      | 24 ++++++
 10 files changed, 239 insertions(+), 64 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
index 3c904fe..dd6d830 100644
--- a/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
+++ b/src/main/java/org/apache/sling/feature/modelconverter/impl/FeatureToProvisioning.java
@@ -151,40 +151,64 @@ public class FeatureToProvisioning {
         // configurations
         for(final org.apache.sling.feature.Configuration cfg : configurations) {
             final Configuration c;
+
+            String[] runModes = null;
             if ( cfg.isFactoryConfiguration() ) {
                 c = new Configuration(cfg.getName(), cfg.getFactoryPid());
             } else {
-                c = new Configuration(cfg.getPid(), null);
+                String pid = cfg.getPid();
+                pid = pid.replaceAll("[.][.](\\S+)", ":$1");
+                int rmIdx = pid.indexOf(".runmodes.");
+                if (rmIdx > 0) {
+                    String rm = pid.substring(rmIdx + ".runmodes.".length());
+                    pid = pid.substring(0, rmIdx);
+                    runModes = rm.split("[.]");
+                }
+                c = new Configuration(pid, null);
             }
             final Enumeration<String> keys = cfg.getProperties().keys();
             while ( keys.hasMoreElements() ) {
-                final String key = keys.nextElement();
-                c.getProperties().put(key, cfg.getProperties().get(key));
-            }
+                String key = keys.nextElement();
+                Object val = cfg.getProperties().get(key);
 
-            String[] runModes = null;
-            Object rm = c.getProperties().remove(".runmodes");
-            if (rm instanceof String) {
-                runModes = ((String) rm).split(",");
+                if (key.startsWith("..")) {
+                    key = ":" + key.substring(2);
+                }
+                c.getProperties().put(key, val);
             }
+
             f.getOrCreateRunMode(runModes).getConfigurations().add(c);
         }
 
         // framework properties
         for(final Map.Entry<String, String> prop : frameworkProps) {
-            f.getOrCreateRunMode(null).getSettings().put(prop.getKey(), prop.getValue());
+            String key = prop.getKey();
+            if (key.startsWith(".runmodes:")) {
+                int lastIdx = key.lastIndexOf(':');
+                String rm = key.substring(".runmodes:".length(), lastIdx);
+                String[] runmodes = rm.split(",");
+                key = key.substring(lastIdx + 1);
+                f.getOrCreateRunMode(runmodes).getSettings().put(key, prop.getValue());
+            } else {
+                f.getOrCreateRunMode(null).getSettings().put(key, prop.getValue());
+            }
         }
 
         // extensions: content packages and repoinit
         for(final Extension ext : extensions) {
             if ( Extension.NAME_CONTENT_PACKAGES.equals(ext.getName()) ) {
                 for(final org.apache.sling.feature.Artifact cp : ext.getArtifacts() ) {
+                    String[] runmodes = null;
                     final ArtifactId id = cp.getId();
                     final Artifact newCP = new Artifact(id.getGroupId(), id.getArtifactId(), id.getVersion(), id.getClassifier(), id.getType());
                     for(final Map.Entry<String, String> prop : cp.getMetadata()) {
-                        newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                        if (prop.getKey().equals("runmodes")) {
+                            runmodes = prop.getValue().split(",");
+                        } else {
+                            newCP.getMetadata().put(prop.getKey(), prop.getValue());
+                        }
                     }
-                    f.getOrCreateRunMode(null).getOrCreateArtifactGroup(0).add(newCP);
+                    f.getOrCreateRunMode(runmodes).getOrCreateArtifactGroup(20).add(newCP);
                 }
 
             } else if ( Extension.NAME_REPOINIT.equals(ext.getName()) ) {
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 62a4f00..6af4aa3 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
@@ -148,7 +148,7 @@ public class ProvisioningToFeature {
             modes = calculateRunModes(effectiveModel, runModes);
         }
 
-        removeInactiveFeaturesAndRunModes(effectiveModel, modes);
+        // removeInactiveFeaturesAndRunModes(effectiveModel, modes);
 
         return effectiveModel;
     }
@@ -237,6 +237,7 @@ public class ProvisioningToFeature {
         }
     }
 
+    // TODO is this needed for something?
     private static void removeInactiveFeaturesAndRunModes(final Model m,
             final Set<String> activeRunModes) {
         final String[] requiredFeatures = new String[] {ModelConstants.FEATURE_LAUNCHPAD, ModelConstants.FEATURE_BOOT};
@@ -394,35 +395,33 @@ public class ProvisioningToFeature {
 
         Extension cpExtension = extensions.getByName(Extension.NAME_CONTENT_PACKAGES);
         for(final RunMode runMode : feature.getRunModes() ) {
-            if ( !ModelConstants.FEATURE_LAUNCHPAD.equals(feature.getName()) ) {
-                for(final ArtifactGroup group : runMode.getArtifactGroups()) {
-                    for(final Artifact artifact : group) {
-                        final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
-                        final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
+            for(final ArtifactGroup group : runMode.getArtifactGroups()) {
+                for(final Artifact artifact : group) {
+                    final ArtifactId id = ArtifactId.fromMvnUrl(artifact.toMvnUrl());
+                    final org.apache.sling.feature.Artifact newArtifact = new org.apache.sling.feature.Artifact(id);
 
-                        for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
-                            newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
-                        }
+                    for(final Map.Entry<String, String> entry : artifact.getMetadata().entrySet()) {
+                        newArtifact.getMetadata().put(entry.getKey(), entry.getValue());
+                    }
 
-                        if ( newArtifact.getId().getType().equals("zip") ) {
-                            if ( cpExtension == null ) {
-                                cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
-                                extensions.add(cpExtension);
-                            }
-                            cpExtension.getArtifacts().add(newArtifact);
-                        } else {
-                            int startLevel = group.getStartLevel();
-                            if ( startLevel == 0) {
-                                if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
-                                    startLevel = 1;
-                                } else if ( startLevel == 0 ) {
-                                    startLevel = 20;
-                                }
+                    if ( newArtifact.getId().getType().equals("zip") ) {
+                        if ( cpExtension == null ) {
+                            cpExtension = new Extension(ExtensionType.ARTIFACTS, Extension.NAME_CONTENT_PACKAGES, true);
+                            extensions.add(cpExtension);
+                        }
+                        cpExtension.getArtifacts().add(newArtifact);
+                    } else {
+                        int startLevel = group.getStartLevel();
+                        if ( startLevel == 0) {
+                            if ( ModelConstants.FEATURE_BOOT.equals(feature.getName()) ) {
+                                startLevel = 1;
+                            } else if ( startLevel == 0 ) {
+                                startLevel = 20;
                             }
-                            newArtifact.getMetadata().put("start-level", String.valueOf(startLevel));
-
-                            bundles.add(newArtifact);
                         }
+                        newArtifact.getMetadata().put("start-level", String.valueOf(startLevel));
+
+                        bundles.add(newArtifact);
                     }
                 }
             }
@@ -430,26 +429,54 @@ public class ProvisioningToFeature {
             for(final Configuration cfg : runMode.getConfigurations()) {
                 final org.apache.sling.feature.Configuration newCfg;
                 if ( cfg.getFactoryPid() != null ) {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), cfg.getPid());
+                    String pid = cfg.getPid();
+                    if (pid.startsWith(":")) {
+                        // The configurator doesn't accept colons ':' in it's keys, so replace these
+                        pid = ".." + pid.substring(1);
+                    }
+
+                    String[] runModeNames = runMode.getNames();
+                    if (runModeNames != null) {
+                        pid = pid + ".runmodes." + String.join(".", runModeNames);
+                    }
+
+                    newCfg = new org.apache.sling.feature.Configuration(cfg.getFactoryPid(), pid);
                 } else {
-                    newCfg = new org.apache.sling.feature.Configuration(cfg.getPid());
+                    String pid = cfg.getPid();
+                    if (pid.startsWith(":")) {
+                        // The configurator doesn't accept colons ':' in it's keys, so replace these
+                        pid = ".." + pid.substring(1);
+                    }
+
+                    String[] runModeNames = runMode.getNames();
+                    if (runModeNames != null) {
+                        pid = pid + ".runmodes." + String.join(".", runModeNames);
+                    }
+
+                    newCfg = new org.apache.sling.feature.Configuration(pid);
                 }
                 final Enumeration<String> keys = cfg.getProperties().keys();
                 while ( keys.hasMoreElements() ) {
-                    final String key = keys.nextElement();
-                    newCfg.getProperties().put(key, cfg.getProperties().get(key));
-                }
+                    String key = keys.nextElement();
+                    Object value = cfg.getProperties().get(key);
 
-                String[] runModeNames = runMode.getNames();
-                if (runModeNames != null) {
-                    newCfg.getProperties().put(".runmodes", String.join(",", runModeNames));
+                    if (key.startsWith(":")) {
+                        key = ".." + key.substring(1);
+                    }
+                    newCfg.getProperties().put(key, value);
                 }
 
                 configurations.add(newCfg);
             }
 
             for(final Map.Entry<String, String> prop : runMode.getSettings()) {
-                properties.put(prop.getKey(), prop.getValue());
+                String[] runModeNames = runMode.getNames();
+                if (runModeNames == null) {
+                    properties.put(prop.getKey(), prop.getValue());
+                } else {
+                    properties.put(".runmodes:" + String.join(",", runModeNames) + ":" +
+                            prop.getKey(), prop.getValue());
+                }
             }
         }
         Extension repoExtension = extensions.getByName(Extension.NAME_REPOINIT);
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 98f2dbc..249d9dc 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
@@ -115,6 +115,26 @@ public class ModelConverterTest {
     }
 
     @Test
+    public void testLaunchpadToProvModel() throws Exception {
+        testConvertToProvisioningModel("/launchpad.json", "/launchpad.txt");
+    }
+
+    @Test
+    public void testLaunchpadToFeature() throws Exception {
+        testConvertToFeature("/launchpad.txt", "/launchpad.json");
+    }
+
+    @Test
+    public void testSimpleToProvModel() throws Exception {
+        testConvertToProvisioningModel("/simple.json", "/simple.txt");
+    }
+
+    @Test
+    public void testSimpleToFeature() throws Exception {
+        testConvertToFeature("/simple.txt", "/simple.json");
+    }
+
+    @Test
     public void testProvModelRoundtripFolder() throws Exception {
         String dir = System.getProperty("test.prov.files.dir");
         File filesDir;
@@ -365,27 +385,31 @@ public class ModelConverterTest {
 
             boolean found = false;
             for (Configuration cfg2 : configs2) {
-                if (!cfg2.getPid().equals(cfg1.getPid())) {
+                if (cfg1.getFactoryPid() == null) {
+                    if (cfg2.getFactoryPid() != null) {
+                        continue;
+                    }
+                } else if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) {
                     continue;
                 }
-                found = true;
 
-                if (cfg1.getFactoryPid() == null) {
-                    if (cfg2.getFactoryPid() != null)
-                        return false;
-                } else {
-                    if (!cfg1.getFactoryPid().equals(cfg2.getFactoryPid())) {
-                        return false;
-                    }
+                if (!cfg1.getPid().equals(cfg2.getPid())) {
+                    continue;
                 }
 
+                // Factory and ordinary PIDs are equal, so check the content
+                found = true;
+
                 if (!configPropsEqual(cfg1.getProperties(), cfg2.getProperties())) {
                     return false;
                 }
 
                 break;
             }
-            assertTrue("Configuration with PID " + cfg1.getPid() + " not found", found);
+            if (!found) {
+                // Configuration with this PID not found
+                return false;
+            }
         }
 
         Map<String, String> m1 = kvToMap(rm1.getSettings());
@@ -426,13 +450,23 @@ public class ModelConverterTest {
         List<Artifact> al2 = new ArrayList<>();
         g2.iterator().forEachRemaining(al2::add);
 
-        for (int i=0; i < al1.size(); i++) {
+        for (int i=0; i<al1.size(); i++) {
             Artifact a1 = al1.get(i);
-            Artifact a2 = al2.get(i);
-            if (a1.compareTo(a2) != 0)
+            boolean found = false;
+            for (Iterator<Artifact> it = al2.iterator(); it.hasNext(); ) {
+                Artifact a2 = it.next();
+                if (a1.compareTo(a2) == 0) {
+                    found = true;
+                    it.remove();
+                }
+            }
+            if (!found) {
                 return false;
+            }
         }
-        return true;
+
+        // Should have found all artifacts
+        return (al2.size() == 0);
     }
 
     private int effectiveStartLevel(String featureName, int startLevel) {
diff --git a/src/test/resources/boot.json b/src/test/resources/boot.json
index c267b67..4cc7d40 100644
--- a/src/test/resources/boot.json
+++ b/src/test/resources/boot.json
@@ -90,6 +90,11 @@
         "sling.run.mode.install.options": "oak_tar,oak_mongo",
         "repository.home": "${sling.home}/repository",
         "localIndexDir": "${sling.home}/repository/index",
+        
+        "# we need runmodes here too...": "",
+        ".runmodes:a:something": "else",
+        ".runmodes::b:special": "true", 
+        
         "#": "${sling.home} needs to be provided at launch time"
     }
 }
diff --git a/src/test/resources/boot.txt b/src/test/resources/boot.txt
index df5a947..d8a6fec 100644
--- a/src/test/resources/boot.txt
+++ b/src/test/resources/boot.txt
@@ -28,6 +28,12 @@
     sling.run.mode.install.options=oak_tar,oak_mongo
     repository.home=${sling.home}/repository
     localIndexDir=${sling.home}/repository/index
+    
+[settings runModes=:b]
+    special=true    
+    
+[settings runModes=a]
+    something=else    
 
 [variables]
     slf4j.version=1.7.25
diff --git a/src/test/resources/launchpad.json b/src/test/resources/launchpad.json
new file mode 100644
index 0000000..0dd9318
--- /dev/null
+++ b/src/test/resources/launchpad.json
@@ -0,0 +1,28 @@
+{
+  "id":"generated:feature:1.0.0",
+  "variables":{
+    "provisioning.model.name":":launchpad"
+  },
+  "bundles":[
+    {
+      "id":"org.apache.sling:org.apache.sling.launchpad.base:5.6.10-2.6.26",
+      "start-level":"20"
+    },
+    {
+      "id":"org.apache.sling:org.apache.sling.commons.osgi:2.4.0",
+      "run-modes":":something",
+      "start-level":"20"
+    }
+  ],
+  "configurations":{
+    "..bootstrap":{
+      "..bootstrap":"uninstall com.google.guava 15.0.0\n"
+    },
+    "..bootstrap.runmodes.:standalone":{
+      "..bootstrap":"uninstall org.apache.felix.http.bridge\nuninstall org.apache.felix.http.api\n"
+    },
+    "org.apache.testing.ConfigPid.factory-configuration.runmodes.:standalone":{
+      "key1":"val1"
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/launchpad.txt b/src/test/resources/launchpad.txt
new file mode 100644
index 0000000..188bf76
--- /dev/null
+++ b/src/test/resources/launchpad.txt
@@ -0,0 +1,20 @@
+[feature name=:launchpad]
+
+[artifacts]
+  org.apache.sling/org.apache.sling.launchpad.base/5.6.10-2.6.26
+
+[configurations]
+  :bootstrap
+    uninstall com.google.guava 15.0.0
+
+[artifacts runModes=:something]
+
+  org.apache.sling/org.apache.sling.commons.osgi/2.4.0
+
+[configurations runModes=:standalone]
+  :bootstrap
+    uninstall org.apache.felix.http.bridge
+    uninstall org.apache.felix.http.api
+
+  org.apache.testing.ConfigPid.factory-configuration
+    key1="val1"
diff --git a/src/test/resources/oak.json b/src/test/resources/oak.json
index d94aa8d..03f64c3 100644
--- a/src/test/resources/oak.json
+++ b/src/test/resources/oak.json
@@ -86,12 +86,10 @@
             "userPrivilegeNames": ["jcr:all"],
             "groupPrivilegeNames": ["jcr:read"]
         },
-        "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService": {
-            ".runmodes": "oak_tar", 
+        "org.apache.jackrabbit.oak.segment.SegmentNodeStoreService.runmodes.oak_tar": {
             "name": "Default NodeStore"
         },
-        "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService": {
-            ".runmodes": "oak_mongo", 
+        "org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.runmodes.oak_mongo": {
             "mongouri": "mongodb://localhost:27017",
             "db": "sling"
         }
diff --git a/src/test/resources/simple.json b/src/test/resources/simple.json
new file mode 100644
index 0000000..4cc130a
--- /dev/null
+++ b/src/test/resources/simple.json
@@ -0,0 +1,9 @@
+{
+  "id":"generated:simple:1.0.0",
+  "bundles":[
+    {
+      "id":"org.apache.aries:org.apache.aries.util:1.1.3",
+      "start-level":"20"
+    }
+  ]
+}
diff --git a/src/test/resources/simple.txt b/src/test/resources/simple.txt
new file mode 100644
index 0000000..53e40a2
--- /dev/null
+++ b/src/test/resources/simple.txt
@@ -0,0 +1,24 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+#
+# The :boot feature contains all things to bootstrap the installation.
+#
+[feature name=simple]
+
+[artifacts]
+    org.apache.aries/org.apache.aries.util/1.1.3

-- 
To stop receiving notification emails like this one, please contact
davidb@apache.org.