You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/11 19:20:54 UTC

[32/33] git commit: Revert "[KARAF-2852] Merge features/core and features/command"

Revert "[KARAF-2852] Merge features/core and features/command"

This reverts commit 999f4970fecd3710da36b709f2d484cd0db38d09.

We actually need to split the commands from the core service
in order to avoid a refresh when the shell is installed.


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

Branch: refs/heads/master
Commit: 0c8e8a81e9d8103013f986604c5e840fe32cef5a
Parents: f2669e1
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 19:01:02 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:04 2014 +0200

----------------------------------------------------------------------
 assemblies/apache-karaf/pom.xml                 |    2 +-
 .../standard/src/main/feature/feature.xml       |    1 +
 features/command/NOTICE                         |   71 +
 features/command/pom.xml                        |   90 ++
 .../command/FeaturesCommandSupport.java         |   42 +
 .../features/command/InfoFeatureCommand.java    |  290 ++++
 .../features/command/InstallFeatureCommand.java |   69 +
 .../command/ListFeatureVersionsCommand.java     |   62 +
 .../features/command/ListFeaturesCommand.java   |  106 ++
 .../karaf/features/command/RepoAddCommand.java  |   54 +
 .../karaf/features/command/RepoListCommand.java |   73 +
 .../features/command/RepoRefreshCommand.java    |   65 +
 .../features/command/RepoRemoveCommand.java     |   56 +
 .../command/UninstallFeatureCommand.java        |   62 +
 .../command/completers/AllFeatureCompleter.java |   33 +
 .../completers/AvailableFeatureCompleter.java   |   33 +
 .../completers/AvailableRepoNameCompleter.java  |   48 +
 .../completers/FeatureCompleterSupport.java     |   65 +
 .../completers/InstalledRepoNameCompleter.java  |   58 +
 .../completers/InstalledRepoUriCompleter.java   |   59 +
 .../completers/RequiredFeatureCompleter.java    |   33 +
 .../src/main/resources/OSGI-INF/bundle.info     |   30 +
 features/core/NOTICE                            |   71 +
 features/core/pom.xml                           |  141 ++
 .../org/apache/karaf/features/BootFinished.java |   24 +
 .../org/apache/karaf/features/BundleInfo.java   |   32 +
 .../org/apache/karaf/features/Capability.java   |   23 +
 .../org/apache/karaf/features/Conditional.java  |   35 +
 .../apache/karaf/features/ConfigFileInfo.java   |   27 +
 .../org/apache/karaf/features/Dependency.java   |   29 +
 .../apache/karaf/features/EventConstants.java   |   46 +
 .../java/org/apache/karaf/features/Feature.java |   63 +
 .../org/apache/karaf/features/FeatureEvent.java |   50 +
 .../apache/karaf/features/FeaturesListener.java |   25 +
 .../karaf/features/FeaturesNamespaces.java      |   41 +
 .../apache/karaf/features/FeaturesService.java  |  104 ++
 .../karaf/features/RegionsPersistence.java      |   26 +
 .../org/apache/karaf/features/Repository.java   |   37 +
 .../apache/karaf/features/RepositoryEvent.java  |   50 +
 .../org/apache/karaf/features/Requirement.java  |   23 +
 .../org/apache/karaf/features/Resolver.java     |   25 +
 .../internal/deployment/DeploymentBuilder.java  |  354 +++++
 .../internal/deployment/Downloader.java         |   35 +
 .../internal/deployment/StreamProvider.java     |   26 +
 .../management/FeaturesServiceMBeanImpl.java    |  290 ++++
 .../management/StandardEmitterMBean.java        |   65 +
 .../karaf/features/internal/model/Bundle.java   |  198 +++
 .../features/internal/model/Capability.java     |   91 ++
 .../features/internal/model/Conditional.java    |   69 +
 .../karaf/features/internal/model/Config.java   |  110 ++
 .../features/internal/model/ConfigFile.java     |  136 ++
 .../karaf/features/internal/model/Content.java  |  199 +++
 .../features/internal/model/Dependency.java     |  121 ++
 .../karaf/features/internal/model/Feature.java  |  374 +++++
 .../karaf/features/internal/model/Features.java |  155 ++
 .../karaf/features/internal/model/JaxbUtil.java |  224 +++
 .../features/internal/model/ObjectFactory.java  |  111 ++
 .../features/internal/model/Requirement.java    |   87 ++
 .../features/internal/model/package-info.java   |   21 +
 .../karaf/features/internal/osgi/Activator.java |  208 +++
 .../repository/AggregateRepository.java         |   55 +
 .../internal/repository/BaseRepository.java     |   86 ++
 .../internal/repository/CacheRepository.java    |   59 +
 .../repository/HttpMetadataProvider.java        |   88 ++
 .../internal/repository/MetadataProvider.java   |   29 +
 .../internal/repository/MetadataRepository.java |   43 +
 .../internal/repository/StaticRepository.java   |   33 +
 .../features/internal/resolver/BaseClause.java  |  114 ++
 .../internal/resolver/CandidateComparator.java  |  129 ++
 .../internal/resolver/CapabilityImpl.java       |  165 ++
 .../internal/resolver/CapabilitySet.java        |  612 ++++++++
 .../internal/resolver/FeatureNamespace.java     |   72 +
 .../internal/resolver/FeatureResource.java      |  133 ++
 .../internal/resolver/IdentityCapability.java   |   63 +
 .../internal/resolver/RequirementImpl.java      |   80 +
 .../internal/resolver/ResolveContextImpl.java   |  102 ++
 .../internal/resolver/ResourceBuilder.java      | 1129 ++++++++++++++
 .../internal/resolver/ResourceImpl.java         |  110 ++
 .../internal/resolver/ServiceNamespace.java     |   30 +
 .../internal/resolver/SimpleFilter.java         |  649 ++++++++
 .../internal/resolver/Slf4jResolverLog.java     |   49 +
 .../internal/resolver/UriNamespace.java         |   47 +
 .../features/internal/service/Artifact.java     |   56 +
 .../internal/service/BootFeaturesInstaller.java |  171 +++
 .../internal/service/EventAdminListener.java    |   91 ++
 .../service/FeatureConfigInstaller.java         |  167 +++
 .../internal/service/FeatureFinder.java         |   68 +
 .../internal/service/FeatureValidationUtil.java |   37 +
 .../internal/service/FeaturesServiceImpl.java   | 1416 ++++++++++++++++++
 .../features/internal/service/Overrides.java    |  132 ++
 .../internal/service/RepositoryImpl.java        |  102 ++
 .../internal/service/RequirementSort.java       |   84 ++
 .../internal/service/SimpleDownloader.java      |   51 +
 .../karaf/features/internal/service/State.java  |   34 +
 .../features/internal/service/StateStorage.java |  175 +++
 .../features/internal/util/ChecksumUtils.java   |   56 +
 .../features/internal/util/JsonReader.java      |  349 +++++
 .../features/internal/util/JsonWriter.java      |  120 ++
 .../karaf/features/internal/util/Macro.java     |  142 ++
 .../features/internal/util/MultiException.java  |   95 ++
 .../management/FeaturesServiceMBean.java        |  142 ++
 .../features/management/codec/JmxFeature.java   |  323 ++++
 .../management/codec/JmxFeatureEvent.java       |   80 +
 .../management/codec/JmxRepository.java         |  132 ++
 .../management/codec/JmxRepositoryEvent.java    |   77 +
 .../src/main/resources/OSGI-INF/bundle.info     |   20 +
 .../karaf/features/karaf-features-1.0.0.xsd     |  239 +++
 .../karaf/features/karaf-features-1.1.0.xsd     |  237 +++
 .../karaf/features/karaf-features-1.2.0.xsd     |  254 ++++
 .../karaf/features/karaf-features-1.3.0.xsd     |  280 ++++
 .../apache/karaf/features/ConditionalTest.java  |   54 +
 .../org/apache/karaf/features/FeatureTest.java  |   32 +
 .../karaf/features/FeaturesServiceTest.java     |  430 ++++++
 .../apache/karaf/features/RepositoryTest.java   |  140 ++
 .../org/apache/karaf/features/TestBase.java     |  105 ++
 .../service/BootFeaturesInstallerTest.java      |   93 ++
 .../internal/service/BundleManagerTest.java     |   64 +
 .../service/FeaturesServiceImplTest.java        |  167 +++
 .../service/FeaturesValidationTest.java         |  102 ++
 .../internal/service/OverridesTest.java         |  208 +++
 .../karaf/features/internal/service/f01.xml     |   92 ++
 .../karaf/features/internal/service/f02.xml     |  164 ++
 .../karaf/features/internal/service/f03.xml     |   27 +
 .../karaf/features/internal/service/f04.xml     |   28 +
 .../karaf/features/internal/service/f05.xml     |   28 +
 .../karaf/features/internal/service/f06.xml     |   36 +
 .../karaf/features/internal/service/f07.xml     |   35 +
 .../internal/service/overrides.properties       |   23 +
 .../karaf/features/internal/service/repo2.xml   |   41 +
 .../org/apache/karaf/features/repo1.xml         |   35 +
 .../org/apache/karaf/features/repo2.xml         |   37 +
 .../org/apache/karaf/features/repo3.xml         |   27 +
 features/pom.xml                                |  127 +-
 .../org/apache/karaf/features/BootFinished.java |   24 -
 .../org/apache/karaf/features/BundleInfo.java   |   32 -
 .../org/apache/karaf/features/Capability.java   |   23 -
 .../org/apache/karaf/features/Conditional.java  |   35 -
 .../apache/karaf/features/ConfigFileInfo.java   |   27 -
 .../org/apache/karaf/features/Dependency.java   |   29 -
 .../apache/karaf/features/EventConstants.java   |   46 -
 .../java/org/apache/karaf/features/Feature.java |   63 -
 .../org/apache/karaf/features/FeatureEvent.java |   50 -
 .../apache/karaf/features/FeaturesListener.java |   25 -
 .../karaf/features/FeaturesNamespaces.java      |   41 -
 .../apache/karaf/features/FeaturesService.java  |  104 --
 .../karaf/features/RegionsPersistence.java      |   26 -
 .../org/apache/karaf/features/Repository.java   |   37 -
 .../apache/karaf/features/RepositoryEvent.java  |   50 -
 .../org/apache/karaf/features/Requirement.java  |   23 -
 .../org/apache/karaf/features/Resolver.java     |   25 -
 .../command/FeaturesCommandSupport.java         |   42 -
 .../features/command/InfoFeatureCommand.java    |  290 ----
 .../features/command/InstallFeatureCommand.java |   69 -
 .../command/ListFeatureVersionsCommand.java     |   62 -
 .../features/command/ListFeaturesCommand.java   |  106 --
 .../karaf/features/command/RepoAddCommand.java  |   54 -
 .../karaf/features/command/RepoListCommand.java |   73 -
 .../features/command/RepoRefreshCommand.java    |   65 -
 .../features/command/RepoRemoveCommand.java     |   56 -
 .../command/UninstallFeatureCommand.java        |   62 -
 .../command/completers/AllFeatureCompleter.java |   33 -
 .../completers/AvailableFeatureCompleter.java   |   33 -
 .../completers/AvailableRepoNameCompleter.java  |   48 -
 .../completers/FeatureCompleterSupport.java     |   65 -
 .../completers/InstalledRepoNameCompleter.java  |   58 -
 .../completers/InstalledRepoUriCompleter.java   |   59 -
 .../completers/RequiredFeatureCompleter.java    |   33 -
 .../internal/deployment/DeploymentBuilder.java  |  354 -----
 .../internal/deployment/Downloader.java         |   35 -
 .../internal/deployment/StreamProvider.java     |   26 -
 .../management/FeaturesServiceMBeanImpl.java    |  290 ----
 .../management/StandardEmitterMBean.java        |   65 -
 .../karaf/features/internal/model/Bundle.java   |  198 ---
 .../features/internal/model/Capability.java     |   89 --
 .../features/internal/model/Conditional.java    |   69 -
 .../karaf/features/internal/model/Config.java   |  110 --
 .../features/internal/model/ConfigFile.java     |  136 --
 .../karaf/features/internal/model/Content.java  |  199 ---
 .../features/internal/model/Dependency.java     |  121 --
 .../karaf/features/internal/model/Feature.java  |  374 -----
 .../karaf/features/internal/model/Features.java |  155 --
 .../karaf/features/internal/model/JaxbUtil.java |  224 ---
 .../features/internal/model/ObjectFactory.java  |  111 --
 .../features/internal/model/Requirement.java    |   87 --
 .../features/internal/model/package-info.java   |   21 -
 .../karaf/features/internal/osgi/Activator.java |  208 ---
 .../repository/AggregateRepository.java         |   55 -
 .../internal/repository/BaseRepository.java     |   86 --
 .../internal/repository/CacheRepository.java    |   59 -
 .../repository/HttpMetadataProvider.java        |   88 --
 .../internal/repository/MetadataProvider.java   |   29 -
 .../internal/repository/MetadataRepository.java |   43 -
 .../internal/repository/StaticRepository.java   |   33 -
 .../features/internal/resolver/BaseClause.java  |  114 --
 .../internal/resolver/CandidateComparator.java  |  129 --
 .../internal/resolver/CapabilityImpl.java       |  165 --
 .../internal/resolver/CapabilitySet.java        |  612 --------
 .../internal/resolver/FeatureNamespace.java     |   72 -
 .../internal/resolver/FeatureResource.java      |  133 --
 .../internal/resolver/IdentityCapability.java   |   63 -
 .../internal/resolver/RequirementImpl.java      |   80 -
 .../internal/resolver/ResolveContextImpl.java   |  102 --
 .../internal/resolver/ResourceBuilder.java      | 1129 --------------
 .../internal/resolver/ResourceImpl.java         |  110 --
 .../internal/resolver/ServiceNamespace.java     |   30 -
 .../internal/resolver/SimpleFilter.java         |  649 --------
 .../internal/resolver/Slf4jResolverLog.java     |   49 -
 .../internal/resolver/UriNamespace.java         |   47 -
 .../features/internal/service/Artifact.java     |   56 -
 .../internal/service/BootFeaturesInstaller.java |  170 ---
 .../internal/service/EventAdminListener.java    |   91 --
 .../service/FeatureConfigInstaller.java         |  167 ---
 .../internal/service/FeatureFinder.java         |   68 -
 .../internal/service/FeatureValidationUtil.java |   37 -
 .../internal/service/FeaturesServiceImpl.java   | 1416 ------------------
 .../features/internal/service/Overrides.java    |  132 --
 .../internal/service/RepositoryImpl.java        |  102 --
 .../internal/service/RequirementSort.java       |   84 --
 .../internal/service/SimpleDownloader.java      |   51 -
 .../karaf/features/internal/service/State.java  |   34 -
 .../features/internal/service/StateStorage.java |  174 ---
 .../features/internal/util/ChecksumUtils.java   |   56 -
 .../features/internal/util/JsonReader.java      |  349 -----
 .../features/internal/util/JsonWriter.java      |  120 --
 .../karaf/features/internal/util/Macro.java     |  142 --
 .../features/internal/util/MultiException.java  |   95 --
 .../management/FeaturesServiceMBean.java        |  142 --
 .../features/management/codec/JmxFeature.java   |  323 ----
 .../management/codec/JmxFeatureEvent.java       |   80 -
 .../management/codec/JmxRepository.java         |  132 --
 .../management/codec/JmxRepositoryEvent.java    |   77 -
 .../src/main/resources/OSGI-INF/bundle.info     |   20 -
 .../karaf/features/karaf-features-1.0.0.xsd     |  239 ---
 .../karaf/features/karaf-features-1.1.0.xsd     |  237 ---
 .../karaf/features/karaf-features-1.2.0.xsd     |  254 ----
 .../karaf/features/karaf-features-1.3.0.xsd     |  280 ----
 .../apache/karaf/features/ConditionalTest.java  |   54 -
 .../org/apache/karaf/features/FeatureTest.java  |   32 -
 .../karaf/features/FeaturesServiceTest.java     |  429 ------
 .../apache/karaf/features/RepositoryTest.java   |  140 --
 .../org/apache/karaf/features/TestBase.java     |  105 --
 .../service/BootFeaturesInstallerTest.java      |   93 --
 .../internal/service/BundleManagerTest.java     |   64 -
 .../service/FeaturesServiceImplTest.java        |  167 ---
 .../service/FeaturesValidationTest.java         |  102 --
 .../internal/service/OverridesTest.java         |  202 ---
 .../karaf/features/internal/service/f01.xml     |   92 --
 .../karaf/features/internal/service/f02.xml     |  164 --
 .../karaf/features/internal/service/f03.xml     |   27 -
 .../karaf/features/internal/service/f04.xml     |   28 -
 .../karaf/features/internal/service/f05.xml     |   28 -
 .../karaf/features/internal/service/f06.xml     |   36 -
 .../karaf/features/internal/service/f07.xml     |   35 -
 .../internal/service/overrides.properties       |   23 -
 .../karaf/features/internal/service/repo2.xml   |   41 -
 .../org/apache/karaf/features/repo1.xml         |   35 -
 .../org/apache/karaf/features/repo2.xml         |   37 -
 .../org/apache/karaf/features/repo3.xml         |   27 -
 instance/pom.xml                                |    2 +-
 kar/pom.xml                                     |    2 +-
 pom.xml                                         |    5 +
 261 files changed, 16137 insertions(+), 15828 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/assemblies/apache-karaf/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/apache-karaf/pom.xml b/assemblies/apache-karaf/pom.xml
