You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2016/06/24 14:06:41 UTC

karaf git commit: [KARAF-884] Generate feature dependencies

Repository: karaf
Updated Branches:
  refs/heads/karaf-4.0.x 0a2adadd0 -> 2d96f9143


[KARAF-884] Generate feature dependencies

Currently, POMs containing feature dependencies (classifier "features"
and type "xml") produce features listing all the required bundles.
This patch causes feature generation to represent feature dependencies
using <feature/> elements instead.

As a side-effect, aggregate features produce a new aggregate feature
containing all the generated features.

Signed-off-by: Stephen Kitt <sk...@redhat.com>


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2d96f914
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2d96f914
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2d96f914

Branch: refs/heads/karaf-4.0.x
Commit: 2d96f914382423762f86c3432587510247beb955
Parents: 0a2adad
Author: Stephen Kitt <sk...@redhat.com>
Authored: Thu Jun 2 16:38:32 2016 +0200
Committer: Jean-Baptiste Onofr� <jb...@apache.org>
Committed: Fri Jun 24 15:28:46 2016 +0200

----------------------------------------------------------------------
 .../features/internal/model/Dependency.java     |  31 +++++
 .../src/it/test-aggregate-features/control.xml  |   5 +
 .../test-check-dependencies-failure/control.xml |   4 +
 .../src/it/test-check-dependencies/control.xml  |   4 +
 .../it/test-feature-dependencies/control.xml    |  34 ++++++
 .../dependencies-features/pom.xml               |  81 +++++++++++++
 .../dependency-bundle-a/pom.xml                 |  58 +++++++++
 .../src/main/java/test/A.java                   |  25 ++++
 .../dependency-bundle-b/pom.xml                 |  61 ++++++++++
 .../src/main/java/test/B.java                   |  25 ++++
 .../dependency-bundle-c/pom.xml                 |  54 +++++++++
 .../src/main/java/test/C.java                   |  25 ++++
 .../dependency-feature-a/pom.xml                |  67 +++++++++++
 .../dependency-feature-c/pom.xml                |  67 +++++++++++
 .../src/it/test-feature-dependencies/pom.xml    |  70 +++++++++++
 .../src/it/test-feature-dependencies/verify.bsh |  35 ++++++
 .../features/GenerateDescriptorMojo.java        | 118 +++++++++++++------
 17 files changed, 729 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
