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 09:44:00 UTC
[sling-slingfeature-maven-plugin] 01/14: Move feature model to
whiteboard git
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
commit 67c5f3c6396d0e2bacfafdea473cd1effa833f8d
Author: Carsten Ziegeler <cz...@adobe.com>
AuthorDate: Fri Nov 3 15:06:50 2017 +0100
Move feature model to whiteboard git
---
pom.xml | 192 ++++++++
.../feature/maven/ApplicationProjectConfig.java | 116 +++++
.../feature/maven/ApplicationProjectInfo.java | 31 ++
.../apache/sling/feature/maven/Environment.java | 35 ++
.../sling/feature/maven/FeatureConstants.java | 32 ++
.../sling/feature/maven/FeatureProjectConfig.java | 138 ++++++
.../sling/feature/maven/FeatureProjectInfo.java | 32 ++
.../apache/sling/feature/maven/Preprocessor.java | 515 +++++++++++++++++++++
.../apache/sling/feature/maven/ProjectHelper.java | 319 +++++++++++++
.../apache/sling/feature/maven/ProjectInfo.java | 27 ++
.../feature/maven/mojos/AbstractFeatureMojo.java | 116 +++++
.../sling/feature/maven/mojos/AttachFeature.java | 77 +++
.../mojos/DependencyLifecycleParticipant.java | 89 ++++
.../META-INF/m2e/lifecycle-mapping-metadata.xml | 32 ++
src/main/resources/META-INF/plexus/components.xml | 103 +++++
src/site/markdown/index.md | 6 +
src/site/site.xml | 35 ++
17 files changed, 1895 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0d887cf
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,192 @@
+<?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>osgifeature-maven-plugin</artifactId>
+ <version>0.01.7-SNAPSHOT</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>Apache Sling OSGi Feature Maven Plugin</name>
+ <description>
+ Maven Plugin for OSGi Applicatgions
+ </description>
+
+ <properties>
+ <sling.java.version>8</sling.java.version>
+ <maven.version>3.5.0</maven.version>
+ <maven.site.path>${project.artifactId}-archives/${project.artifactId}-LATEST</maven.site.path>
+ </properties>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/tooling/maven/osgifeature-maven-plugin</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/tooling/maven/osgifeature-maven-plugin</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/tooling/maven/osgifeature-maven-plugin</url>
+ </scm>
+
+ <!-- Support for publishing the mvn site. -->
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <url>scm:svn:https://svn.apache.org/repos/infra/websites/production/sling/content/components/${maven.site.path}</url>
+ </site>
+ </distributionManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-component-metadata</artifactId>
+ <version>1.7.1</version>
+ <executions>
+ <execution>
+ <id>generate-metadata</id>
+ <goals>
+ <goal>generate-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>mojo-descriptor</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>descriptor</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>generated-helpmojo</id>
+ <goals>
+ <goal>helpmojo</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <configuration>
+ <checkoutDirectory>${user.home}/maven-sites/${maven.site.path}</checkoutDirectory>
+ <tryUpdate>true</tryUpdate>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>src/site/markdown/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.feature</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.feature.support</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-artifact</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-compat</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-interactivity-api</artifactId>
+ <version>1.0-alpha-6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-archiver</artifactId>
+ <version>3.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ <version>3.0.24</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>maven-filtering</artifactId>
+ <version>3.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.10.19</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ </dependencies>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </reporting>
+
+</project>
diff --git a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
new file mode 100644
index 0000000..78cd363
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectConfig.java
@@ -0,0 +1,116 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.artifact.Artifact;
+
+public class ApplicationProjectConfig {
+
+ public static final String CFG_FEATURES = "features";
+
+ public static final String CFG_TEST_FEATURES = "testFeatures";
+
+ public static final String CFG_FEATURE_REFS = "featureRefs";
+
+ public static final String CFG_TEST_FEATURE_REFS = "testFeatureRefs";
+
+ public static final String DEFAULT_FEATURE_DIR = "src/main/osgi/features";
+
+ public static final String DEFAULT_TEST_FEATURE_DIR = "src/test/osgi/features";
+
+ public static final String DEFAULT_REF_DIR = "src/main/osgi/feature-refs";
+
+ public static final String DEFAULT_TEST_REF_DIR = "src/test/osgi/feature-refs";
+
+ private final String featuresDirName;
+
+ private final String featureRefsDirName;
+
+ private final boolean skipAddDep;
+
+ private final String name;
+
+ private final String scope;
+
+ private final boolean isTest;
+
+ public static ApplicationProjectConfig getMainConfig(final ApplicationProjectInfo info) {
+ return new ApplicationProjectConfig(info, false);
+ }
+
+ public static ApplicationProjectConfig getTestConfig(final ApplicationProjectInfo info) {
+ return new ApplicationProjectConfig(info, true);
+ }
+
+ private ApplicationProjectConfig(final ApplicationProjectInfo info, final boolean test) {
+ this.isTest = test;
+ final String featuresDirCfgName;
+ final String featureRefsDirCfgName;
+ final String defaultDir;
+ final String defaultRefDir;
+ final String skipAddDepCfgName;
+ final String defaultSkipValue;
+ if ( test ) {
+ featuresDirCfgName = CFG_TEST_FEATURES;
+ featureRefsDirCfgName = CFG_TEST_FEATURE_REFS;
+ defaultDir = DEFAULT_TEST_FEATURE_DIR;
+ defaultRefDir = DEFAULT_TEST_REF_DIR;
+ skipAddDepCfgName = FeatureProjectConfig.CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES;
+ defaultSkipValue = "true";
+ this.scope = Artifact.SCOPE_TEST;
+ this.name = "test features";
+ } else {
+ featuresDirCfgName = CFG_FEATURES;
+ featureRefsDirCfgName = CFG_FEATURE_REFS;
+ defaultDir = DEFAULT_FEATURE_DIR;
+ defaultRefDir = DEFAULT_REF_DIR;
+ skipAddDepCfgName = FeatureProjectConfig.CFG_SKIP_ADD_FEATURE_DEPENDENCIES;
+ defaultSkipValue = "false";
+ this.scope = Artifact.SCOPE_PROVIDED;
+ this.name = "features";
+ }
+ this.featuresDirName = ProjectHelper.getConfigValue(info.plugin, featuresDirCfgName, defaultRefDir);
+ this.featureRefsDirName = ProjectHelper.getConfigValue(info.plugin, featureRefsDirCfgName, defaultDir);
+ final String skipCfg = ProjectHelper.getConfigValue(info.plugin, skipAddDepCfgName, defaultSkipValue);
+ this.skipAddDep = "true".equals(skipCfg.toLowerCase());
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getFeatureDir() {
+ return this.featuresDirName;
+ }
+
+ public String getFeatureRefDir() {
+ return this.featuresDirName;
+ }
+
+ public boolean isSkipAddDependencies() {
+ return this.skipAddDep;
+ }
+
+ public String getScope() {
+ return this.scope;
+ }
+
+ public boolean isTestConfig() {
+ return this.isTest;
+ }
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
new file mode 100644
index 0000000..dc0e393
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/ApplicationProjectInfo.java
@@ -0,0 +1,31 @@
+/*
+ * 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.maven;
+
+import org.apache.sling.feature.Feature;
+
+import java.util.List;
+
+public class ApplicationProjectInfo extends ProjectInfo {
+
+ public List<Feature> features;
+ public List<Feature> testFeatures;
+
+ public List<Feature> assembledFeatures;
+ public List<Feature> assembledTestFeatures;
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/Environment.java b/src/main/java/org/apache/sling/feature/maven/Environment.java
new file mode 100644
index 0000000..ca5592d
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/Environment.java
@@ -0,0 +1,35 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.execution.MavenSession;
+import org.codehaus.plexus.logging.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Environment {
+
+ public ArtifactHandlerManager artifactHandlerManager;
+ public ArtifactResolver resolver;
+ public MavenSession session;
+ public Logger logger;
+ public final Map<String, ProjectInfo> modelProjects = new HashMap<>();
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java b/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
new file mode 100644
index 0000000..96a3b2c
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureConstants.java
@@ -0,0 +1,32 @@
+/*
+ * 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.maven;
+
+public abstract class FeatureConstants {
+
+ public static final String PACKAGING_FEATURE = "osgifeature";
+
+ public static final String PACKAGING_APPLICATION = "osgiapp";
+
+ public static final String CLASSIFIER_FEATURE = "feature";
+
+ public static final String CLASSIFIER_TEST_FEATURE = "testfeature";
+
+ public static final String FEATURE_ARTIFACT_NAME = "feature.json";
+
+ public static final String TEST_FEATURE_ARTIFACT_NAME = "testfeature.json";
+}
diff --git a/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java b/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java
new file mode 100644
index 0000000..a9ba4f5
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureProjectConfig.java
@@ -0,0 +1,138 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.artifact.Artifact;
+
+public class FeatureProjectConfig {
+
+ public static final String CFG_SKIP_ADD_FEATURE_DEPENDENCIES = "skipAddFeatureDependencies";
+
+ public static final String CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES = "skipAddTestFeatureDependencies";
+
+ public static final String CFG_FEATURE_FILE = "featureFile";
+
+ public static final String CFG_TEST_FEATURE_FILE = "testFeatureFile";
+
+ public static final String CFG_FEATURE_INLINED = "feature";
+
+ public static final String CFG_TEST_FEATURE_INLINED = "testFeature";
+
+ public static final String CFG_SKIP_ADD_JAR_TO_FEATURE = "skipAddJarToFeature";
+
+ public static final String CFG_SKIP_ADD_JAR_TO_TEST_FEATURE = "skipAddJarToTestFeature";
+
+ public static final String CFG_JAR_START_LEVEL = "jarStartLevel";
+
+ public static final String DEFAULT_FEATURE_FILE = "src/main/osgi/feature.json";
+
+ public static final String DEFAULT_TEST_FEATURE_FILE = "src/test/osgi/feature.json";
+
+ public static final String DEFAULT_START_LEVEL = "20";
+
+ private final String inlinedFeature;
+
+ private final String featureFileName;
+
+ private final boolean skipAddDep;
+
+ private final String name;
+
+ private final String scope;
+
+ private final boolean isTest;
+
+ private final String jarStartLevel;
+
+ private final boolean skipAddJar;
+
+ public static FeatureProjectConfig getMainConfig(final FeatureProjectInfo info) {
+ return new FeatureProjectConfig(info, false);
+ }
+
+ public static FeatureProjectConfig getTestConfig(final FeatureProjectInfo info) {
+ return new FeatureProjectConfig(info, true);
+ }
+
+ private FeatureProjectConfig(final FeatureProjectInfo info, final boolean test) {
+ this.isTest = test;
+ final String inlineCfgName;
+ final String fileCfgName;
+ final String defaultFile;
+ final String skipAddDepCfgName;
+ final String defaultSkipValue;
+ if ( test ) {
+ inlineCfgName = CFG_TEST_FEATURE_INLINED;
+ fileCfgName = CFG_TEST_FEATURE_FILE;
+ defaultFile = DEFAULT_TEST_FEATURE_FILE;
+ this.scope = Artifact.SCOPE_TEST;
+ skipAddDepCfgName = CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES;
+ defaultSkipValue = "true";
+ this.name = "test feature";
+ this.skipAddJar = "true".equals(ProjectHelper.getConfigValue(info.plugin, CFG_SKIP_ADD_JAR_TO_TEST_FEATURE, "true"));
+ } else {
+ inlineCfgName = CFG_FEATURE_INLINED;
+ fileCfgName = CFG_TEST_FEATURE_FILE;
+ defaultFile = DEFAULT_FEATURE_FILE;
+ this.scope = Artifact.SCOPE_PROVIDED;
+ skipAddDepCfgName = CFG_SKIP_ADD_FEATURE_DEPENDENCIES;
+ defaultSkipValue = "false";
+ this.name = "feature";
+ this.skipAddJar = "true".equals(ProjectHelper.getConfigValue(info.plugin, CFG_SKIP_ADD_JAR_TO_FEATURE, "true"));
+ }
+ this.inlinedFeature = ProjectHelper.getConfigValue(info.plugin, inlineCfgName, null);
+ this.featureFileName = ProjectHelper.getConfigValue(info.plugin, fileCfgName, defaultFile);
+ final String skipCfg = ProjectHelper.getConfigValue(info.plugin, skipAddDepCfgName, defaultSkipValue);
+ this.skipAddDep = "true".equals(skipCfg.toLowerCase());
+ this.jarStartLevel = ProjectHelper.getConfigValue(info.plugin, CFG_JAR_START_LEVEL, DEFAULT_START_LEVEL);
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getInlinedFeature() {
+ return this.inlinedFeature;
+ }
+
+ public String getFeatureFileName() {
+ return this.featureFileName;
+ }
+
+ public boolean isSkipAddDependencies() {
+ return this.skipAddDep;
+ }
+
+ public String getScope() {
+ return this.scope;
+ }
+
+ public boolean isTestConfig() {
+ return this.isTest;
+ }
+
+ public String getJarStartLevel() {
+ return this.jarStartLevel;
+ }
+
+ public boolean isSkipAddJarToFeature() {
+ return this.skipAddJar;
+ }
+
+
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java b/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
new file mode 100644
index 0000000..b0f379b
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/FeatureProjectInfo.java
@@ -0,0 +1,32 @@
+/*
+ * 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.maven;
+
+import org.apache.sling.feature.Feature;
+
+public class FeatureProjectInfo extends ProjectInfo {
+
+ public boolean featureDone = false;
+ public boolean testFeatureDone = false;
+
+ public Feature feature;
+ public Feature assembledFeature;
+
+ public Feature testFeature;
+ public Feature assembledTestFeature;
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/Preprocessor.java b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
new file mode 100644
index 0000000..47a09c5
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/Preprocessor.java
@@ -0,0 +1,515 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.project.MavenProject;
+import org.apache.sling.feature.Artifact;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.process.BuilderContext;
+import org.apache.sling.feature.process.FeatureBuilder;
+import org.apache.sling.feature.process.FeatureProvider;
+import org.apache.sling.feature.support.FeatureUtil;
+import org.apache.sling.feature.support.json.FeatureJSONReader;
+import org.codehaus.plexus.logging.Logger;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * The processor processes all feature projects.
+ */
+public class Preprocessor {
+
+ /**
+ * Process the provided projects.
+ * @param env The environment with all maven settings and projects
+ */
+ public void process(final Environment env) {
+ for(final ProjectInfo info : env.modelProjects.values()) {
+ if ( info instanceof FeatureProjectInfo ) {
+ final FeatureProjectInfo finfo = (FeatureProjectInfo)info;
+ process(env, finfo, FeatureProjectConfig.getMainConfig(finfo));
+ process(env, finfo, FeatureProjectConfig.getTestConfig(finfo));
+ if ( FeatureConstants.PACKAGING_FEATURE.equals(info.project.getPackaging()) && finfo.feature == null ) {
+ throw new RuntimeException("Feature project has no feature defined: " + info.project.getId());
+ }
+
+ ProjectHelper.storeProjectInfo(finfo);
+ } else {
+ final ApplicationProjectInfo ainfo = (ApplicationProjectInfo)info;
+ process(env, ainfo, ApplicationProjectConfig.getMainConfig(ainfo));
+ process(env, ainfo, ApplicationProjectConfig.getTestConfig(ainfo));
+
+ ProjectHelper.storeProjectInfo(ainfo);
+ }
+ }
+ }
+
+ /**
+ * Process a single feature project.
+ *
+ * @param env The environment with all maven settings and projects
+ * @param info The project to process.
+ * @param config The configuration for the project.
+ */
+ private void process(final Environment env,
+ final FeatureProjectInfo info,
+ final FeatureProjectConfig config) {
+ if ( (config.isTestConfig() && info.testFeatureDone == true )
+ || (!config.isTestConfig() && info.featureDone == true) ) {
+ env.logger.debug("Return assembled " + config.getName() + " for " + info.project.getId());
+ return;
+ }
+ // prevent recursion and multiple processing
+ if ( config.isTestConfig() ) {
+ info.testFeatureDone = true;
+ } else {
+ info.featureDone = true;
+ }
+ env.logger.debug("Processing " + config.getName() + " in project " + info.project.getId());
+
+ // read project feature, either inlined or from file
+ final Feature feature = readProjectFeature(env.logger, info.project, config);
+ if ( feature == null ) {
+ env.logger.debug("No " + config.getName() + " found in project " + info.project.getId());
+ return;
+ }
+ if ( config.isTestConfig() ) {
+ info.testFeature = feature;
+ } else {
+ info.feature = feature;
+ }
+
+ // process attachments (only for jar or bundle)
+ if ( "jar".equals(info.project.getPackaging())
+ || "bundle".equals(info.project.getPackaging())) {
+ if ( config.isSkipAddJarToFeature() ) {
+ env.logger.debug("Skip adding jar to " + config.getName());
+ } else {
+ final Artifact jar = new Artifact(new ArtifactId(info.project.getGroupId(),
+ info.project.getArtifactId(),
+ info.project.getVersion(),
+ null,
+ "jar"));
+ feature.getBundles().add(Integer.valueOf(config.getJarStartLevel()), jar);
+ }
+ }
+
+ final Feature assembledFeature = FeatureBuilder.assemble(feature, new BuilderContext(this.createFeatureProvider(env,
+ info,
+ config.isTestConfig(),
+ config.isSkipAddDependencies(),
+ config.getScope(), null)));
+ if ( config.isTestConfig() ) {
+ info.assembledTestFeature = assembledFeature;
+ } else {
+ info.assembledFeature = assembledFeature;
+ }
+
+ if ( config.isSkipAddDependencies() ) {
+ env.logger.debug("Not adding artifacts from feature as dependencies");
+ } else {
+ addDependenciesFromFeature(env, info, assembledFeature, config.getScope());
+ }
+ }
+
+ private void scan(final List<File> files, final File dir, final String ext) {
+ for(final File f : dir.listFiles()) {
+ if ( !f.getName().startsWith(".") ) {
+ if ( f.isDirectory() ) {
+ scan(files, f, ext);
+ } else if ( f.getName().endsWith("." + ext) ) {
+ files.add(f);
+ }
+ }
+ }
+ }
+
+ /**
+ * Process a single application project.
+ *
+ * @param env The environment with all maven settings and projects
+ * @param info The project to process.
+ * @param config The configuration for the project.
+ */
+ private void process(final Environment env,
+ final ApplicationProjectInfo info,
+ final ApplicationProjectConfig config) {
+ final List<Feature> featureList = new ArrayList<>();
+ env.logger.debug("Processing " + config.getName() + " in project " + info.project.getId());
+
+ // an application supports two sets of files:
+ // features and references to features
+
+ // feature files first:
+ final File dir = new File(info.project.getBasedir(), config.getFeatureDir());
+ if ( dir.exists() ) {
+ final List<File> files = new ArrayList<>();
+ scan(files, dir, "json");
+
+ for(final File file : files) {
+ // create id in case the file does not contain one
+ // classifier is the hard part, we use the file path/name
+ String fileName = file.getAbsolutePath().substring(dir.getAbsolutePath().length() + 1);
+ fileName = fileName.substring(0, fileName.length() - 5); // remove .json
+ fileName = fileName.replace(File.separatorChar, '_');
+ fileName = fileName.replace('-', '_');
+ final String classifier;
+ if ( config.isTestConfig() ) {
+ classifier = "test_" + fileName;
+ } else {
+ classifier = fileName;
+ }
+ final ArtifactId id = new ArtifactId(info.project.getGroupId(),
+ info.project.getArtifactId(),
+ info.project.getVersion(),
+ classifier,
+ FeatureConstants.PACKAGING_FEATURE);
+
+ // We should pass in an "id" to FeatureJSONReader.read and later on check the id (again, need to handle ref files)
+ try (final FileReader reader = new FileReader(file)) {
+ final Feature feature = FeatureJSONReader.read(reader, id, file.getAbsolutePath());
+
+ this.checkFeatureId(id, feature);
+
+ this.setProjectInfo(info.project, feature);
+ this.postProcessReadFeature(feature);
+ featureList.add(feature);
+
+ } catch ( final IOException io) {
+ throw new RuntimeException("Unable to read feature " + file.getAbsolutePath(), io);
+ }
+ }
+ } else {
+ env.logger.debug("Feature directory " + config.getFeatureDir() + " does not exist in project " + info.project.getId());
+ }
+ final List<Feature> assembledFeatureList = new ArrayList<>();
+ for(final Feature feature : featureList) {
+ final Feature assembledFeature = FeatureBuilder.assemble(feature, new BuilderContext(this.createFeatureProvider(env,
+ info,
+ config.isTestConfig(),
+ config.isSkipAddDependencies(),
+ config.getScope(),
+ featureList)));
+ assembledFeatureList.add(assembledFeature);
+ }
+ if ( config.isTestConfig() ) {
+ info.testFeatures = featureList;
+ info.assembledTestFeatures = assembledFeatureList;
+ } else {
+ info.features = featureList;
+ info.assembledFeatures = assembledFeatureList;
+ }
+
+ // and now references
+ final List<Feature> featureRefList = new ArrayList<>();
+ final File refDir = new File(info.project.getBasedir(), config.getFeatureRefDir());
+ if ( refDir.exists() ) {
+ final List<File> files = new ArrayList<>();
+ scan(files, refDir, "ref");
+
+ for(final File file : files) {
+ try {
+ final List<String> features = FeatureUtil.parseFeatureRefFile(file);
+ if ( features.isEmpty() ) {
+ env.logger.debug("Empty feature ref file at " + file);
+ } else {
+ for(final String ref : features) {
+ if ( !ref.startsWith("mvn:") ) {
+ throw new RuntimeException("Unsupported feature ref in feature ref file at " + file + " : " + ref);
+ }
+ final ArtifactId id = ArtifactId.fromMvnUrl(ref);
+ final Feature feature = this.createFeatureProvider(env, info, config.isTestConfig(), config.isSkipAddDependencies(), config.getScope(), null).provide(id);
+ if ( feature == null ) {
+ throw new RuntimeException("Unable to resolve feature " + id);
+ }
+ featureRefList.add(feature);
+ }
+ }
+ } catch ( final IOException io) {
+ throw new RuntimeException("Unable to read feature " + file.getAbsolutePath(), io);
+ }
+ }
+ }
+ final List<Feature> assembledFeatureRefList = new ArrayList<>();
+ for(final Feature feature : featureRefList) {
+ final Feature assembledFeature = FeatureBuilder.assemble(feature, new BuilderContext(this.createFeatureProvider(env,
+ info,
+ config.isTestConfig(),
+ config.isSkipAddDependencies(),
+ config.getScope(),
+ featureList)));
+ assembledFeatureRefList.add(assembledFeature);
+ }
+ if ( config.isTestConfig() ) {
+ info.testFeatures.addAll(featureRefList);
+ info.assembledTestFeatures.addAll(assembledFeatureRefList);
+ } else {
+ info.features.addAll(featureRefList);
+ info.assembledFeatures.addAll(assembledFeatureRefList);
+ }
+
+ if ( config.isSkipAddDependencies() ) {
+ env.logger.debug("Not adding artifacts from features as dependencies");
+ } else {
+ for(final Feature feature : assembledFeatureList) {
+ addDependenciesFromFeature(env, info, feature, config.getScope());
+ }
+ }
+ }
+
+ /**
+ * Add all dependencies from the feature
+ * @param env The environment
+ * @param info The project info
+ * @param assembledFeature The assembled feature for finding the artifacts.
+ * @param scope The scope which the new dependencies should have
+ */
+ private void addDependenciesFromFeature(
+ final Environment env,
+ final ProjectInfo info,
+ final Feature assembledFeature,
+ final String scope) {
+ for(final Map.Entry<Integer, org.apache.sling.feature.Artifact> entry : assembledFeature.getBundles()) {
+ final ArtifactId a = entry.getValue().getId();
+ if ( a.getGroupId().equals(info.project.getGroupId())
+ && a.getArtifactId().equals(info.project.getArtifactId())
+ && a.getVersion().equals(info.project.getVersion()) ) {
+ // skip artifact from the same project
+ env.logger.debug("- skipping dependency " + a.toMvnId());
+ continue;
+ }
+
+ env.logger.debug("- adding dependency " + a.toMvnId());
+ final Dependency dep = ProjectHelper.toDependency(a, scope);
+ info.project.getDependencies().add(dep);
+ }
+ for(final Extension ext : assembledFeature.getExtensions()) {
+ if ( ext.getType() != ExtensionType.ARTIFACTS ) {
+ continue;
+ }
+ for(final org.apache.sling.feature.Artifact art : ext.getArtifacts()) {
+ final ArtifactId a = art.getId();
+ if ( a.getGroupId().equals(info.project.getGroupId())
+ && a.getArtifactId().equals(info.project.getArtifactId())
+ && a.getVersion().equals(info.project.getVersion()) ) {
+ // skip artifact from the same project
+ env.logger.debug("- skipping dependency " + a.toMvnId());
+ continue;
+ }
+ env.logger.debug("- adding dependency " + a.toMvnId());
+ final Dependency dep = ProjectHelper.toDependency(a, scope);
+ info.project.getDependencies().add(dep);
+ }
+ }
+ }
+
+ /**
+ * Read the feature for a feature project.
+ * The feature is either inlined in the pom or stored in a file in the project.
+ *
+ * @param logger The logger
+ * @param project The current maven project
+ * @param config The configuration
+ * @return The feature or {@code null}
+ */
+ protected Feature readProjectFeature(
+ final Logger logger,
+ final MavenProject project,
+ final FeatureProjectConfig config) {
+ final File featureFile = new File(project.getBasedir(), config.getFeatureFileName());
+ logger.debug("Checking feature file " + config.getFeatureFileName() + " : " + featureFile.exists());
+ logger.debug("Inlined feature : " + (config.getInlinedFeature() != null));
+
+ if ( config.getInlinedFeature() != null && featureFile.exists() ) {
+ throw new RuntimeException("Only one (feature file or inlined feature) can be specified - but not both");
+ }
+
+ final String classifier;
+ if ( config.isTestConfig() ) {
+ classifier = FeatureConstants.CLASSIFIER_TEST_FEATURE;
+ } else if ( FeatureConstants.PACKAGING_FEATURE.equals(project.getPackaging()) ) {
+ classifier = null;
+ } else {
+ classifier = FeatureConstants.CLASSIFIER_FEATURE;
+ }
+ final ArtifactId id = new ArtifactId(project.getGroupId(),
+ project.getArtifactId(),
+ project.getVersion(),
+ classifier,
+ FeatureConstants.PACKAGING_FEATURE);
+
+ final Feature feature;
+ if ( config.getInlinedFeature() != null ) {
+ logger.debug("Reading inlined model from project " + project.getId());
+ try (final Reader reader = new StringReader(config.getInlinedFeature())) {
+ feature = FeatureJSONReader.read(reader, id, null);
+ } catch ( final IOException io) {
+ throw new RuntimeException("Unable to read inlined feature", io);
+ }
+ } else {
+ if ( !featureFile.exists() ) {
+ logger.debug("Feature file " + featureFile + " in project " + project.getId() + " does not exist.");
+ return null;
+ }
+ logger.debug("Reading feature " + featureFile + " in project " + project.getId());
+ try (final FileReader reader = new FileReader(featureFile)) {
+ feature = FeatureJSONReader.read(reader, id, featureFile.getAbsolutePath());
+ } catch ( final IOException io) {
+ throw new RuntimeException("Unable to read feature " + featureFile, io);
+ }
+ }
+ this.checkFeatureId(id, feature);
+
+ this.setProjectInfo(project, feature);
+
+ // post process and return
+ return postProcessReadFeature(feature);
+ }
+
+ private void checkFeatureId(final ArtifactId id, final Feature feature) {
+ // check feature id
+ if ( !id.getGroupId().equals(feature.getId().getGroupId()) ) {
+ throw new RuntimeException("Wrong group id for feature. It should be " + id.getGroupId() + " but is " + feature.getId().getGroupId());
+ }
+ if ( !id.getArtifactId().equals(feature.getId().getArtifactId()) ) {
+ throw new RuntimeException("Wrong artifact id for feature. It should be " + id.getArtifactId() + " but is " + feature.getId().getArtifactId());
+ }
+ if ( !id.getVersion().equals(feature.getId().getVersion()) ) {
+ throw new RuntimeException("Wrong version for feature. It should be " + id.getVersion() + " but is " + feature.getId().getVersion());
+ }
+ }
+
+ /**
+ * Hook to post process the local feature
+ * @param result The read feature
+ * @return The post processed feature
+ */
+ protected Feature postProcessReadFeature(final Feature result) {
+ return result;
+ }
+
+ protected void setProjectInfo(final MavenProject project, final Feature feature) {
+ // set title, description, vendor, license
+ if ( feature.getTitle() == null ) {
+ feature.setTitle(project.getName());
+ }
+ if ( feature.getDescription() == null ) {
+ feature.setDescription(project.getDescription());
+ }
+ if ( feature.getVendor() == null && project.getOrganization() != null ) {
+ feature.setVendor(project.getOrganization().getName());
+ }
+ if ( feature.getLicense() == null
+ && project.getLicenses() != null
+ && !project.getLicenses().isEmpty()) {
+ final String license = project.getLicenses().stream()
+ .filter(l -> l.getName() != null )
+ .map(l -> l.getName())
+ .collect(Collectors.joining(", "));
+
+ feature.setLicense(license);
+ }
+ }
+
+ protected FeatureProvider createFeatureProvider(final Environment env,
+ final ProjectInfo info,
+ final boolean isTest,
+ final boolean skipAddDependencies,
+ final String dependencyScope,
+ final List<Feature> projectFeatures) {
+ return new FeatureProvider() {
+
+ @Override
+ public Feature provide(final ArtifactId id) {
+
+ final Dependency dep = ProjectHelper.toDependency(id, dependencyScope);
+ if ( !skipAddDependencies ) {
+
+ env.logger.debug("- adding feature dependency " + id.toMvnId());
+ info.project.getDependencies().add(dep);
+ }
+
+ // if it's a project from the current reactor build, we can't resolve it right now
+ final String key = id.getGroupId() + ":" + id.getArtifactId();
+ final ProjectInfo depProjectInfo = env.modelProjects.get(key);
+ if ( depProjectInfo != null ) {
+ env.logger.debug("Found reactor " + id.getType() + " dependency to project: " + id);
+ // check if it is a feature project
+ if ( depProjectInfo instanceof FeatureProjectInfo ) {
+ final FeatureProjectInfo depInfo = (FeatureProjectInfo)depProjectInfo;
+ if ( isTest ) {
+ process(env, depInfo, FeatureProjectConfig.getTestConfig(depInfo));
+ } else {
+ process(env, depInfo, FeatureProjectConfig.getMainConfig(depInfo));
+ }
+ if ( isTest && depInfo.assembledTestFeature == null ) {
+ env.logger.error("Unable to get feature " + id.toMvnId() + " : Recursive test feature dependency list including project " + info.project);
+ } else if ( !isTest && depInfo.assembledFeature == null ) {
+ env.logger.error("Unable to get feature " + id.toMvnId() + " : Recursive feature dependency list including project " + info.project);
+ } else {
+
+ if ( isTest ) {
+ return depInfo.testFeature;
+ } else {
+ return depInfo.feature;
+ }
+ }
+ } else {
+ // we only support a dependency to *this* application project
+ final ApplicationProjectInfo depInfo = (ApplicationProjectInfo)depProjectInfo;
+ if ( depInfo != info) {
+ env.logger.error("Unable to get feature " + id.toMvnId() + " : Feature dependency is to a different application project from " + info.project);
+ return null;
+ }
+ if ( projectFeatures != null ) {
+ for(final Feature f : projectFeatures) {
+ if ( f.getId().equals(id)) {
+ return f;
+ }
+ }
+ }
+ return null;
+ }
+ } else {
+ env.logger.debug("Found external " + id.getType() + " dependency: " + id);
+
+ // "external" dependency, we can already resolve it
+ final File featureFile = ProjectHelper.getOrResolveArtifact(info.project, env.session, env.artifactHandlerManager, env.resolver, id).getFile();
+ try (final FileReader r = new FileReader(featureFile)) {
+ return FeatureJSONReader.read(r, featureFile.getAbsolutePath());
+ } catch ( final IOException ioe) {
+ env.logger.error("Unable to read feature file from " + featureFile, ioe);
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java b/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
new file mode 100644
index 0000000..a314113
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/ProjectHelper.java
@@ -0,0 +1,319 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.project.MavenProject;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.support.json.FeatureJSONReader;
+import org.apache.sling.feature.support.json.FeatureJSONWriter;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public abstract class ProjectHelper {
+
+ /** Read feature. */
+ private static final String RAW_FEATURE_JSON = Feature.class.getName() + "/rawmain.json";
+ private static final String RAW_TEST_FEATURE_JSON = Feature.class.getName() + "/rawtest.json";
+
+ /** Assembled feature. */
+ private static final String ASSEMBLED_FEATURE_JSON = Feature.class.getName() + "/assembledmain.json";
+ private static final String ASSEMBLED_TEST_FEATURE_JSON = Feature.class.getName() + "/assembledtest.json";
+
+ private static void store(final MavenProject project, final String key, final Feature feature) {
+ if ( feature != null ) {
+ // we have to serialize as the dependency lifecycle participant uses a different class loader (!)
+ try ( final StringWriter w1 = new StringWriter() ) {
+ FeatureJSONWriter.write(w1, feature);
+ project.setContextValue(key, w1.toString());
+ } catch ( final IOException ioe) {
+ throw new RuntimeException(ioe.getMessage(), ioe);
+ }
+ }
+ }
+
+ private static void store(final MavenProject project, final String key, final List<Feature> features) {
+ if ( features != null && !features.isEmpty()) {
+ project.setContextValue(key, features.size());
+ // we have to serialize as the dependency lifecycle participant uses a different class loader (!)
+ int index = 0;
+ for(final Feature f : features) {
+ try ( final StringWriter w1 = new StringWriter() ) {
+ FeatureJSONWriter.write(w1, f);
+ project.setContextValue(key + "_" + String.valueOf(index), w1.toString());
+ index++;
+ } catch ( final IOException ioe) {
+ throw new RuntimeException(ioe.getMessage(), ioe);
+ }
+ }
+ }
+ }
+
+ private static Feature getFeature(final MavenProject project, final String key) {
+ final String cacheKey = key + "-cache";
+ Feature result = null;
+ try {
+ result = (Feature) project.getContextValue(cacheKey);
+ } catch ( final Exception e) {
+ // if we get a class cast exception, we read again
+ }
+ if ( result == null ) {
+ final String text = (String)project.getContextValue(key);
+ if ( text == null ) {
+ result = null;
+ } else {
+ try ( final StringReader r = new StringReader(text) ) {
+ result = FeatureJSONReader.read(r, project.getId());
+ project.setContextValue(cacheKey, result);
+ } catch ( final IOException ioe) {
+ throw new RuntimeException(ioe.getMessage(), ioe);
+ }
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static List<Feature> getFeatures(final MavenProject project, final String key) {
+ final String cacheKey = key + "-cache";
+ List<Feature> result = null;
+ try {
+ result = (List<Feature>) project.getContextValue(cacheKey);
+ } catch ( final Exception e) {
+ // if we get a class cast exception, we read again
+ }
+ if ( result == null ) {
+ final Integer size = (Integer)project.getContextValue(key);
+ if ( size != null ) {
+ result = new ArrayList<>();
+ for(int i=0; i<size;i++) {
+ final String text = (String)project.getContextValue(key + "_" + String.valueOf(i));
+ if ( text == null ) {
+ throw new RuntimeException("Unable to get feature from internal store.");
+ }
+ try ( final StringReader r = new StringReader(text) ) {
+ final Feature feature = FeatureJSONReader.read(r, project.getId());
+ result.add(feature);
+ } catch ( final IOException ioe) {
+ throw new RuntimeException(ioe.getMessage(), ioe);
+ }
+ }
+ project.setContextValue(cacheKey, result);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Store all relevant information about the project for plugins to be
+ * retrieved
+ * @param info The project info
+ */
+ public static void storeProjectInfo(final FeatureProjectInfo info) {
+ store(info.project, RAW_FEATURE_JSON, info.feature);
+ store(info.project, RAW_TEST_FEATURE_JSON, info.testFeature);
+ store(info.project, ASSEMBLED_FEATURE_JSON, info.assembledFeature);
+ store(info.project, ASSEMBLED_TEST_FEATURE_JSON, info.assembledTestFeature);
+ }
+
+ /**
+ * Get the assembled feature from the project
+ * @param project The maven projet
+ * @return The assembled feature or {@code null}
+ */
+ public static Feature getAssembledFeature(final MavenProject project) {
+ return getFeature(project, ASSEMBLED_FEATURE_JSON);
+ }
+
+ /**
+ * Get the raw feature from the project
+ * @param project The maven projet
+ * @return The raw feature or {@code null}
+ */
+ public static Feature getFeature(final MavenProject project) {
+ return getFeature(project, RAW_FEATURE_JSON);
+ }
+
+ /**
+ * Get the assembled test feature from the project
+ * @param project The maven projet
+ * @return The assembled feature or {@code null}
+ */
+ public static Feature getAssembledTestFeature(final MavenProject project) {
+ return getFeature(project, ASSEMBLED_TEST_FEATURE_JSON);
+ }
+
+ /**
+ * Get the raw test feature from the project
+ * @param project The maven projet
+ * @return The raw feature or {@code null}
+ */
+ public static Feature getTestFeature(final MavenProject project) {
+ return getFeature(project, RAW_TEST_FEATURE_JSON);
+ }
+
+ /**
+ * Store all relevant information about the project for plugins to be
+ * retrieved
+ * @param info The project info
+ */
+ public static void storeProjectInfo(final ApplicationProjectInfo info) {
+ store(info.project, RAW_FEATURE_JSON, info.features);
+ store(info.project, RAW_TEST_FEATURE_JSON, info.testFeatures);
+ store(info.project, ASSEMBLED_FEATURE_JSON, info.assembledFeatures);
+ store(info.project, ASSEMBLED_TEST_FEATURE_JSON, info.assembledTestFeatures);
+ }
+
+ /**
+ * Get the assembled features from the project
+ * @param project The maven projet
+ * @return The assembled features or {@code null}
+ */
+ public static List<Feature> getAssembledFeatures(final MavenProject project) {
+ return getFeatures(project, ASSEMBLED_FEATURE_JSON);
+ }
+
+ /**
+ * Get the raw feature from the project
+ * @param project The maven projet
+ * @return The raw features or {@code null}
+ */
+ public static List<Feature> getFeatures(final MavenProject project) {
+ return getFeatures(project, RAW_FEATURE_JSON);
+ }
+
+ /**
+ * Get the assembled test feature from the project
+ * @param project The maven projet
+ * @return The assembled features or {@code null}
+ */
+ public static List<Feature> getAssembledTestFeatures(final MavenProject project) {
+ return getFeatures(project, ASSEMBLED_TEST_FEATURE_JSON);
+ }
+
+ /**
+ * Get the raw test feature from the project
+ * @param project The maven projet
+ * @return The raw features or {@code null}
+ */
+ public static List<Feature> getTestFeatures(final MavenProject project) {
+ return getFeatures(project, RAW_TEST_FEATURE_JSON);
+ }
+
+ /**
+ * Gets a configuration value for a plugin if it is set in the configuration for
+ * the plugin or any configuration for an execution of the plugin.
+ * @param plugin Plugin
+ * @param name Configuration parameter.
+ * @param defaultValue The default value if no configuration is found.
+ * @return The default value if nothing is configured, the value otherwise.
+ * @throws RuntimeException If more than one value is configured
+ */
+ public static String getConfigValue(final Plugin plugin,
+ final String name,
+ final String defaultValue) {
+ final Set<String> values = new HashSet<>();
+ final Xpp3Dom config = plugin == null ? null : (Xpp3Dom)plugin.getConfiguration();
+ final Xpp3Dom globalNode = (config == null ? null : config.getChild(name));
+ if ( globalNode != null ) {
+ values.add(globalNode.getValue());
+ }
+ for(final PluginExecution exec : plugin.getExecutions()) {
+ final Xpp3Dom cfg = (Xpp3Dom)exec.getConfiguration();
+ final Xpp3Dom pluginNode = (cfg == null ? null : cfg.getChild(name));
+ if ( pluginNode != null ) {
+ values.add(pluginNode.getValue());
+ }
+ }
+ if ( values.size() > 1 ) {
+ throw new RuntimeException("More than one value configured in plugin (executions) of "
+ + plugin.getKey() + " for " + name + " : " + values);
+ }
+ return values.isEmpty() ? defaultValue : values.iterator().next();
+ }
+
+ /**
+ * Get a resolved Artifact from the coordinates provided
+ *
+ * @return the artifact, which has been resolved.
+ */
+ public static Artifact getOrResolveArtifact(final MavenProject project,
+ final MavenSession session,
+ final ArtifactHandlerManager artifactHandlerManager,
+ final ArtifactResolver resolver,
+ final ArtifactId id) {
+ final Set<Artifact> artifacts = project.getDependencyArtifacts();
+ for(final Artifact artifact : artifacts) {
+ if ( artifact.getGroupId().equals(id.getGroupId())
+ && artifact.getArtifactId().equals(id.getArtifactId())
+ && artifact.getVersion().equals(id.getVersion())
+ && artifact.getType().equals(id.getVersion())
+ && ((id.getClassifier() == null && artifact.getClassifier() == null) || (id.getClassifier() != null && id.getClassifier().equals(artifact.getClassifier()))) ) {
+ return artifact;
+ }
+ }
+ final Artifact prjArtifact = new DefaultArtifact(id.getGroupId(),
+ id.getArtifactId(),
+ VersionRange.createFromVersion(id.getVersion()),
+ Artifact.SCOPE_PROVIDED,
+ id.getType(),
+ id.getClassifier(),
+ artifactHandlerManager.getArtifactHandler(id.getType()));
+ try {
+ resolver.resolve(prjArtifact, project.getRemoteArtifactRepositories(), session.getLocalRepository());
+ } catch (final ArtifactResolutionException | ArtifactNotFoundException e) {
+ throw new RuntimeException("Unable to get artifact for " + id.toMvnId(), e);
+ }
+ return prjArtifact;
+ }
+
+ public static String toString(final Dependency d) {
+ return "Dependency {groupId=" + d.getGroupId() + ", artifactId=" + d.getArtifactId() + ", version=" + d.getVersion() +
+ (d.getClassifier() != null ? ", classifier=" + d.getClassifier() : "") +
+ ", type=" + d.getType() + "}";
+ }
+
+ public static Dependency toDependency(final ArtifactId id, final String scope) {
+ final Dependency dep = new Dependency();
+ dep.setGroupId(id.getGroupId());
+ dep.setArtifactId(id.getArtifactId());
+ dep.setVersion(id.getVersion());
+ dep.setType(id.getType());
+ dep.setClassifier(id.getClassifier());
+ dep.setScope(scope);
+
+ return dep;
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java b/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java
new file mode 100644
index 0000000..6e3fa0d
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/ProjectInfo.java
@@ -0,0 +1,27 @@
+/*
+ * 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.maven;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+
+public class ProjectInfo {
+
+ public MavenProject project;
+ public Plugin plugin;
+}
+
diff --git a/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java b/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java
new file mode 100644
index 0000000..7c7e2ea
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AbstractFeatureMojo.java
@@ -0,0 +1,116 @@
+/*
+ * 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.maven.mojos;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.sling.feature.maven.FeatureProjectConfig;
+
+import java.io.File;
+
+/**
+ * Base class for all mojos.
+ */
+public abstract class AbstractFeatureMojo extends AbstractMojo {
+
+ /**
+ * The feature file..
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name = FeatureProjectConfig.CFG_FEATURE_FILE,
+ defaultValue="${basedir}/" + FeatureProjectConfig.DEFAULT_FEATURE_FILE)
+ private File featureFile;
+
+ /**
+ * The test feature file..
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name = FeatureProjectConfig.CFG_TEST_FEATURE_FILE,
+ defaultValue="${basedir}/" + FeatureProjectConfig.DEFAULT_TEST_FEATURE_FILE)
+ private File testFeatureFile;
+
+ /**
+ * Inlined model.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name = FeatureProjectConfig.CFG_FEATURE_INLINED)
+ private String feature;
+
+ /**
+ * Inlined test model.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name = FeatureProjectConfig.CFG_TEST_FEATURE_INLINED)
+ private String testFeature;
+
+ /**
+ * If set to {@code true} the artifacts from the feature are not as dependencies to the project.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name=FeatureProjectConfig.CFG_SKIP_ADD_FEATURE_DEPENDENCIES,
+ defaultValue="false")
+ private boolean skipAddFeatureDependencies;
+
+ /**
+ * If set to {@code true} the artifacts from the test feature are not as dependencies to the project.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name=FeatureProjectConfig.CFG_SKIP_ADD_TEST_FEATURE_DEPENDENCIES,
+ defaultValue="true")
+ private boolean skipAddTestFeatureDependencies;
+
+ /**
+ * If set to {@code true} the main jar artifact is not added to the feature.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name=FeatureProjectConfig.CFG_SKIP_ADD_JAR_TO_FEATURE,
+ defaultValue="false")
+ private boolean skipAddJarToFeature;
+
+ /**
+ * If set to {@code true} the main jar artifact is not added to the test feature.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name=FeatureProjectConfig.CFG_SKIP_ADD_JAR_TO_TEST_FEATURE,
+ defaultValue="false")
+ private boolean skipAddJarToTestFeature;
+
+ /**
+ * The start level for the attached jar/bundle.
+ * This parameter is evaluated in the {@link DependencyLifecycleParticipant}.
+ */
+ @Parameter(name=FeatureProjectConfig.CFG_JAR_START_LEVEL,
+ defaultValue=FeatureProjectConfig.DEFAULT_START_LEVEL)
+ private int jarStartLevel;
+
+ @Parameter(property = "project", readonly = true, required = true)
+ protected MavenProject project;
+
+ @Parameter(property = "session", readonly = true, required = true)
+ protected MavenSession mavenSession;
+
+ @Component
+ protected MavenProjectHelper projectHelper;
+
+ protected File getTmpDir() {
+ return new File(this.project.getBuild().getDirectory(), "osgifeature-tmp");
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java
new file mode 100644
index 0000000..79c5c23
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/AttachFeature.java
@@ -0,0 +1,77 @@
+/*
+ * 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.maven.mojos;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.maven.FeatureConstants;
+import org.apache.sling.feature.maven.ProjectHelper;
+import org.apache.sling.feature.support.json.FeatureJSONWriter;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Attach the feature as a project artifact.
+ */
+@Mojo(name = "attach-feature",
+ defaultPhase = LifecyclePhase.PACKAGE,
+ requiresDependencyResolution = ResolutionScope.TEST,
+ threadSafe = true
+ )
+public class AttachFeature extends AbstractFeatureMojo {
+
+ private void attach(final Feature feature,
+ final String artifactName,
+ final String classifier)
+ throws MojoExecutionException {
+ if ( feature != null ) {
+
+ // write the feature
+ final File outputFile = new File(this.project.getBuild().getDirectory() + File.separatorChar + artifactName);
+ outputFile.getParentFile().mkdirs();
+
+ try ( final Writer writer = new FileWriter(outputFile)) {
+ FeatureJSONWriter.write(writer, feature);
+ } catch (final IOException e) {
+ throw new MojoExecutionException("Unable to write feature to " + outputFile, e);
+ }
+
+ // if this project is a feature, it's the main artifact
+ if ( project.getPackaging().equals(FeatureConstants.PACKAGING_FEATURE)
+ && (FeatureConstants.CLASSIFIER_FEATURE.equals(classifier))) {
+ project.getArtifact().setFile(outputFile);
+ } else {
+ // otherwise attach it as an additional artifact
+ projectHelper.attachArtifact(project, FeatureConstants.PACKAGING_FEATURE,
+ classifier, outputFile);
+ }
+ }
+ }
+
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ attach(ProjectHelper.getFeature(this.project), FeatureConstants.FEATURE_ARTIFACT_NAME, FeatureConstants.CLASSIFIER_FEATURE);
+ attach(ProjectHelper.getTestFeature(this.project), FeatureConstants.TEST_FEATURE_ARTIFACT_NAME, FeatureConstants.CLASSIFIER_TEST_FEATURE);
+ }
+}
diff --git a/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java b/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
new file mode 100644
index 0000000..ba53623
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/DependencyLifecycleParticipant.java
@@ -0,0 +1,89 @@
+/*
+ * 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.maven.mojos;
+
+import org.apache.maven.AbstractMavenLifecycleParticipant;
+import org.apache.maven.MavenExecutionException;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.sling.feature.maven.ApplicationProjectInfo;
+import org.apache.sling.feature.maven.Environment;
+import org.apache.sling.feature.maven.FeatureConstants;
+import org.apache.sling.feature.maven.FeatureProjectInfo;
+import org.apache.sling.feature.maven.Preprocessor;
+import org.apache.sling.feature.maven.ProjectInfo;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * Maven lifecycle participant which adds the artifacts of the model to the dependencies.
+ */
+@Component(role = AbstractMavenLifecycleParticipant.class)
+public class DependencyLifecycleParticipant extends AbstractMavenLifecycleParticipant {
+
+ /**
+ * The plugin ID consists of <code>groupId:artifactId</code>, see {@link Plugin#constructKey(String, String)}
+ */
+ private static final String PLUGIN_ID = "org.apache.sling:osgifeature-maven-plugin";
+
+ @Requirement
+ private Logger logger;
+
+ @Requirement
+ private ArtifactHandlerManager artifactHandlerManager;
+
+ /**
+ * Used to look up Artifacts in the remote repository.
+ *
+ */
+ @Requirement
+ private ArtifactResolver resolver;
+
+ @Override
+ public void afterProjectsRead(final MavenSession session) throws MavenExecutionException {
+ final Environment env = new Environment();
+ env.artifactHandlerManager = artifactHandlerManager;
+ env.resolver = resolver;
+ env.logger = logger;
+ env.session = session;
+
+ logger.debug("Searching for project using plugin '" + PLUGIN_ID + "'...");
+
+ for (final MavenProject project : session.getProjects()) {
+ // consider all projects where this plugin is configured
+ Plugin plugin = project.getPlugin(PLUGIN_ID);
+ if (plugin != null) {
+ logger.debug("Found project " + project.getId() + " using " + PLUGIN_ID);
+ final ProjectInfo info;
+ if ( FeatureConstants.PACKAGING_APPLICATION.equals(project.getPackaging()) ) {
+ info = new ApplicationProjectInfo();
+ } else {
+ info = new FeatureProjectInfo();
+ }
+ info.plugin = plugin;
+ info.project = project;
+ env.modelProjects.put(project.getGroupId() + ":" + project.getArtifactId(), info);
+ }
+ }
+
+ new Preprocessor().process(env);
+ }
+}
diff --git a/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
new file mode 100644
index 0000000..0f2b325
--- /dev/null
+++ b/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml
@@ -0,0 +1,32 @@
+<!--
+ 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.
+-->
+<lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <goals>
+ <goal>attach-feature</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <ignore/>
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+</lifecycleMappingMetadata>
diff --git a/src/main/resources/META-INF/plexus/components.xml b/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000..6933d3b
--- /dev/null
+++ b/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,103 @@
+<!--
+ 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.
+-->
+<component-set>
+ <components>
+ <component>
+ <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+ <role-hint>osgifeature</role-hint>
+ <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+ <configuration>
+ <lifecycles>
+ <lifecycle>
+ <id>default</id>
+ <phases>
+ <package>org.apache.sling:slingstart-maven-plugin:attach-slingfeature</package>
+ <install>org.apache.maven.plugins:maven-install-plugin:install</install>
+ <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+ </phases>
+ </lifecycle>
+ </lifecycles>
+ </configuration>
+ </component>
+ <component>
+ <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+ <role-hint>osgiapp</role-hint>
+ <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+ <configuration>
+ <lifecycles>
+ <lifecycle>
+ <id>default</id>
+ <phases>
+ <process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
+ <compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
+ <process-test-resources>
+ org.apache.maven.plugins:maven-resources-plugin:testResources,
+ </process-test-resources>
+ <test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
+ <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
+ <prepare-package>org.apache.sling:slingstart-maven-plugin:prepare-package</prepare-package>
+ <package>
+ org.apache.sling:slingstart-maven-plugin:attach-slingfeature,
+ org.apache.sling:slingstart-maven-plugin:package
+ </package>
+ <install>org.apache.maven.plugins:maven-install-plugin:install</install>
+ <deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+ </phases>
+ </lifecycle>
+ </lifecycles>
+ </configuration>
+ </component>
+ <component>
+ <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+ <role-hint>osgifeature</role-hint>
+ <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+ <configuration>
+ <type>osgifeature</type>
+ <includesDependencies>false</includesDependencies>
+ <language>json</language>
+ <extension>json</extension>
+ <addedToClasspath>false</addedToClasspath>
+ </configuration>
+ </component>
+ <component>
+ <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+ <role-hint>osgiapp</role-hint>
+ <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+ <configuration>
+ <type>osgiapp</type>
+ <includesDependencies>false</includesDependencies>
+ <language>java</language>
+ <extension>jar</extension>
+ <addedToClasspath>false</addedToClasspath>
+ </configuration>
+ </component>
+ <component>
+ <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+ <role-hint>osgijar</role-hint>
+ <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+ <configuration>
+ <type>osgijar</type>
+ <includesDependencies>false</includesDependencies>
+ <language>java</language>
+ <extension>zip</extension>
+ <addedToClasspath>false</addedToClasspath>
+ </configuration>
+ </component>
+ </components>
+</component-set>
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
new file mode 100644
index 0000000..bd08e61
--- /dev/null
+++ b/src/site/markdown/index.md
@@ -0,0 +1,6 @@
+OSGiMaven Plugin
+================
+
+Maven Plugin for OSGi Applications
+
+See [Goals](plugin-info.html) for a list of supported goals.
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..9abab11
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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>
+ <skin>
+ <groupId>org.apache.maven.skins</groupId>
+ <artifactId>maven-fluido-skin</artifactId>
+ <version>1.6</version>
+ </skin>
+ <body>
+ <menu name="Overview">
+ <item name="Introduction" href="index.html"/>
+ <item name="Goals" href="plugin-info.html"/>
+ </menu>
+ <menu ref="reports"/>
+ </body>
+</project>
--
To stop receiving notification emails like this one, please contact
davidb@apache.org.