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-slingfeature-maven-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e5a9d7  SLING-7860 Enhance slingfeature-maven-plugin to aggregate 
multiple features into a single feature
4e5a9d7 is described below

commit 4e5a9d70155f21852cbc200f6954d8321e657074
Author: David Bosschaert <[email protected]>
AuthorDate: Thu Aug 30 15:27:08 2018 +0100

    SLING-7860 Enhance slingfeature-maven-plugin to aggregate multiple features 
into a single feature
---
 pom.xml                                            |   5 +
 .../feature/maven/mojos/AggregateFeatures.java     | 129 ++++++++++++++++++---
 .../feature/maven/mojos/AggregateFeaturesTest.java |  67 +++++++++++
 .../dir/{test_z.json => test_z.feature}            |   0
 4 files changed, 182 insertions(+), 19 deletions(-)

diff --git a/pom.xml b/pom.xml
index 8418cd8..95f4f96 100644
--- a/pom.xml
+++ b/pom.xml
@@ -180,6 +180,11 @@
             <version>3.0.24</version>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.framework</artifactId>
+            <version>1.9.0</version>
+        </dependency>
+        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
             <version>2.5</version>
diff --git 
a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java 
b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
index 6314c9c..162910b 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AggregateFeatures.java
@@ -47,6 +47,7 @@ import java.nio.file.Files;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
@@ -85,7 +86,11 @@ public class AggregateFeatures extends AbstractFeatureMojo {
 
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
-        Map<ArtifactId, Feature> featureMap = readFeatures(features);
+        File aggregatedFeaturesDir = new 
File(project.getBuild().getDirectory(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION);
+        aggregatedFeaturesDir.mkdirs();
+        Map<ArtifactId, Feature> contextFeatures = 
readFeaturesFromDirectory(aggregatedFeaturesDir);
+
+        Map<ArtifactId, Feature> featureMap = readFeatures(features, 
contextFeatures);
 
         ArtifactId newFeatureID = new ArtifactId(project.getGroupId(), 
project.getArtifactId(),
                 project.getVersion(), classifier, 
FeatureConstants.PACKAGING_FEATURE);
@@ -98,7 +103,22 @@ public class AggregateFeatures extends AbstractFeatureMojo {
         BuilderContext builderContext = new BuilderContext(new 
FeatureProvider() {
             @Override
             public Feature provide(ArtifactId id) {
-                return featureMap.get(id);
+                Feature f = featureMap.get(id);
+                if (f != null)
+                    return f;
+
+                // Check for the feature in the local context
+                f = contextFeatures.get(id);
+                if (f != null)
+                    return f;
+
+                // Finally, look the feature up via Maven's dependency 
mechanism
+                try {
+                    return readFeatureFromMavenArtifact(id.getGroupId(), 
id.getArtifactId(), id.getVersion(),
+                            id.getType(), id.getClassifier());
+                } catch (IOException e) {
+                    throw new RuntimeException("Cannot find feature: " + id, 
e);
+                }
             }
         }).add(StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                 ServiceLoader.load(FeatureExtensionHandler.class).iterator(), 
Spliterator.ORDERED), false)
@@ -106,9 +126,6 @@ public class AggregateFeatures extends AbstractFeatureMojo {
 
         Feature result = FeatureBuilder.assemble(newFeature, builderContext);
 
-        File aggregatedFeaturesDir = new 
File(project.getBuild().getDirectory(), 
FeatureConstants.FEATURE_PROCESSED_LOCATION);
-        aggregatedFeaturesDir.mkdirs();
-
         try (FileWriter fileWriter = new FileWriter(new 
File(aggregatedFeaturesDir, classifier + ".json"))) {
             FeatureJSONWriter.write(fileWriter, result);
         } catch (IOException e) {
@@ -116,7 +133,7 @@ public class AggregateFeatures extends AbstractFeatureMojo {
         }
     }
 
-    private Map<ArtifactId, Feature> readFeatures(Collection<FeatureConfig> 
featureConfigs) throws MojoExecutionException {
+    private Map<ArtifactId, Feature> readFeatures(Collection<FeatureConfig> 
featureConfigs, Map<ArtifactId, Feature> contextFeatures) throws 
MojoExecutionException {
         Map<ArtifactId, Feature> featureMap = new HashMap<>();
 
         try {
@@ -124,7 +141,7 @@ public class AggregateFeatures extends AbstractFeatureMojo {
                 if (fc.location != null) {
                     readFeaturesFromDirectory(fc, featureMap);
                 } else if (fc.artifactId != null) {
-                    readFeaturesFromArtifact(fc, featureMap);
+                    readFeatureFromMavenArtifact(fc, featureMap, 
contextFeatures);
                 }
             }
         } catch (IOException e) {
@@ -134,9 +151,32 @@ public class AggregateFeatures extends AbstractFeatureMojo 
{
         return featureMap;
     }
 
-    private void readFeaturesFromArtifact(FeatureConfig fc, Map<ArtifactId, 
Feature> featureMap) throws IOException {
+    private void readFeatureFromMavenArtifact(FeatureConfig fc, 
Map<ArtifactId, Feature> featureMap,
+            Map<ArtifactId, Feature> contextFeatures) throws IOException {
+        ArtifactId id = new ArtifactId(fc.groupId, fc.artifactId, fc.version, 
fc.classifier, fc.type);
+        Feature f = contextFeatures.get(id);
+        if (f != null) {
+            featureMap.put(id, f);
+        } else {
+            f = readFeatureFromMavenArtifact(id);
+            if (f != null) {
+                featureMap.put(id, f);
+            }
+        }
+    }
+
+    private Feature readFeatureFromMavenArtifact(ArtifactId id) throws 
IOException {
+        return readFeatureFromMavenArtifact(id.getGroupId(), 
id.getArtifactId(), id.getVersion(), id.getType(), id.getClassifier());
+    }
+
+    private Feature readFeatureFromMavenArtifact(String groupId, String 
artifactId, String version, String type, String classifier) throws IOException {
+        File artFile = resolveMavenArtifact(groupId, artifactId, version, 
type, classifier);
+        return readFeatureFromFile(artFile);
+    }
+
+    private File resolveMavenArtifact(String groupId, String artifactId, 
String version, String type, String classifier) {
         Artifact art = repoSystem.createArtifactWithClassifier(
-                fc.groupId, fc.artifactId, fc.version, fc.type, fc.classifier);
+                groupId, artifactId, version, type, classifier);
 
         ArtifactResolutionRequest resReq = new ArtifactResolutionRequest()
             .setArtifact(art)
@@ -145,17 +185,33 @@ public class AggregateFeatures extends 
AbstractFeatureMojo {
         artifactResolver.resolve(resReq);
 
         File artFile = art.getFile();
-        readFeatureFromFile(artFile, featureMap);
+        return artFile;
     }
 
     private void readFeaturesFromDirectory(FeatureConfig fc, Map<ArtifactId, 
Feature> featureMap) throws IOException {
+        Map<String,String> includes = new HashMap<>();
+        Map<String,String> excludes = new HashMap<>();
+
+        for (String inc : fc.includes) {
+            includes.put(inc, convertGlobToRegex(inc));
+        }
+        for (String exc : fc.excludes) {
+            excludes.put(exc, convertGlobToRegex(exc));
+        }
+
         nextFile:
         for (File f : new File(fc.location).listFiles()) {
-            boolean matchesIncludes = fc.includes.size() == 0;
-            for (String inc : fc.includes) {
-                inc = convertGlobToRegex(inc);
+            // First check that it is allowed as part of the includes
+            boolean matchesIncludes = includes.size() == 0;
+
+            for (Iterator<String> it = includes.values().iterator(); 
it.hasNext(); ) {
+                String inc = it.next();
                 if (f.getName().matches(inc)) {
                     matchesIncludes = true;
+                    if (!isGlob(inc)) {
+                        // Not a glob
+                        it.remove();
+                    }
                     break;
                 }
             }
@@ -163,15 +219,51 @@ public class AggregateFeatures extends 
AbstractFeatureMojo {
             if (!matchesIncludes)
                 continue nextFile;
 
-            for (String exc : fc.excludes) {
-                exc = convertGlobToRegex(exc);
+            // Ensure there is no exclusion for it
+            for (Iterator<String> it = excludes.values().iterator(); 
it.hasNext(); ) {
+                String exc = it.next();
                 if (f.getName().matches(exc)) {
+                    if (!isGlob(exc)) {
+                        // Not a glob
+                        it.remove();
+                    }
                     continue nextFile;
                 }
             }
 
-            readFeatureFromFile(f, featureMap);
+            Feature feat = readFeatureFromFile(f);
+            featureMap.put(feat.getId(), feat);
+        }
+
+        // If there are any non-glob includes/excludes left, fail as the 
plugin is then incorrectly configured
+        for (Map.Entry<String,String> i : includes.entrySet()) {
+            if (!isGlob(i.getValue())) {
+                throw new IOException("Non-wildcard include " + i.getKey() + " 
not found.");
+            }
         }
+        for (Map.Entry<String,String> e : excludes.entrySet()) {
+            if (!isGlob(e.getValue())) {
+                throw new IOException("Non-wildcard exclude " + e.getKey() + " 
not found.");
+            }
+        }
+    }
+
+    private boolean isGlob(String name) {
+        return name.contains("*");
+    }
+
+    private Map<ArtifactId, Feature> readFeaturesFromDirectory(File directory) 
throws MojoExecutionException {
+        Map<ArtifactId, Feature> m = new HashMap<>();
+        FeatureConfig fc = new FeatureConfig();
+        fc.setLocation(directory.getAbsolutePath());
+
+        try {
+            readFeaturesFromDirectory(fc, m);
+        } catch (IOException e) {
+            throw new MojoExecutionException("Problem reading feature", e);
+        }
+
+        return m;
     }
 
     private String convertGlobToRegex(String glob) {
@@ -180,11 +272,10 @@ public class AggregateFeatures extends 
AbstractFeatureMojo {
         return glob;
     }
 
-    private void readFeatureFromFile(File f, Map<ArtifactId, Feature> 
featureMap) throws IOException {
+    private Feature readFeatureFromFile(File f) throws IOException {
         String content = new String(Files.readAllBytes(f.toPath()));
         content = Substitution.replaceMavenVars(project, content);
-        Feature feat = FeatureJSONReader.read(new StringReader(content), null);
-        featureMap.put(feat.getId(), feat);
+        return FeatureJSONReader.read(new StringReader(content), null);
     }
 
     public static class FeatureConfig {
diff --git 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
index ce0a837..8e7b90e 100644
--- 
a/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
+++ 
b/src/test/java/org/apache/sling/feature/maven/mojos/AggregateFeaturesTest.java
@@ -22,6 +22,7 @@ import 
org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
 import org.apache.maven.artifact.resolver.ArtifactResolver;
 import org.apache.maven.model.Build;
+import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.repository.RepositorySystem;
 import org.apache.sling.feature.ArtifactId;
@@ -54,6 +55,8 @@ import java.util.Set;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 public class AggregateFeaturesTest {
     private Path tempDir;
@@ -181,6 +184,8 @@ public class AggregateFeaturesTest {
         FeatureConfig fc = new FeatureConfig();
         fc.setLocation(featuresDir.getAbsolutePath());
         fc.setIncludes("*.json");
+        fc.setIncludes("*.foobar");
+        fc.setIncludes("test_z.feature");
         fc.setExcludes("*_v*");
         fc.setExcludes("test_w.json");
 
@@ -237,6 +242,68 @@ public class AggregateFeaturesTest {
     }
 
     @Test
+    public void testNonMatchingDirectoryIncludes() throws Exception {
+        File featuresDir = new File(
+                getClass().getResource("/aggregate-features/dir").getFile());
+
+        FeatureConfig fc = new FeatureConfig();
+        fc.setLocation(featuresDir.getAbsolutePath());
+        fc.setIncludes("doesnotexist.json");
+
+        Build mockBuild = Mockito.mock(Build.class);
+        Mockito.when(mockBuild.getDirectory()).thenReturn(tempDir.toString());
+
+        MavenProject mockProj = Mockito.mock(MavenProject.class);
+        Mockito.when(mockProj.getBuild()).thenReturn(mockBuild);
+        Mockito.when(mockProj.getGroupId()).thenReturn("org.foo");
+        Mockito.when(mockProj.getArtifactId()).thenReturn("org.foo.bar");
+        Mockito.when(mockProj.getVersion()).thenReturn("1.2.3-SNAPSHOT");
+
+        AggregateFeatures af = new AggregateFeatures();
+        af.classifier = "aggregated";
+        af.features = Collections.singletonList(fc);
+        af.project = mockProj;
+
+        try {
+            af.execute();
+            fail("Should have thrown an exception because doesnotexist.json is 
not a file");
+        } catch (MojoExecutionException mee) {
+            assertTrue(mee.getCause().getMessage().contains("Non-wildcard 
include doesnotexist.json not found"));
+        }
+    }
+
+    @Test
+    public void testNonMatchingDirectoryExcludes() throws Exception {
+        File featuresDir = new File(
+                getClass().getResource("/aggregate-features/dir").getFile());
+
+        FeatureConfig fc = new FeatureConfig();
+        fc.setLocation(featuresDir.getAbsolutePath());
+        fc.setExcludes("doesnotexist.json");
+
+        Build mockBuild = Mockito.mock(Build.class);
+        Mockito.when(mockBuild.getDirectory()).thenReturn(tempDir.toString());
+
+        MavenProject mockProj = Mockito.mock(MavenProject.class);
+        Mockito.when(mockProj.getBuild()).thenReturn(mockBuild);
+        Mockito.when(mockProj.getGroupId()).thenReturn("org.foo");
+        Mockito.when(mockProj.getArtifactId()).thenReturn("org.foo.bar");
+        Mockito.when(mockProj.getVersion()).thenReturn("1.2.3-SNAPSHOT");
+
+        AggregateFeatures af = new AggregateFeatures();
+        af.classifier = "aggregated";
+        af.features = Collections.singletonList(fc);
+        af.project = mockProj;
+
+        try {
+            af.execute();
+            fail("Should have thrown an exception because doesnotexist.json is 
not a file");
+        } catch (MojoExecutionException mee) {
+            assertTrue(mee.getCause().getMessage().contains("Non-wildcard 
exclude doesnotexist.json not found"));
+        }
+    }
+
+    @Test
     public void testReadFeatureFromArtifact() throws Exception {
         File featureFile = new File(
                 
getClass().getResource("/aggregate-features/test_x.json").getFile());
diff --git a/src/test/resources/aggregate-features/dir/test_z.json 
b/src/test/resources/aggregate-features/dir/test_z.feature
similarity index 100%
rename from src/test/resources/aggregate-features/dir/test_z.json
rename to src/test/resources/aggregate-features/dir/test_z.feature

Reply via email to