index ce631b8..a799b0a 100644
--- a/assemblies/apache-karaf/pom.xml
+++ b/assemblies/apache-karaf/pom.xml
@@ -161,8 +161,8 @@
                     </installedFeatures>
                     <bootFeatures>
                         <feature>aries-blueprint</feature>
-                        <feature>shell-compat</feature>
                         <feature>shell</feature>
+                        <feature>shell-compat</feature>
                         <feature>jaas</feature>
                         <feature>ssh</feature>
                         <feature>management</feature>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/assemblies/features/standard/src/main/feature/feature.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index 86f8270..5e3fd11 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -73,6 +73,7 @@
         <bundle dependency="true" start-level="30">mvn:org.jledit/core/${jledit.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.core/${project.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/${project.version}</bundle>
+        <bundle start-level="30">mvn:org.apache.karaf.features/org.apache.karaf.features.command/${project.version}</bundle>
     </feature>
 
     <feature name="shell-compat" description="Karaf Shell Compatibility" version="${project.version}">

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/NOTICE
----------------------------------------------------------------------
diff --git a/features/command/NOTICE b/features/command/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/features/command/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/pom.xml
----------------------------------------------------------------------
diff --git a/features/command/pom.xml b/features/command/pom.xml
new file mode 100644
index 0000000..4f49bb1
--- /dev/null
+++ b/features/command/pom.xml
@@ -0,0 +1,90 @@
+<?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>
+
+    <parent>
+        <groupId>org.apache.karaf.features</groupId>
+        <artifactId>features</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>org.apache.karaf.features.command</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Features :: Command</name>
+    <description>This bundle provides the Karaf shell commands to manipulate features.</description>
+
+    <properties>
+        <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>${project.basedir}/src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>**/*.info</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Karaf-Commands>org.apache.karaf.features.command.*</Karaf-Commands>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
new file mode 100644
index 0000000..076650d
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
@@ -0,0 +1,42 @@
+/*
+ * 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.karaf.features.command;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+
+public abstract class FeaturesCommandSupport implements Action {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    @Override
+    public Object execute() throws Exception {
+        if (featuresService == null) {
+            throw new IllegalStateException("FeaturesService not found");
+        }
+        doExecute(featuresService);
+        return null;
+    }
+
+    protected abstract void doExecute(FeaturesService admin) throws Exception;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
new file mode 100644
index 0000000..5ad855c
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
@@ -0,0 +1,290 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "info", description = "Shows information about selected feature.")
+@Service
+public class InfoFeatureCommand extends FeaturesCommandSupport {
+
+    private static final String INDENT = "  ";
+    private static final String FEATURE_CONTENT = "Feature";
+    private static final String CONDITIONAL_CONTENT = "Conditional(%s)";
+
+	@Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false)
+    @Completion(AllFeatureCompleter.class)
+    private String name;
+
+    @Argument(index = 1, name = "version", description = "The version of the feature", required = false, multiValued = false)
+    private String version;
+
+    @Option(name = "-c", aliases={"--configuration"}, description="Display configuration info", required = false, multiValued = false)
+    private boolean config;
+
+    @Option(name = "-d", aliases={"--dependency"}, description="Display dependencies info", required = false, multiValued = false)
+    private boolean dependency;
+
+    @Option(name = "-b", aliases={"--bundle"}, description="Display bundles info", required = false, multiValued = false)
+    private boolean bundle;
+
+    @Option(name = "--conditional", description="Display conditional info", required = false, multiValued = false)
+    private boolean conditional;
+
+    @Option(name = "-t", aliases={"--tree"}, description="Display feature tree", required = false, multiValued = false)
+    private boolean tree;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        Feature feature = null;
+
+        if (version != null && version.length() > 0) {
+            feature = admin.getFeature(name, version);
+        } else {
+            feature = admin.getFeature(name);
+        }
+
+        if (feature == null) {
+            System.out.println("Feature not found");
+            return;
+        }
+
+        // default behavior
+        if (!config && !dependency && !bundle && !conditional) {
+            config = true;
+            dependency = true;
+            bundle = true;
+            conditional = true;
+        }
+
+        System.out.println("Feature " + feature.getName() + " " + feature.getVersion());
+        if (feature.getDescription() != null) {
+        	System.out.println("Description:");
+        	System.out.println(INDENT + feature.getDescription());
+        }
+        
+        if(feature.getDetails() != null) {
+        	System.out.println("Details:");
+        	printWithIndent(feature.getDetails());
+        }
+
+        if (config) {
+            displayConfigInformation(feature, FEATURE_CONTENT);
+            displayConfigFileInformation(feature, FEATURE_CONTENT);
+        }
+
+        if (dependency) {
+            displayDependencyInformation(feature, FEATURE_CONTENT);
+        }
+
+        if (bundle) {
+            displayBundleInformation(feature, FEATURE_CONTENT);
+        }
+
+        if(conditional) {
+           displayConditionalInfo(feature);
+        }
+
+        if (tree) {
+            if (config || dependency || bundle) {
+                System.out.println("\nFeature tree");
+            }
+
+            int unresolved = displayFeatureTree(admin, feature.getName(), feature.getVersion(), "");
+            if (unresolved > 0) {
+                System.out.println("Tree contains " + unresolved + " unresolved dependencies");
+                System.out.println(" * means that node declares dependency but the dependent feature is not available.");
+            }
+        }
+    }
+
+    private void printWithIndent(String details) {
+    	String[] lines = details.split("\r?\n");
+    	for (String line : lines) {
+			System.out.println(INDENT + line);
+		}
+	}
+
+	private void displayBundleInformation(Feature feature, String contentType) {
+        List<BundleInfo> bundleInfos = feature.getBundles();
+        if (bundleInfos.isEmpty()) {
+            System.out.println(contentType + " has no bundles.");
+        } else {
+            System.out.println(contentType + " contains followed bundles:");
+            for (BundleInfo featureBundle : bundleInfos) {
+                int startLevel = featureBundle.getStartLevel();
+                StringBuilder sb = new StringBuilder();
+                sb.append(INDENT).append(featureBundle.getLocation());
+                if(startLevel > 0) {
+                    sb.append(" start-level=").append(startLevel);
+                }
+                System.out.println(sb.toString());
+            }
+        }
+    }
+
+    private void displayDependencyInformation(Feature feature, String contentType) {
+        List<Dependency> dependencies = feature.getDependencies();
+        if (dependencies.isEmpty()) {
+            System.out.println(contentType + " has no dependencies.");
+        } else {
+            System.out.println(contentType + " depends on:");
+            for (Dependency featureDependency : dependencies) {
+                System.out.println(INDENT + featureDependency.getName() + " " + featureDependency.getVersion());
+            }
+        }
+    }
+
+    private void displayConfigInformation(Feature feature, String contentType) {
+        Map<String, Map<String, String>> configurations = feature.getConfigurations();
+        if (configurations.isEmpty()) {
+            System.out.println(contentType + " has no configuration");
+        } else {
+            System.out.println(contentType + " configuration:");
+            for (String name : configurations.keySet()) {
+                System.out.println(INDENT + name);
+            }
+        }
+    }
+    
+    private void displayConfigFileInformation(Feature feature, String contentType) {
+    	List<ConfigFileInfo> configurationFiles = feature.getConfigurationFiles();
+    	if (configurationFiles.isEmpty()) {
+    		System.out.println(contentType + " has no configuration files");
+    	} else {
+    		System.out.println(contentType + " configuration files: ");
+    		for (ConfigFileInfo configFileInfo : configurationFiles) {
+				System.out.println(INDENT + configFileInfo.getFinalname());
+			}
+    	}    	
+    }
+
+    /**
+     * Called originally with featureName and featureVersion that have already been resolved successfully.
+     *
+     * @param admin
+     * @param featureName
+     * @param featureVersion
+     * @param prefix
+     * @return
+     * @throws Exception
+     */
+    private int displayFeatureTree(FeaturesService admin, String featureName, String featureVersion, String prefix) throws Exception {
+        int unresolved = 0;
+
+        Feature resolved = admin.getFeature(featureName, featureVersion);
+        if (resolved != null) {
+            System.out.println(prefix + " " + resolved.getName() + " " + resolved.getVersion());
+        } else {
+            System.out.println(prefix + " " + featureName + " " + featureVersion + " *");
+            unresolved++;
+        }
+
+        if (resolved != null) {
+            if (bundle) {
+                List<String> bundleLocation = new LinkedList<String>();
+                List<BundleInfo> bundles = resolved.getBundles();
+                for (BundleInfo bundleInfo : bundles) {
+                    bundleLocation.add(bundleInfo.getLocation());
+                }
+
+                if (conditional) {
+                    for (Conditional cond : resolved.getConditional()) {
+                        List<String> condition = cond.getCondition();
+                        List<BundleInfo> conditionalBundles = cond.getBundles();
+                        for (BundleInfo bundleInfo : conditionalBundles) {
+                            bundleLocation.add(bundleInfo.getLocation() + "(condition:"+condition+")");
+                        }
+                    }
+                }
+                for (int i = 0, j = bundleLocation.size(); i < j; i++) {
+                    System.out.println(prefix + " " + (i + 1 == j ? "\\" : "+") + " " + bundleLocation.get(i));
+                }
+            }
+            prefix += "   ";
+            List<Dependency> dependencies = resolved.getDependencies();
+            for (int i = 0, j = dependencies.size(); i < j; i++) {
+                Dependency toDisplay =  dependencies.get(i);
+                unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
+            }
+
+            if (conditional) {
+                for (Conditional cond : resolved.getConditional()) {
+                    List<Dependency> conditionDependencies = cond.getDependencies();
+                    for (int i = 0, j = conditionDependencies.size(); i < j; i++) {
+                        Dependency toDisplay =  dependencies.get(i);
+                        unresolved += displayFeatureTree(admin, toDisplay.getName(), toDisplay.getVersion(), prefix +1);
+                    }
+                }
+            }
+        }
+
+        return unresolved;
+    }
+
+    private void displayConditionalInfo(Feature feature) {
+        List<? extends Conditional> conditionals = feature.getConditional();
+        if (conditionals.isEmpty()) {
+            System.out.println("Feature has no conditionals.");
+        } else {
+            System.out.println("Feature contains followed conditionals:");
+            for (Conditional featureConditional : conditionals) {
+                String conditionDescription = getConditionDescription(featureConditional);
+                Feature wrappedConditional = featureConditional.asFeature(feature.getName(), feature.getVersion());
+                if (config) {
+                    displayConfigInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                    displayConfigFileInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (dependency) {
+                    displayDependencyInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+
+                if (bundle) {
+                    displayBundleInformation(wrappedConditional, String.format(CONDITIONAL_CONTENT, conditionDescription));
+                }
+            }
+        }
+    }
+
+    private String getConditionDescription(Conditional cond) {
+        StringBuffer sb = new StringBuffer();
+        for (String dep : cond.getCondition()) {
+            if (sb.length() > 0) {
+                sb.append(" ");
+            }
+            sb.append(dep);
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
new file mode 100644
index 0000000..b7f8184
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
@@ -0,0 +1,69 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AvailableFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "install", description = "Installs a feature with the specified name and version.")
+@Service
+public class InstallFeatureCommand extends FeaturesCommandSupport {
+
+    private static String DEFAULT_VERSION = "0.0.0";
+
+    @Argument(index = 0, name = "feature", description = "The name and version of the features to install. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
+    @Completion(AvailableFeatureCompleter.class)
+    List<String> features;
+
+    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
+    boolean noRefresh;
+
+    @Option(name = "-s", aliases = "--no-auto-start", description = "Do not start the bundles", required = false, multiValued = false)
+    boolean noStart;
+
+    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
+    boolean verbose;
+
+    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
+    boolean simulate;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
+        if (simulate) {
+            options.add(FeaturesService.Option.Simulate);
+        }
+        if (noStart) {
+            options.add(FeaturesService.Option.NoAutoStartBundles);
+        }
+        if (noRefresh) {
+            options.add(FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (verbose) {
+            options.add(FeaturesService.Option.Verbose);
+        }
+        admin.installFeatures(new HashSet<String>(features), options);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
new file mode 100644
index 0000000..b2c5e42
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
@@ -0,0 +1,62 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.Arrays;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "version-list", description = "Lists all versions of a feature available from the currently available repositories.")
+@Service
+public class ListFeatureVersionsCommand extends FeaturesCommandSupport {
+
+	@Argument(index = 0, name = "feature", description = "Name of feature.", required = true, multiValued = false)
+    @Completion(AllFeatureCompleter.class)
+	String feature;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("Version");
+        table.column("Repository");
+        table.column("Repository URL");
+        table.emptyTableText("No versions available for features '" + feature + "'");
+             
+        for (Repository r : Arrays.asList(admin.listRepositories())) {
+            for (Feature f : r.getFeatures()) {
+
+                if (f.getName().equals(feature)) {
+                    table.addRow().addContent(f.getVersion(), r.getName(), r.getURI());
+                }
+            }
+        }
+
+        table.print(System.out, !noFormat);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
new file mode 100644
index 0000000..e86ff64
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
@@ -0,0 +1,106 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "list", description = "Lists all existing features available from the defined repositories.")
+@Service
+public class ListFeaturesCommand extends FeaturesCommandSupport {
+
+    @Option(name = "-i", aliases = {"--installed"}, description = "Display a list of all installed features only", required = false, multiValued = false)
+    boolean onlyInstalled;
+
+    @Option(name = "-r", aliases = {"--required"}, description = "Display a list of all required features only", required = false, multiValued = false)
+    boolean onlyRequired;
+
+    @Option(name = "-o", aliases = {"--ordered"}, description = "Display a list using alphabetical order ", required = false, multiValued = false)
+    boolean ordered;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        boolean needsLegend = false;
+        
+        ShellTable table = new ShellTable();
+        table.column("Name");
+        table.column("Version");
+        table.column("Required");
+        table.column("Installed");
+        table.column("Repository");
+        table.column("Description").maxSize(50);
+        table.emptyTableText(onlyInstalled ? "No features installed" : "No features available");
+
+        List<Repository> repos = Arrays.asList(featuresService.listRepositories());
+        for (Repository r : repos) {
+            List<Feature> features = Arrays.asList(r.getFeatures());
+            if (ordered) {
+                Collections.sort(features, new FeatureComparator());
+            }
+            for (Feature f : features) {
+                if (onlyInstalled && !featuresService.isInstalled(f)) {
+                    // Filter out not installed features if we only want to see the installed ones
+                    continue;
+                }
+                if (onlyRequired && !featuresService.isRequired(f)) {
+                    // Filter out not installed features if we only want to see the installed ones
+                    continue;
+                }
+                table.addRow().addContent(
+                        f.getName(),
+                        f.getVersion(),
+                        featuresService.isRequired(f) ? "x" : "",
+                        featuresService.isInstalled(f) ? "x" : "",
+                        r.getName(),
+                        f.getDescription());
+                if (isInstalledViaDeployDir(r.getName())) {
+                    needsLegend = true;
+                }
+            }
+        }
+
+        table.print(System.out, !noFormat);
+
+        if (needsLegend) {
+            System.out.println("* Installed via deploy directory");
+        }
+
+    }
+
+    private boolean isInstalledViaDeployDir(String st) {
+        return (st == null || st.length() <= 1) ? false : (st.charAt(st.length() - 1) == '*');
+    }
+
+    class FeatureComparator implements Comparator<Feature> {
+        public int compare(Feature o1, Feature o2) {
+            return o1.getName().toLowerCase().compareTo( o2.getName().toLowerCase() );
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
new file mode 100644
index 0000000..16faf42
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
@@ -0,0 +1,54 @@
+/*
+ * 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.karaf.features.command;
+
+import java.net.URI;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.AvailableRepoNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "repo-add", description = "Add a features repository")
+@Service
+public class RepoAddCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "name/url", description = "Shortcut name of the features repository or the full URL", required = true, multiValued = false)
+    @Completion(AvailableRepoNameCompleter.class)
+    private String nameOrUrl;
+    
+    @Argument(index = 1, name = "version", description = "The version of the features repository if using features repository name as first argument. It should be empty if using the URL", required = false, multiValued = false)
+    private String version;
+
+    @Option(name = "-i", aliases = { "--install" }, description = "Install all features contained in the features repository", required = false, multiValued = false)
+    private boolean install;
+
+    @Override
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        String effectiveVersion = (version == null) ? "LATEST" : version;
+        URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
+        if (uri == null) {
+            uri = new URI(nameOrUrl);
+        }
+        System.out.println("Adding feature url " + uri);
+        featuresService.addRepository(uri, install);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
new file mode 100644
index 0000000..55acf79
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
@@ -0,0 +1,73 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.MultiException;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "feature", name = "repo-list", description = "Displays a list of all defined repositories.")
+@Service
+public class RepoListCommand extends FeaturesCommandSupport {
+
+    @Option(name="-r", description="Reload all feature urls", required = false, multiValued = false)
+    boolean reload;
+
+    @Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
+    boolean noFormat;
+    
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        if (reload) {
+            reloadAllRepos(featuresService);
+        }
+        
+        ShellTable table = new ShellTable();
+        table.column("Repository");
+        table.column("URL");
+        table.emptyTableText("No repositories available");
+
+        Repository[] repos = featuresService.listRepositories();
+     	for (Repository repo : repos) {
+            if (repo != null) {
+     	        table.addRow().addContent(repo.getName(), repo.getURI().toString()); 
+            }
+     	}
+     	table.print(System.out, !noFormat);
+    }
+
+    private void reloadAllRepos(FeaturesService featuresService) throws Exception {
+        System.out.println("Reloading all repositories from their urls");
+        System.out.println();
+        List<Exception> exceptions = new ArrayList<Exception>();
+        for (Repository repo : featuresService.listRepositories()) {
+            try {
+                featuresService.addRepository(repo.getURI());
+            } catch (Exception e) {
+                exceptions.add(e);
+            }
+        }
+        MultiException.throwIf("Unable to reload repositories", exceptions);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
new file mode 100644
index 0000000..8c7ed79
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
@@ -0,0 +1,65 @@
+/*
+ * 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.karaf.features.command;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+
+@Command(scope = "feature", name = "repo-refresh", description = "Refresh a features repository")
+public class RepoRefreshCommand extends FeaturesCommandSupport {
+    @Argument(index = 0, name = "Feature name or uri", description = "Shortcut name of the feature repository or the full URI", required = false, multiValued = false)
+    @Completion(InstalledRepoUriCompleter.class)
+    private String nameOrUrl;
+    
+    @Argument(index = 1, name = "Feature version", description = "The version of the feature if using the feature name. Should be empty if using the uri", required = false, multiValued = false)
+    private String version;
+
+    @Override
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+        List<URI> uris = new ArrayList<URI>();
+    	if (nameOrUrl != null) {
+    		String effectiveVersion = (version == null) ? "LATEST" : version;
+        	URI uri = featuresService.getRepositoryUriFor(nameOrUrl, effectiveVersion);
+        	if (uri == null) {
+        		uri = new URI(nameOrUrl);
+        	}
+            uris.add(uri);
+    	} else {
+            Repository[] repos = featuresService.listRepositories();
+            for (Repository repo : repos) {
+                uris.add(repo.getURI());
+            }
+    	}
+        for (URI uri : uris) {
+            try {
+                System.out.println("Refreshing feature url " + uri);
+                featuresService.refreshRepository(uri);
+            } catch (Exception e) {
+                System.err.println("Error refreshing " + uri.toString() + ": " + e.getMessage());
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
new file mode 100644
index 0000000..0710b72
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
@@ -0,0 +1,56 @@
+/*
+ * 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.karaf.features.command;
+
+import java.net.URI;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "repo-remove", description = "Removes the specified repository features service.")
+@Service
+public class RepoRemoveCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "repository", description = "Name or url of the repository to remove.", required = true, multiValued = false)
+    @Completion(InstalledRepoNameCompleter.class)
+    private String repository;
+
+    @Option(name = "-u", aliases = { "--uninstall-all" }, description = "Uninstall all features from the repository", required = false, multiValued = false)
+    private boolean uninstall;
+
+    protected void doExecute(FeaturesService featuresService) throws Exception {
+    	URI uri = null;
+    	for (Repository r : featuresService.listRepositories()) {
+    		if (r.getName() != null && r.getName().equals(repository)) {
+    			uri = r.getURI();
+    			break;
+    		}
+    	}
+
+    	if (uri == null) {
+    	    uri = new URI(repository);
+    	}
+
+    	featuresService.removeRepository(uri, uninstall);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
new file mode 100644
index 0000000..e62f697
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
@@ -0,0 +1,62 @@
+/*
+ * 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.karaf.features.command;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.RequiredFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "feature", name = "uninstall", description = "Uninstalls a feature with the specified name and version.")
+@Service
+public class UninstallFeatureCommand extends FeaturesCommandSupport {
+
+    @Argument(index = 0, name = "features", description = "The name and version of the features to uninstall. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
+    @Completion(RequiredFeatureCompleter.class)
+    List<String> features;
+
+    @Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
+    boolean noRefresh;
+
+    @Option(name = "-v", aliases = "--verbose", description = "Explain what is being done", required = false, multiValued = false)
+    boolean verbose;
+
+    @Option(name = "-t", aliases = "--simulate", description = "Perform a simulation only", required = false, multiValued = false)
+    boolean simulate;
+
+    protected void doExecute(FeaturesService admin) throws Exception {
+        // iterate in the provided feature
+        EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
+        if (simulate) {
+            options.add(FeaturesService.Option.Simulate);
+        }
+        if (noRefresh) {
+            options.add(FeaturesService.Option.NoAutoRefreshBundles);
+        }
+        if (verbose) {
+            options.add(FeaturesService.Option.Verbose);
+        }
+        admin.uninstallFeatures(new HashSet<String>(features), options);
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
new file mode 100644
index 0000000..7444b95
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for available features.
+ */
+@Service
+public class AllFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
new file mode 100644
index 0000000..79cd280
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for features not installed yet.
+ */
+@Service
+public class AvailableFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return !featuresService.isInstalled(feature);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
new file mode 100644
index 0000000..acefe77
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Shows the list of feature repos that can be installed with their short name
+ */
+@Service
+public class AvailableRepoNameCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter(Arrays.asList(featuresService.getRepositoryNames()));
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
new file mode 100644
index 0000000..d01e5af
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
@@ -0,0 +1,65 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Base completer for feature commands.
+ */
+public abstract class FeatureCompleterSupport implements Completer {
+
+    /**
+     * Feature service.
+     */
+    @Reference
+    protected FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Feature feature : featuresService.listFeatures()) {
+                if (acceptsFeature(feature)) {
+                    delegate.getStrings().add(feature.getName());
+                }
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+    /**
+     * Method for filtering features.
+     *
+     * @param feature The feature.
+     * @return True if feature should be available in completer.
+     */
+    protected abstract boolean acceptsFeature(Feature feature);
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
new file mode 100644
index 0000000..94e4cf7
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * {@link Completer} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+@Service
+public class InstalledRepoNameCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Repository repository : featuresService.listRepositories()) {
+                delegate.getStrings().add(repository.getName());
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
new file mode 100644
index 0000000..7a760c2
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * {@link Completer} for Feature Repository URLs.
+ *
+ * Displays a list of currently installed Feature repositories.
+ *
+ */
+
+@Service
+public class InstalledRepoUriCompleter implements Completer {
+
+    @Reference
+    private FeaturesService featuresService;
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+
+    public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Repository repository : featuresService.listRepositories()) {
+                delegate.getStrings().add(repository.getURI().toString());
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(session, commandLine, candidates);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
new file mode 100644
index 0000000..a51f75f
--- /dev/null
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/RequiredFeatureCompleter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.karaf.features.command.completers;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+/**
+ * {@link org.apache.karaf.shell.console.Completer} for installed features.
+ */
+@Service
+public class RequiredFeatureCompleter extends FeatureCompleterSupport {
+
+    @Override
+    protected boolean acceptsFeature(Feature feature) {
+        return featuresService.isRequired(feature);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/command/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/features/command/src/main/resources/OSGI-INF/bundle.info b/features/command/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..8f0598b
--- /dev/null
+++ b/features/command/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,30 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+This bundle provides the Karaf shell commands to manipulate features.
+
+The following commands are available:
+
+* features:addUrl - Adds a list of repository URLs to the features service.
+* features:info- Shows information about selected information.
+* features:install- Installs a feature with the specified name and version.
+* features:list - Lists all existing features available from the defined repositories.
+* features:listVersions- Lists all versions of a feature available from the currently available repositories.
+* features:listRepositories- Displays a list of all defined repositories.
+* features:listUrl- Displays a list of all defined repository URLs.
+* features:refreshUrl- Reloads the list of available features from the repositories.
+* features:removeRepository- Removes the specified repository features service.
+* features:removeUrl- Removes the given list of repository URLs from the features service.
+* features:uninstall- Uninstalls a feature with the specified name and version.
+
+h1. See also
+
+Commands- and Provisioning- sections of the Karaf User Guide.

http://git-wip-us.apache.org/repos/asf/karaf/blob/0c8e8a81/features/core/NOTICE
----------------------------------------------------------------------
diff --git a/features/core/NOTICE b/features/core/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/features/core/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License