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