----------------------------------------------------------------------
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
index a0a3854..21b1667 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/Dependency.java
@@ -54,6 +54,15 @@ public class Dependency implements org.apache.karaf.features.Dependency {
     @XmlAttribute
     protected boolean dependency;
 
+    public Dependency() {
+        // Nothing to do
+    }
+
+    public Dependency(String name, String version) {
+        this.name = name;
+        this.version = version;
+    }
+
     /**
      * Feature name should be non empty string.
      *
@@ -120,4 +129,26 @@ public class Dependency implements org.apache.karaf.features.Dependency {
         return getName() + Feature.VERSION_SEPARATOR + getVersion();
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Dependency that = (Dependency) o;
+
+        if (prerequisite != that.prerequisite) return false;
+        if (dependency != that.dependency) return false;
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+        return version != null ? version.equals(that.version) : that.version == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (version != null ? version.hashCode() : 0);
+        result = 31 * result + (prerequisite ? 1 : 0);
+        result = 31 * result + (dependency ? 1 : 0);
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-aggregate-features/control.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-aggregate-features/control.xml b/tooling/karaf-maven-plugin/src/it/test-aggregate-features/control.xml
index aaf7e5b..81e1844 100644
--- a/tooling/karaf-maven-plugin/src/it/test-aggregate-features/control.xml
+++ b/tooling/karaf-maven-plugin/src/it/test-aggregate-features/control.xml
@@ -29,4 +29,9 @@
         <bundle>mvn:test/aggregate-recursive-module-c/1.0-SNAPSHOT</bundle>
         <bundle>mvn:test/aggregate-recursive-module-b/1.0-SNAPSHOT</bundle>
     </feature>
+    <feature name="aggregate-features" description="aggregate-features" version="1.0.0.SNAPSHOT">
+        <details>Test Description</details>
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">aggregate-recursive-module-c</feature>
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">aggregate-recursive-module-d</feature>
+    </feature>
 </features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-check-dependencies-failure/control.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-check-dependencies-failure/control.xml b/tooling/karaf-maven-plugin/src/it/test-check-dependencies-failure/control.xml
index cf5aaa6..9e7ef4e 100644
--- a/tooling/karaf-maven-plugin/src/it/test-check-dependencies-failure/control.xml
+++ b/tooling/karaf-maven-plugin/src/it/test-check-dependencies-failure/control.xml
@@ -28,4 +28,8 @@
         <bundle>mvn:test/dependency-module-a/1.0-SNAPSHOT</bundle>
         <bundle>mvn:test/dependency-module-b/1.0-SNAPSHOT</bundle>
     </feature>
+    <feature name="check-dependencies-features" description="check-dependencies-features" version="1.0.0.SNAPSHOT">
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-module-c</feature>
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-module-d</feature>
+    </feature>
 </features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-check-dependencies/control.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-check-dependencies/control.xml b/tooling/karaf-maven-plugin/src/it/test-check-dependencies/control.xml
index cf5aaa6..9e7ef4e 100644
--- a/tooling/karaf-maven-plugin/src/it/test-check-dependencies/control.xml
+++ b/tooling/karaf-maven-plugin/src/it/test-check-dependencies/control.xml
@@ -28,4 +28,8 @@
         <bundle>mvn:test/dependency-module-a/1.0-SNAPSHOT</bundle>
         <bundle>mvn:test/dependency-module-b/1.0-SNAPSHOT</bundle>
     </feature>
+    <feature name="check-dependencies-features" description="check-dependencies-features" version="1.0.0.SNAPSHOT">
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-module-c</feature>
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-module-d</feature>
+    </feature>
 </features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/control.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/control.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/control.xml
new file mode 100644
index 0000000..d0f9b53
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/control.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="dependencies-features">
+    <feature name="dependency-feature-a" description="dependency-feature-a" version="1.0.0.SNAPSHOT">
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-feature-c</feature>
+        <bundle>mvn:test/dependency-bundle-a/1.0-SNAPSHOT</bundle>
+        <bundle>mvn:test/dependency-bundle-b/1.0-SNAPSHOT</bundle>
+    </feature>
+    <feature name="dependency-feature-c" description="dependency-feature-c" version="1.0.0.SNAPSHOT">
+        <bundle>mvn:test/dependency-bundle-c/1.0-SNAPSHOT</bundle>
+    </feature>
+    <feature name="dependencies-features" description="dependencies-features" version="1.0.0.SNAPSHOT">
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-feature-a</feature>
+        <feature version="1.0.0.SNAPSHOT" prerequisite="false" dependency="false">dependency-feature-c</feature>
+    </feature>
+</features>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependencies-features/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependencies-features/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependencies-features/pom.xml
new file mode 100644
index 0000000..3b232ab
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependencies-features/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependencies-features</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <packaging>feature</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-feature-a</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-feature-c</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>@pom.version@</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>generate-features-file</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>features-generate-descriptor</goal>
+                        </goals>
+                        <configuration>
+                            <aggregateFeatures>true</aggregateFeatures>
+                            <checkDependencyChange>true</checkDependencyChange>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/pom.xml
new file mode 100644
index 0000000..4498f53
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependency-bundle-a</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-bundle-b</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.7</version>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/src/main/java/test/A.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/src/main/java/test/A.java b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/src/main/java/test/A.java
new file mode 100644
index 0000000..9aa5496
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-a/src/main/java/test/A.java
@@ -0,0 +1,25 @@
+/*
+ * 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 test.a;
+
+public class A
+{
+    public static String ASTRING = "A-string";
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/pom.xml
new file mode 100644
index 0000000..b1c465c
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependency-bundle-b</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <packaging>bundle</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-feature-c</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.7</version>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/src/main/java/test/B.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/src/main/java/test/B.java b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/src/main/java/test/B.java
new file mode 100644
index 0000000..b66ddea
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-b/src/main/java/test/B.java
@@ -0,0 +1,25 @@
+/*
+ * 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 test.b;
+
+public class B
+{
+    public static String BSTRING = "B-string";
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/pom.xml
new file mode 100644
index 0000000..797b1e4
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependency-bundle-c</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <packaging>bundle</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.7</version>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/src/main/java/test/C.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/src/main/java/test/C.java b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/src/main/java/test/C.java
new file mode 100644
index 0000000..ad36cd8
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-bundle-c/src/main/java/test/C.java
@@ -0,0 +1,25 @@
+/*
+ * 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 test.c;
+
+public class C
+{
+    public static String CSTRING = "C-string";
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-a/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-a/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-a/pom.xml
new file mode 100644
index 0000000..d11c7ee
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-a/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependency-feature-a</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-bundle-a</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>@pom.version@</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>generate-features-file</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>features-generate-descriptor</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-c/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-c/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-c/pom.xml
new file mode 100644
index 0000000..6717450
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/dependency-feature-c/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+  ~ 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>test</groupId>
+        <artifactId>test-feature-dependencies</artifactId>
+        <version>1.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>test</groupId>
+    <artifactId>dependency-feature-c</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>test</groupId>
+            <artifactId>dependency-bundle-c</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>@pom.version@</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>generate-features-file</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>features-generate-descriptor</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/pom.xml b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/pom.xml
new file mode 100644
index 0000000..143f0c7
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>test</groupId>
+    <artifactId>test-feature-dependencies</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <!-- Feature A contains bundle A, which depends on bundle B, which depends on feature C containing bundle C -->
+
+    <modules>
+        <module>dependency-feature-a</module>
+        <module>dependency-bundle-a</module>
+        <module>dependency-bundle-b</module>
+        <module>dependency-feature-c</module>
+        <module>dependency-bundle-c</module>
+        <module>dependencies-features</module>
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>@pom.version@</version>
+                <executions>
+                    <execution>
+                        <id>generate-features-file</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>features-generate-descriptor</goal>
+                        </goals>
+                        <configuration>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/verify.bsh
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/verify.bsh b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/verify.bsh
new file mode 100644
index 0000000..c551535
--- /dev/null
+++ b/tooling/karaf-maven-plugin/src/it/test-feature-dependencies/verify.bsh
@@ -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.
+ */
+
+import org.custommonkey.xmlunit.*;
+import java.io.*;
+import java.lang.*;
+
+Reader r = new FileReader(new File(basedir, "control.xml"));
+
+// load the features file pushed to the repository
+File generated = new File(basedir, "dependencies-features/target/feature/feature.xml" );
+if (generated.exists()) {
+    try {
+        XMLAssert.assertXMLEqual(r, new FileReader(generated));
+        return true;
+    } catch (Throwable ignored) { }
+}
+
+return false;

http://git-wip-us.apache.org/repos/asf/karaf/blob/2d96f914/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
index df27aa6..a738bad 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
@@ -56,6 +56,7 @@ import org.apache.karaf.tooling.utils.DependencyHelper;
 import org.apache.karaf.tooling.utils.DependencyHelperFactory;
 import org.apache.karaf.tooling.utils.LocalDependency;
 import org.apache.karaf.tooling.utils.ManifestUtils;
+import org.apache.karaf.tooling.utils.MavenUtil;
 import org.apache.karaf.tooling.utils.MojoSupport;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
@@ -82,6 +83,7 @@ import org.apache.maven.shared.filtering.MavenResourcesFiltering;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.StringUtils;
+import org.eclipse.aether.artifact.DefaultArtifact;
 import org.xml.sax.SAXException;
 
 /**
@@ -408,6 +410,10 @@ public class GenerateDescriptorMojo extends MojoSupport {
             feature.getBundle().add(bundle);
         }
         boolean needWrap = false;
+
+        // First pass to look for features
+        // Track other features we depend on
+        Map<Dependency, Feature> otherFeatures = new HashMap<>();
         for (final LocalDependency entry : localDependencies) {
             Object artifact = entry.getArtifact();
 
@@ -415,45 +421,48 @@ public class GenerateDescriptorMojo extends MojoSupport {
                 continue;
             }
 
-            if (this.dependencyHelper.isArtifactAFeature(artifact)) {
-                if (aggregateFeatures && FEATURE_CLASSIFIER.equals(this.dependencyHelper.getClassifier(artifact))) {
-                    File featuresFile = this.dependencyHelper.resolve(artifact, getLog());
-                    if (featuresFile == null || !featuresFile.exists()) {
-                        throw new MojoExecutionException("Cannot locate file for feature: " + artifact + " at " + featuresFile);
-                    }
-                    Features includedFeatures = readFeaturesFile(featuresFile);
-                    //TODO check for duplicates?
-                    features.getFeature().addAll(includedFeatures.getFeature());
-                }
-            } else if (addBundlesToPrimaryFeature) {
-                String bundleName = this.dependencyHelper.artifactToMvn(artifact, getVersionOrRange(entry.getParent(), artifact));
-                File bundleFile = this.dependencyHelper.resolve(artifact, getLog());
-                Manifest manifest = getManifest(bundleFile);
-
-                if (manifest == null || !ManifestUtils.isBundle(getManifest(bundleFile))) {
-                    bundleName = "wrap:" + bundleName;
-                    needWrap = true;
+            processFeatureArtifact(features, feature, otherFeatures, artifact, entry.getParent(), true);
+        }
+
+        // Second pass to look for bundles
+        if (addBundlesToPrimaryFeature) {
+            for (final LocalDependency entry : localDependencies) {
+                Object artifact = entry.getArtifact();
+
+                if (excludedArtifactIds.contains(this.dependencyHelper.getArtifactId(artifact))) {
+                    continue;
                 }
 
-                Bundle bundle = null;
-                for (Bundle b : feature.getBundle()) {
-                    if (bundleName.equals(b.getLocation())) {
-                        bundle = b;
-                        break;
+                if (!this.dependencyHelper.isArtifactAFeature(artifact)) {
+                    String bundleName = this.dependencyHelper.artifactToMvn(artifact, getVersionOrRange(entry.getParent(), artifact));
+                    File bundleFile = this.dependencyHelper.resolve(artifact, getLog());
+                    Manifest manifest = getManifest(bundleFile);
+
+                    if (manifest == null || !ManifestUtils.isBundle(getManifest(bundleFile))) {
+                        bundleName = "wrap:" + bundleName;
+                        needWrap = true;
                     }
-                }
-                if (bundle == null) {
-                    bundle = objectFactory.createBundle();
-                    bundle.setLocation(bundleName);
-                    if (!"provided".equals(entry.getScope()) || !ignoreScopeProvided) {
-                        feature.getBundle().add(bundle);
+
+                    Bundle bundle = null;
+                    for (Bundle b : feature.getBundle()) {
+                        if (bundleName.equals(b.getLocation())) {
+                            bundle = b;
+                            break;
+                        }
+                    }
+                    if (bundle == null) {
+                        bundle = objectFactory.createBundle();
+                        bundle.setLocation(bundleName);
+                        if (!"provided".equals(entry.getScope()) || !ignoreScopeProvided) {
+                            feature.getBundle().add(bundle);
+                        }
+                    }
+                    if ("runtime".equals(entry.getScope())) {
+                        bundle.setDependency(true);
+                    }
+                    if (startLevel != null && bundle.getStartLevel() == 0) {
+                        bundle.setStartLevel(startLevel);
                     }
-                }
-                if ("runtime".equals(entry.getScope())) {
-                    bundle.setDependency(true);
-                }
-                if (startLevel != null && bundle.getStartLevel() == 0) {
-                    bundle.setStartLevel(startLevel);
                 }
             }
         }
@@ -479,6 +488,45 @@ public class GenerateDescriptorMojo extends MojoSupport {
         getLog().info("...done!");
     }
 
+    private void processFeatureArtifact(Features features, Feature feature, Map<Dependency, Feature> otherFeatures,
+                                        Object artifact, Object parent, boolean add)
+            throws MojoExecutionException, XMLStreamException, JAXBException, IOException {
+        if (this.dependencyHelper.isArtifactAFeature(artifact) && FEATURE_CLASSIFIER.equals(
+                this.dependencyHelper.getClassifier(artifact))) {
+            File featuresFile = this.dependencyHelper.resolve(artifact, getLog());
+            if (featuresFile == null || !featuresFile.exists()) {
+                throw new MojoExecutionException(
+                        "Cannot locate file for feature: " + artifact + " at " + featuresFile);
+            }
+            Features includedFeatures = readFeaturesFile(featuresFile);
+            for (String repository : includedFeatures.getRepository()) {
+                processFeatureArtifact(features, feature, otherFeatures,
+                        new DefaultArtifact(MavenUtil.mvnToAether(repository)), parent, false);
+            }
+            for (Feature includedFeature : includedFeatures.getFeature()) {
+                Dependency dependency = new Dependency(includedFeature.getName(), includedFeature.getVersion());
+                // We musn't de-duplicate here, we may have seen a feature in !add mode
+                otherFeatures.put(dependency, includedFeature);
+                if (add) {
+                    if (!feature.getFeature().contains(dependency)) {
+                        feature.getFeature().add(dependency);
+                    }
+                    if (aggregateFeatures) {
+                        if (!features.getFeature().contains(includedFeature)) {
+                            features.getFeature().add(includedFeature);
+                        }
+                    } else {
+                        // Add the feature to the repositories, if it isn't already there
+                        String mvn = this.dependencyHelper.artifactToMvn(artifact, getVersionOrRange(parent, artifact));
+                        if (!features.getRepository().contains(mvn)) {
+                            features.getRepository().add(mvn);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Extract the MANIFEST from the give file.
      */