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

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


The following commit(s) were added to refs/heads/master by this push:
     new 92bc78f  SLING-8107 : Correct setting the feature origin
92bc78f is described below

commit 92bc78f3bfd414ceae6cba2e89d513e24b6853eb
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Wed Nov 14 08:25:32 2018 +0100

    SLING-8107 : Correct setting the feature origin
---
 .../java/org/apache/sling/feature/Artifact.java    | 14 +++++
 .../apache/sling/feature/builder/BuilderUtil.java  | 73 +++++++++++++++-------
 .../sling/feature/builder/FeatureBuilder.java      | 72 ++++++++++++---------
 .../sling/feature/builder/BuilderUtilTest.java     | 10 +--
 4 files changed, 110 insertions(+), 59 deletions(-)

diff --git a/src/main/java/org/apache/sling/feature/Artifact.java 
b/src/main/java/org/apache/sling/feature/Artifact.java
index c4767c0..504f7fe 100644
--- a/src/main/java/org/apache/sling/feature/Artifact.java
+++ b/src/main/java/org/apache/sling/feature/Artifact.java
@@ -128,6 +128,20 @@ public class Artifact implements Comparable<Artifact> {
         return this.id.equals(((Artifact)obj).id);
     }
 
+    /**
+     * Create a copy of the artifact with a different id
+     * 
+     * @param id The new id
+     * @return The copy of the feature with the new id
+     */
+    public Artifact copy(final ArtifactId id) {
+        final Artifact result = new Artifact(id);
+
+        result.getMetadata().putAll(this.getMetadata());
+
+        return result;
+    }
+
     @Override
     public String toString() {
         return "Artifact [id=" + id.toMvnId()
diff --git a/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java 
b/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
index ab80ec2..f8864b9 100644
--- a/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
+++ b/src/main/java/org/apache/sling/feature/builder/BuilderUtil.java
@@ -110,18 +110,20 @@ class BuilderUtil {
         mergeWithContextOverwrite("Variable", target, source, (null != 
context) ? context.getVariables() : null);
     }
 
-    // bundles
+    /**
+     * Merge bundles from source into target
+     *
+     * @param target             The target bundles
+     * @param source             The source bundles
+     * @param originatingFeature Optional, if set origin will be recorded
+     * @param artifactMergeAlg   Algorithm used to merge the artifacts
+     */
     static void mergeBundles(final Bundles target,
         final Bundles source,
         final Feature originatingFeature,
             final ArtifactMergeAlgorithm artifactMergeAlg) {
         for(final Map.Entry<Integer, List<Artifact>> entry : 
source.getBundlesByStartOrder().entrySet()) {
             for(final Artifact a : entry.getValue()) {
-                // Record the original feature of the bundle
-                if 
(a.getMetadata().get(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE) == null) {
-                    
a.getMetadata().put(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE, 
originatingFeature.getId().toMvnId());
-                }
-
                 // version handling - use provided algorithm
                 boolean replace = true;
                 if (artifactMergeAlg == ArtifactMergeAlgorithm.HIGHEST) {
@@ -132,7 +134,15 @@ class BuilderUtil {
                 }
                 if ( replace ) {
                     target.removeSame(a.getId());
-                    target.add(a);
+                    // create a copy to detach artifact from source
+                    final Artifact cp = a.copy(a.getId());
+                    // Record the original feature of the bundle
+                    if (originatingFeature != null
+                            && 
a.getMetadata().get(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE) == null) {
+                        
cp.getMetadata().put(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE,
+                                originatingFeature.getId().toMvnId());
+                    }
+                    target.add(cp);
                 }
             }
         }
@@ -183,9 +193,17 @@ class BuilderUtil {
         }
     }
 
-    // default merge for extensions
+    /**
+     * Merge an extension from source into target
+     *
+     * @param target             The target extension
+     * @param source             The source extension
+     * @param originatingFeature Optional, if set origin will be recorded for
+     *                           artifacts
+     * @param artifactMergeAlg   The merge algorithm for artifacts
+     */
     static void mergeExtensions(final Extension target,
-        final Extension source,
+            final Extension source, final Feature originatingFeature,
             final ArtifactMergeAlgorithm artifactMergeAlg) {
         switch ( target.getType() ) {
             case TEXT : // simply append
@@ -225,29 +243,38 @@ class BuilderUtil {
                 target.setJSON(buffer.toString());
                 break;
 
-            case ARTIFACTS : for(final Artifact a : source.getArtifacts()) {
-                    // use artifactMergeAlg
-                    boolean replace = true;
+        case ARTIFACTS:
+            for (final Artifact a : source.getArtifacts()) {
+                // use artifactMergeAlg
+                boolean replace = true;
                 if (artifactMergeAlg == ArtifactMergeAlgorithm.HIGHEST) {
-                         final Artifact existing = 
target.getArtifacts().getSame(a.getId());
-                         if ( existing != null && 
existing.getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion()) > 0 ) {
-                            replace = false;
-                         }
+                    final Artifact existing = 
target.getArtifacts().getSame(a.getId());
+                    if (existing != null
+                            && 
existing.getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion()) > 0) {
+                        replace = false;
                     }
-                    if ( replace ) {
-                    target.getArtifacts().removeSame(a.getId());
-                    target.getArtifacts().add(a);
                 }
+                if (replace) {
+                    target.getArtifacts().removeSame(a.getId());
+                    // create a copy to detach artifact from source
+                    final Artifact cp = a.copy(a.getId());
+                    // Record the original feature of the artifact
+                    if (originatingFeature != null
+                            && 
a.getMetadata().get(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE) == null) {
+                        
cp.getMetadata().put(FeatureConstants.ARTIFACT_ATTR_ORIGINAL_FEATURE,
+                                originatingFeature.getId().toMvnId());
+                    }
+                    target.getArtifacts().add(cp);
                 }
-                break;
+            }
+            break;
         }
     }
 
     // extensions (add/merge)
     static void mergeExtensions(final Feature target,
         final Feature source,
-            final ArtifactMergeAlgorithm artifactMergeAlg,
-        final BuilderContext context) {
+            final ArtifactMergeAlgorithm artifactMergeAlg, final 
BuilderContext context, final boolean recordOrigin) {
         for(final Extension ext : source.getExtensions()) {
             boolean found = false;
 
@@ -269,7 +296,7 @@ class BuilderUtil {
                     }
                     if ( !handled ) {
                         // default merge
-                        mergeExtensions(current, ext, artifactMergeAlg);
+                        mergeExtensions(current, ext, recordOrigin ? source : 
null, artifactMergeAlg);
                     }
                 }
             }
diff --git a/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java 
b/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
index 0fd9dbb..a7709fe 100644
--- a/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
+++ b/src/main/java/org/apache/sling/feature/builder/FeatureBuilder.java
@@ -196,7 +196,7 @@ public abstract class FeatureBuilder {
             }
             usedFeatures.add(assembled.getId());
 
-            merge(target, assembled, context, context.getMergeAlgorithm());
+            merge(target, assembled, context, context.getMergeAlgorithm(), 
true);
         }
 
         // append feature list in extension
@@ -315,15 +315,15 @@ public abstract class FeatureBuilder {
                 throw new IllegalStateException(
                         "Included feature " + i.getId() + " is marked as final 
and can't be used in an include.");
             }
-            final Feature af = internalAssemble(processedFeatures, f, context);
+            final Feature includedFeature = 
internalAssemble(processedFeatures, f, context);
 
             // process include instructions
-            include(af, i);
+            processInclude(includedFeature, i);
 
             // and now merge
-            merge(result, af, context, 
BuilderContext.ArtifactMergeAlgorithm.LATEST);
+            merge(result, includedFeature, context, 
BuilderContext.ArtifactMergeAlgorithm.LATEST, true);
 
-            merge(result, feature, context, 
BuilderContext.ArtifactMergeAlgorithm.LATEST);
+            merge(result, feature, context, 
BuilderContext.ArtifactMergeAlgorithm.LATEST, false);
         }
         processedFeatures.remove(feature.getId().toMvnId());
 
@@ -334,9 +334,9 @@ public abstract class FeatureBuilder {
     private static void merge(final Feature target,
             final Feature source,
             final BuilderContext context,
-            final BuilderContext.ArtifactMergeAlgorithm mergeAlg) {
+            final BuilderContext.ArtifactMergeAlgorithm mergeAlg, final 
boolean recordOrigin) {
         BuilderUtil.mergeVariables(target.getVariables(), 
source.getVariables(), context);
-        BuilderUtil.mergeBundles(target.getBundles(), source.getBundles(), 
source, mergeAlg);
+        BuilderUtil.mergeBundles(target.getBundles(), source.getBundles(), 
recordOrigin ? source : null, mergeAlg);
         BuilderUtil.mergeConfigurations(target.getConfigurations(), 
source.getConfigurations());
         BuilderUtil.mergeFrameworkProperties(target.getFrameworkProperties(), 
source.getFrameworkProperties(), context);
         BuilderUtil.mergeRequirements(target.getRequirements(), 
source.getRequirements());
@@ -344,29 +344,36 @@ public abstract class FeatureBuilder {
         BuilderUtil.mergeExtensions(target,
                 source,
                 mergeAlg,
-                context);
+                context, recordOrigin);
     }
 
-    private static void include(final Feature base, final Include i) {
-        // process removals
-        // bundles
-        for(final ArtifactId a : i.getBundleRemovals()) {
+    /**
+     * Process the include statement Process all the removals contained in the
+     * include
+     *
+     * @param feature The feature
+     * @param include The include
+     */
+    private static void processInclude(final Feature feature, final Include 
include) {
+        // process bundles removals
+        for (final ArtifactId a : include.getBundleRemovals()) {
             boolean removed = false;
             final boolean ignoreVersion = 
a.getOSGiVersion().equals(Version.emptyVersion);
             if ( ignoreVersion ) {
                 // remove any version of that bundle
-                while (base.getBundles().removeSame(a)) {
+                while (feature.getBundles().removeSame(a)) {
                     // continue to remove
                     removed = true;
                 }
             } else {
                 // remove exact version
-                removed = base.getBundles().removeExact(a);
+                removed = feature.getBundles().removeExact(a);
             }
             if ( !removed ) {
-                throw new IllegalStateException("Bundle " + a + " can't be 
removed from feature " + base.getId() + " as it is not part of that feature.");
+                throw new IllegalStateException("Bundle " + a + " can't be 
removed from feature " + feature.getId()
+                        + " as it is not part of that feature.");
             }
-            final Iterator<Configuration> iter = 
base.getConfigurations().iterator();
+            final Iterator<Configuration> iter = 
feature.getConfigurations().iterator();
             while ( iter.hasNext() ) {
                 final Configuration cfg = iter.next();
                 final String bundleId = 
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT_ID);
@@ -382,8 +389,9 @@ public abstract class FeatureBuilder {
                 }
             }
         }
-        // configurations
-        for(final String c : i.getConfigurationRemovals()) {
+
+        // process configuration removals
+        for (final String c : include.getConfigurationRemovals()) {
             final int attrPos = c.indexOf('@');
             final String val = (attrPos == -1 ? c : c.substring(0, attrPos));
             final String attr = (attrPos == -1 ? null : c.substring(attrPos + 
1));
@@ -391,39 +399,40 @@ public abstract class FeatureBuilder {
             final int sepPos = val.indexOf('~');
             Configuration found = null;
             if ( sepPos == -1 ) {
-                found = base.getConfigurations().getConfiguration(val);
+                found = feature.getConfigurations().getConfiguration(val);
 
             } else {
                 final String factoryPid = val.substring(0, sepPos);
                 final String name = val.substring(sepPos + 1);
 
-                found = 
base.getConfigurations().getFactoryConfiguration(factoryPid, name);
+                found = 
feature.getConfigurations().getFactoryConfiguration(factoryPid, name);
             }
             if ( found != null ) {
                 if ( attr == null ) {
-                    base.getConfigurations().remove(found);
+                    feature.getConfigurations().remove(found);
                 } else {
                     found.getProperties().remove(attr);
                 }
             }
         }
 
-        // framework properties
-        for(final String p : i.getFrameworkPropertiesRemovals()) {
-            base.getFrameworkProperties().remove(p);
+        // process framework properties removals
+        for (final String p : include.getFrameworkPropertiesRemovals()) {
+            feature.getFrameworkProperties().remove(p);
         }
 
-        // extensions
-        for(final String name : i.getExtensionRemovals()) {
-            for(final Extension ext : base.getExtensions()) {
+        // process extensions removals
+        for (final String name : include.getExtensionRemovals()) {
+            for (final Extension ext : feature.getExtensions()) {
                 if ( ext.getName().equals(name) ) {
-                    base.getExtensions().remove(ext);
+                    feature.getExtensions().remove(ext);
                     break;
                 }
             }
         }
-        for(final Map.Entry<String, List<ArtifactId>> entry : 
i.getArtifactExtensionRemovals().entrySet()) {
-            for(final Extension ext : base.getExtensions()) {
+        // process artifact extensions removals
+        for (final Map.Entry<String, List<ArtifactId>> entry : 
include.getArtifactExtensionRemovals().entrySet()) {
+            for (final Extension ext : feature.getExtensions()) {
                 if ( ext.getName().equals(entry.getKey()) ) {
                     for(final ArtifactId toRemove : entry.getValue() ) {
                         boolean removed = false;
@@ -452,7 +461,8 @@ public abstract class FeatureBuilder {
                             }
                         }
                         if ( !removed ) {
-                            throw new IllegalStateException("Artifact " + 
toRemove + " can't be removed from feature " + base.getId() + " as it is not 
part of that feature.");
+                            throw new IllegalStateException("Artifact " + 
toRemove + " can't be removed from feature "
+                                    + feature.getId() + " as it is not part of 
that feature.");
                         }
                     }
                     break;
diff --git 
a/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java 
b/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
index f49527c..798578a 100644
--- a/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
+++ b/src/test/java/org/apache/sling/feature/builder/BuilderUtilTest.java
@@ -215,7 +215,7 @@ public class BuilderUtilTest {
 
         source.setJSON("[\"source1\",\"source2\"]");
 
-        BuilderUtil.mergeExtensions(target, source, 
ArtifactMergeAlgorithm.HIGHEST);
+        BuilderUtil.mergeExtensions(target, source, null, 
ArtifactMergeAlgorithm.HIGHEST);
 
         assertEquals(target.getJSON(), 
"[\"target1\",\"target2\",\"source1\",\"source2\"]");
 
@@ -307,7 +307,7 @@ public class BuilderUtilTest {
         Feature ft = new Feature(ArtifactId.fromMvnId("g:t:1"));
 
         assertEquals("Precondition", 0, ft.getExtensions().size());
-        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx);
+        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx, true);
         assertEquals(1, ft.getExtensions().size());
 
         Extension actual = ft.getExtensions().get(0);
@@ -331,7 +331,7 @@ public class BuilderUtilTest {
         ft.getExtensions().add(et);
 
         assertEquals("Precondition", 1, ft.getExtensions().size());
-        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx);
+        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx, true);
         assertEquals(1, ft.getExtensions().size());
 
         Extension actual = ft.getExtensions().get(0);
@@ -358,7 +358,7 @@ public class BuilderUtilTest {
         Feature ft = new Feature(ArtifactId.fromMvnId("g:t:1"));
 
         assertEquals("Precondition", 0, ft.getExtensions().size());
-        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx);
+        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx, true);
         assertEquals(1, ft.getExtensions().size());
 
         Extension actual = ft.getExtensions().get(0);
@@ -383,7 +383,7 @@ public class BuilderUtilTest {
         ft.getExtensions().add(et);
 
         assertEquals("Precondition", 1, ft.getExtensions().size());
-        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx);
+        BuilderUtil.mergeExtensions(ft, fs, ArtifactMergeAlgorithm.LATEST, 
ctx, true);
         assertEquals(1, ft.getExtensions().size());
 
         Extension actual = ft.getExtensions().get(0);

Reply via email to