You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gg...@apache.org on 2017/06/21 13:27:14 UTC

[01/12] karaf git commit: [KARAF-5008] org.apache.karaf.maven.SettingsTest#encryptMavenPassword

Repository: karaf
Updated Branches:
  refs/heads/master-maven-commands [created] e517bad1a


[KARAF-5008] org.apache.karaf.maven.SettingsTest#encryptMavenPassword


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

Branch: refs/heads/master-maven-commands
Commit: 045cb99d6a376a5d7ea794c982e2bf608a4b20e7
Parents: e254d83
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Mon Jun 19 14:35:01 2017 +0200
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              |  2 +-
 .../karaf/maven/command/HttpProxyCommand.java   | 10 +--
 .../command/MavenConfigurationSupport.java      | 20 +++++
 .../maven/command/RepositoryListCommand.java    | 10 +--
 .../karaf/maven/command/SummaryCommand.java     |  2 +-
 .../org/apache/karaf/maven/SettingsTest.java    | 62 +++++++++++++++
 .../src/test/resources/reference-settings.xml   | 82 ++++++++++++++++++++
 maven/pom.xml                                   |  2 +-
 8 files changed, 169 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
index 1380a56..db2f2a7 100644
--- a/maven/core/pom.xml
+++ b/maven/core/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.karaf</groupId>
         <artifactId>karaf</artifactId>
-        <version>4.1.1-SNAPSHOT</version>
+        <version>4.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
index 85eeb40..6f8b794 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
@@ -66,15 +66,7 @@ public class HttpProxyCommand extends MavenConfigurationSupport {
                 row.addContent(proxy.getId(), proxy.getHost(), proxy.getPort());
                 row.addContent(proxy.getUsername() != null ? proxy.getUsername() : "");
                 if (showPasswords) {
-                    if (proxyPasswords.containsKey(proxy.getId())) {
-                        row.addContent(proxyPasswords.get(proxy.getId()));
-                    } else {
-                        if (cipher.isEncryptedString(proxy.getPassword())) {
-                            row.addContent(proxy.getPassword() + " (can't decrypt)");
-                        } else {
-                            row.addContent(proxy.getPassword() == null ? "" : proxy.getPassword());
-                        }
-                    }
+                    addPasswordInfo(row, proxyPasswords, proxy.getId(), proxy.getPassword());
                 }
             }
             table.print(System.out);

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index 9e9bf26..4c3416a 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -34,6 +34,7 @@ import org.apache.karaf.shell.api.action.Action;
 import org.apache.karaf.shell.api.action.Option;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.table.Row;
 import org.apache.maven.settings.Profile;
 import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Repository;
@@ -538,6 +539,25 @@ public abstract class MavenConfigurationSupport implements Action {
                 .toArray(String[]::new);
     }
 
+    /**
+     * Adds information used by proxy/server
+     * @param row {@link org.apache.karaf.shell.support.table.ShellTable}'s row to add information to
+     * @param id2Password mapping of ids (servers/proxies to decrypted passwords)
+     * @param id ID of proxy or server from <code>settings.xml</code>
+     * @param password password to use if decryption failed
+     */
+    protected void addPasswordInfo(Row row, Map<String, String> id2Password, String id, String password) {
+        if (id2Password.containsKey(id)) {
+            row.addContent(id2Password.get(id));
+        } else {
+            if (cipher.isEncryptedString(password)) {
+                row.addContent(password + " (can't decrypt)");
+            } else {
+                row.addContent(password == null ? "" : password);
+            }
+        }
+    }
+
     protected static class SourceAnd<T> {
         String source;
         T value;

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
index b2d31be..90c7c26 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
@@ -63,15 +63,7 @@ public class RepositoryListCommand extends MavenConfigurationSupport {
                 if (servers.containsKey(repoURL.getId())) {
                     Server server = servers.get(repoURL.getId());
                     row.addContent(server.getUsername() == null ? "" : server.getUsername());
-                    if (serverPasswords.containsKey(repoURL.getId())) {
-                        row.addContent(serverPasswords.get(repoURL.getId()));
-                    } else {
-                        if (cipher.isEncryptedString(server.getPassword())) {
-                            row.addContent(server.getPassword() + " (can't decrypt)");
-                        } else {
-                            row.addContent(server.getPassword() == null ? "" : server.getPassword());
-                        }
-                    }
+                    addPasswordInfo(row, serverPasswords, repoURL.getId(), server.getPassword());
                 } else {
                     row.addContent("", "");
                 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index be71a93..1678239 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -98,7 +98,7 @@ public class SummaryCommand extends MavenConfigurationSupport {
             sourceInfo = "BundleContext property (" + prefix + REQUIRE_CONFIG_ADMIN_CONFIG + ")";
         }
         addRow(table, propertyIds ? REQUIRE_CONFIG_ADMIN_CONFIG : "Require Config Admin", new SourceAnd<Boolean>(sourceInfo, requireConfigAdmin),
-                "Wheter MavenResolver service is registered ONLY with proper " + PID + " PID configuration");
+                "Whether MavenResolver service is registered ONLY with proper " + PID + " PID configuration");
 
         // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.buildSettings()
         String useFallbackRepositoriesProperty = (String) config.get(prefix + PROPERTY_USE_FALLBACK_REPOSITORIES);

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
new file mode 100644
index 0000000..b0d9110
--- /dev/null
+++ b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.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.maven;
+
+import java.io.IOException;
+
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.io.DefaultSettingsWriter;
+import org.junit.Test;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
+import org.sonatype.plexus.components.cipher.PBECipher;
+
+public class SettingsTest {
+
+    @Test
+    public void readAndWriteSettings() throws IOException {
+        Settings settings = new Settings();
+        Server s = new Server();
+        s.setId("id");
+        settings.getServers().add(s);
+
+        new DefaultSettingsWriter().write(System.out, null, settings);
+    }
+
+    @Test
+    public void encryptMavenPassword() throws Exception {
+        // non-master password ('mvn -ep admin')
+        DefaultPlexusCipher plexusCipher = new DefaultPlexusCipher();
+        System.out.println(plexusCipher.encrypt("admin", "admin"));
+
+        // master password (`mvn -emp admin`)
+        PBECipher cipher = new PBECipher();
+        System.out.println(cipher.encrypt64("admin","settings.security"));
+    }
+
+    @Test
+    public void decryptMavenPassword() throws Exception {
+        // non-master password ('mvn -ep admin')
+        DefaultPlexusCipher plexusCipher = new DefaultPlexusCipher();
+        System.out.println(plexusCipher.decrypt("{EhjazkVpkMoHjAgaUKX+UxeXn9lsJGHst2uFKmhNZ8U=}", "admin"));
+
+        // master password (`mvn -emp admin`)
+        PBECipher cipher = new PBECipher();
+        System.out.println(cipher.decrypt64("oWE12FbirwYHNit93TAMA+OC/GJge2r9FuzI8kOuHlA=","settings.security"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/core/src/test/resources/reference-settings.xml
----------------------------------------------------------------------
diff --git a/maven/core/src/test/resources/reference-settings.xml b/maven/core/src/test/resources/reference-settings.xml
new file mode 100644
index 0000000..25b58fb
--- /dev/null
+++ b/maven/core/src/test/resources/reference-settings.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+
+    <localRepository>file:///</localRepository>
+
+    <proxies>
+        <proxy>
+            <id>id1</id>
+            <host>localhost</host>
+            <port>3128</port>
+            <protocol>http</protocol>
+            <username>username</username>
+            <password>password</password>
+        </proxy>
+    </proxies>
+
+    <servers>
+        <server>
+            <id>id</id>
+            <username>username</username>
+            <password>password</password>
+        </server>
+    </servers>
+
+    <profiles>
+        <profile>
+            <id>profile1</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <repositories>
+                <repository>
+                    <id>id1</id>
+                    <url>http://localhost/maven-repository/releases</url>
+                    <releases>
+                        <enabled>true</enabled>
+                        <updatePolicy>never</updatePolicy>
+                        <checksumPolicy>warn</checksumPolicy>
+                    </releases>
+                    <snapshots>
+                        <enabled>false</enabled>
+                    </snapshots>
+                </repository>
+                <repository>
+                    <id>id2</id>
+                    <url>http://localhost/maven-repository/snapshots</url>
+                    <releases>
+                        <enabled>false</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                        <updatePolicy>always</updatePolicy>
+                        <checksumPolicy>warn</checksumPolicy>
+                    </snapshots>
+                </repository>
+            </repositories>
+        </profile>
+    </profiles>
+
+    <activeProfiles>
+        <activeProfile>profile1</activeProfile>
+    </activeProfiles>
+
+</settings>

http://git-wip-us.apache.org/repos/asf/karaf/blob/045cb99d/maven/pom.xml
----------------------------------------------------------------------
diff --git a/maven/pom.xml b/maven/pom.xml
index a8d8369..95a3983 100644
--- a/maven/pom.xml
+++ b/maven/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.karaf</groupId>
         <artifactId>karaf</artifactId>
-        <version>4.1.1-SNAPSHOT</version>
+        <version>4.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 


[08/12] karaf git commit: [KARAF-5008] maven:summary - update and checksum policy information

Posted by gg...@apache.org.
[KARAF-5008] maven:summary - update and checksum policy information


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

Branch: refs/heads/master-maven-commands
Commit: f3fe90b8531cf30dd4cac4953d73ac5d7693b6ce
Parents: 3ea2be2
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Tue Mar 14 08:23:23 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              |  11 +-
 .../command/MavenConfigurationSupport.java      |  81 +++++++-----
 .../karaf/maven/command/SummaryCommand.java     | 127 +++++++++++++++++--
 3 files changed, 165 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/f3fe90b8/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
index a05b3d1..197a145 100644
--- a/maven/core/pom.xml
+++ b/maven/core/pom.xml
@@ -45,11 +45,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.karaf</groupId>
-            <artifactId>org.apache.karaf.util</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.karaf.shell</groupId>
             <artifactId>org.apache.karaf.shell.core</artifactId>
         </dependency>
@@ -112,9 +107,9 @@
                         <Private-Package>
                             org.apache.karaf.maven.command,
                             org.apache.karaf.maven.core,
-                            org.apache.maven.settings.*,
-                            org.apache.maven.execution,
-                            org.apache.maven.model,
+                            org.apache.maven.settings.*;-split-package:=merge-first,
+                            org.apache.maven.execution;-split-package:=merge-first,
+                            org.apache.maven.model;-split-package:=merge-first,
                             org.codehaus.plexus.component.annotations,
                             org.sonatype.plexus.components.sec.dispatcher*,
                             org.sonatype.plexus.components.cipher,

http://git-wip-us.apache.org/repos/asf/karaf/blob/f3fe90b8/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index dbab04a..2a77c9d 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -44,21 +44,26 @@ import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 
 /**
  * <p>Base class for <code>maven:</code> commands.</p>
- * <p>Even if it duplicates some code from pax-url-aether, this should be treated as verification code of how
- * pax-url-aether should interact with <code>org.ops4j.pax.url.mvn</code> PID configuration.</p>
+ * <p>Important: even if it duplicates some code from pax-url-aether, this should be treated as verification code of
+ * how pax-url-aether should interact with <code>org.ops4j.pax.url.mvn</code> PID configuration.</p>
  */
 public abstract class MavenConfigurationSupport implements Action {
 
     public static Logger LOG = LoggerFactory.getLogger(MavenConfigurationSupport.class);
     protected static final String PID = "org.ops4j.pax.url.mvn";
 
-    static final String PROPERTY_LOCAL_REPOSITORY = "localRepository";
-    static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
-    static final String PROPERTY_REPOSITORIES = "repositories";
-    static final String PROPERTY_SETTINGS_FILE = "settings";
+    protected static final String PATTERN_PID_PROPERTY = "Explicit %s PID configuration (%s)";
 
-    protected FileAndSource localRepository;
-    protected FileAndSource settings;
+    protected static final String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+    protected static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
+    protected static final String PROPERTY_REPOSITORIES = "repositories";
+    protected static final String PROPERTY_SETTINGS_FILE = "settings";
+    protected static final String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
+    protected static final String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
+    protected static final String PROPERTY_UPDATE_RELEASES = "updateReleases";
+
+    protected SourceAnd<File> localRepository;
+    protected SourceAnd<File> settings;
     protected Settings effectiveSettings;
     protected Map<String, String> serverPasswords = new HashMap<>();
     protected Map<String, String> proxyPasswords = new HashMap<>();
@@ -74,8 +79,8 @@ public abstract class MavenConfigurationSupport implements Action {
 
         if (c != null && c.getProperties() != null) {
             settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
-            if (settings.file != null) {
-                reReadSettings(settings.file);
+            if (settings.value != null) {
+                reReadSettings(settings.value);
             }
             localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
 
@@ -116,8 +121,8 @@ public abstract class MavenConfigurationSupport implements Action {
      * @param cmProperty property obtained from Config Admin
      * @return
      */
-    protected FileAndSource settings(String cmProperty) {
-        FileAndSource result = new FileAndSource();
+    protected SourceAnd<File> settings(String cmProperty) {
+        SourceAnd<File> result = new SourceAnd<>();
         URL locationUrl = null;
         String probableErrorMessage = null;
 
@@ -125,14 +130,14 @@ public abstract class MavenConfigurationSupport implements Action {
         if (cmProperty != null && !"".equals(cmProperty.trim())) {
             try {
                 locationUrl = new URL(cmProperty);
-                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SETTINGS_FILE);
                 probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
                         locationUrl, PID, PROPERTY_SETTINGS_FILE);
             } catch (MalformedURLException e) {
                 File file = new File(cmProperty);
                 if (file.isFile()) {
-                    result.file = file;
-                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                    result.value = file;
+                    result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SETTINGS_FILE);
                     return result;
                 }
             }
@@ -142,7 +147,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl == null) {
             File file = new File(System.getProperty("user.home") + "/.m2/settings.xml");
             if (file.isFile()) {
-                result.file = file;
+                result.value = file;
                 result.source = "Implicit ${user.home}/.m2/settings.xml";
                 return result;
             }
@@ -152,7 +157,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl == null) {
             File file = new File(System.getProperty("maven.home") + "/conf/settings.xml");
             if (file.isFile()) {
-                result.file = file;
+                result.value = file;
                 result.source = "Implicit ${maven.home}/conf/settings.xml";
                 return result;
             }
@@ -162,7 +167,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl == null) {
             File file = new File(System.getenv("M2_HOME") + "/conf/settings.xml");
             if (file.isFile()) {
-                result.file = file;
+                result.value = file;
                 result.source = "Implicit $M2_HOME/conf/settings.xml";
                 return result;
             }
@@ -171,7 +176,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl != null) {
             File file = new File(locationUrl.getPath());
             if (file.isFile()) {
-                result.file = file;
+                result.value = file;
                 return result;
             } else {
                 throw new IllegalArgumentException(probableErrorMessage);
@@ -187,8 +192,8 @@ public abstract class MavenConfigurationSupport implements Action {
      * @param cmProperty property obtained from Config Admin
      * @return
      */
-    protected FileAndSource localRepository(String cmProperty) {
-        FileAndSource result = new FileAndSource();
+    protected SourceAnd<File> localRepository(String cmProperty) {
+        SourceAnd<File> result = new SourceAnd<>();
         URL locationUrl = null;
         String probableErrorMessage = null;
 
@@ -196,14 +201,14 @@ public abstract class MavenConfigurationSupport implements Action {
         if (cmProperty != null && !"".equals(cmProperty.trim())) {
             try {
                 locationUrl = new URL(cmProperty);
-                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
                 probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
                         locationUrl, PID, PROPERTY_LOCAL_REPOSITORY);
             } catch (MalformedURLException e) {
                 File file = new File(cmProperty);
                 if (file.isDirectory()) {
-                    result.file = file;
-                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                    result.value = file;
+                    result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
                     return result;
                 }
             }
@@ -213,14 +218,14 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl == null && effectiveSettings != null && effectiveSettings.getLocalRepository() != null) {
             try {
                 locationUrl = new URL(effectiveSettings.getLocalRepository());
-                result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                result.source = String.format("Explicit <localRepository> in %s", settings.value);
                 probableErrorMessage = String.format("%s configured in %s is not accessible",
-                        effectiveSettings.getLocalRepository(), settings.file);
+                        effectiveSettings.getLocalRepository(), settings.value);
             } catch (MalformedURLException e) {
                 File file = new File(effectiveSettings.getLocalRepository());
                 if (file.isDirectory()) {
-                    result.file = file;
-                    result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                    result.value = file;
+                    result.source = String.format("Explicit <localRepository> in %s", settings.value);
                     return result;
                 }
             }
@@ -230,7 +235,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl == null) {
             File file = new File(System.getProperty("user.home") + "/.m2/repository");
             if (file.isDirectory()) {
-                result.file = file;
+                result.value = file;
                 result.source = "Implicit ${user.home}/.m2/repository";
                 return result;
             }
@@ -239,7 +244,7 @@ public abstract class MavenConfigurationSupport implements Action {
         if (locationUrl != null) {
             File file = new File(locationUrl.getPath());
             if (file.isDirectory()) {
-                result.file = file;
+                result.value = file;
                 return result;
             } else {
                 throw new IllegalArgumentException(probableErrorMessage);
@@ -290,9 +295,21 @@ public abstract class MavenConfigurationSupport implements Action {
         String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
     }
 
-    protected static class FileAndSource  {
-        File file;
+    protected static class SourceAnd<T> {
         String source;
+        T value;
+
+        public SourceAnd() {
+        }
+
+        public SourceAnd(String source, T value) {
+            this.source = source;
+            this.value = value;
+        }
+
+        public String val() {
+            return value == null ? "" : value.toString();
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/f3fe90b8/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index 0e791cd..56d6118 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -32,17 +32,20 @@ public class SummaryCommand extends MavenConfigurationSupport {
     @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
     boolean description;
 
+    @Option(name = "-s", aliases = { "--source" }, description = "Adds information about where the value is configured", required = false, multiValued = false)
+    boolean source;
+
     /*
      * All options from org.ops4j.pax.url.mvn.ServiceConstants (2.5.2):
      *
-     * String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+     * +String PROPERTY_LOCAL_REPOSITORY = "localRepository";
      * String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
      * String PROPERTY_REPOSITORIES = "repositories";
-     * String PROPERTY_SETTINGS_FILE = "settings";
+     * +String PROPERTY_SETTINGS_FILE = "settings";
      * String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
-     * String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
-     * String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
-     * String PROPERTY_UPDATE_RELEASES = "updateReleases";
+     * +String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
+     * +String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
+     * +String PROPERTY_UPDATE_RELEASES = "updateReleases";
      * String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote";
      * String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
      * String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
@@ -77,24 +80,120 @@ public class SummaryCommand extends MavenConfigurationSupport {
         ShellTable table = new ShellTable();
         table.column(new Col("Option").alignRight());
         table.column("Value");
-        table.column("Source");
+        if (source) {
+            table.column("Source");
+        }
         if (description) {
             table.column("Description");
         }
 
+        addRow(table, "Local repository", localRepository,
+                "Maven repository to store artifacts resolved in *remote repositories*",
+                source, description);
+
+        addRow(table, "Settings file", settings,
+                "Settings file that may contain configuration of additional repositories, http proxies and mirrors",
+                source, description);
+
+        // for default update/checksum policies specified at repository URI level, see
+        // org.ops4j.pax.url.mvn.internal.AetherBasedResolver.addRepo()
+
+        // see org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer#isUpdatedRequired()
+        SourceAnd<String> updatePolicy = updatePolicy((String) config.get(prefix + PROPERTY_GLOBAL_UPDATE_POLICY));
+        addRow(table, "Global update policy", updatePolicy,
+                "Overrides update policy specified at repository level (if specified)",
+                source, description);
+
+        // see org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider#newChecksumPolicy()
+        SourceAnd<String> checksumPolicy = checksumPolicy((String) config.get(prefix + PROPERTY_GLOBAL_CHECKSUM_POLICY));
+        addRow(table, "Global checksum policy", checksumPolicy,
+                "Checksum policy for all repositories",
+                source, description);
+
+        String updateReleasesProperty = (String) config.get(prefix + PROPERTY_UPDATE_RELEASES);
+        boolean updateReleases = false;
+        String sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_UPDATE_RELEASES);
+        if (updateReleasesProperty == null) {
+            sourceInfo = "Default \"false\"";
+        } else {
+            updateReleases = "true".equals(updateReleasesProperty);
+        }
+        addRow(table, "Update releases", new SourceAnd<Boolean>(sourceInfo, updateReleases),
+                "Whether to download non-SNAPSHOT artifacts according to update policy",
+                source, description);
+
+        table.print(System.out);
+    }
+
+    /**
+     * Helper to add row to {@link ShellTable}
+     * @param table
+     * @param label
+     * @param value
+     * @param description
+     * @param addSource
+     * @param addDescription
+     */
+    private <T> void addRow(ShellTable table, String label, SourceAnd<T> value, String description, boolean addSource, boolean addDescription) {
         Row row = table.addRow();
-        row.addContent("Local repository", localRepository.file, localRepository.source);
-        if (description) {
-            row.addContent("Maven repository to store artifacts resolved in *remote repositories*");
+        row.addContent(label, value.val());
+        if (addSource) {
+            row.addContent(value.source);
         }
+        if (addDescription) {
+            row.addContent(description);
+        }
+    }
 
-        row = table.addRow();
-        row.addContent("Settings file", settings.file, settings.source);
-        if (description) {
-            row.addContent("Settings file that may contain configuration of additional repositories, http proxies and mirrors");
+    private SourceAnd<String> updatePolicy(String cmProperty) {
+        SourceAnd<String> result = new SourceAnd<>();
+        result.value = cmProperty;
+
+        if (cmProperty == null || "".equals(cmProperty.trim())) {
+            result.value = "";
+            result.source = "Implicit \"never\", but doesn't override repository-specific value";
+            return result;
         }
 
-        table.print(System.out);
+        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_UPDATE_POLICY);
+        if ("always".equals(cmProperty) || "never".equals(cmProperty) || "daily".equals(cmProperty)) {
+            // ok
+        } else if (cmProperty.startsWith("interval")) {
+            int minutes = 1440;
+            try {
+                String n = cmProperty.substring("interval".length() + 1);
+                minutes = Integer.parseInt(n);
+            } catch (Exception e) {
+                result.value = "interval:1440";
+                result.source = "Implicit \"interval:1440\" (error parsing \"" + cmProperty + "\")";
+            }
+        } else {
+            result.value = "never";
+            result.source = "Implicit \"never\" (unknown value \"" + cmProperty + "\")";
+        }
+
+        return result;
+    }
+
+    private SourceAnd<String> checksumPolicy(String cmProperty) {
+        SourceAnd<String> result = new SourceAnd<>();
+        result.value = cmProperty;
+
+        if (cmProperty == null || "".equals(cmProperty.trim())) {
+            result.value = "warn";
+            result.source = "Default \"warn\"";
+            return result;
+        }
+
+        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_CHECKSUM_POLICY);
+        if ("ignore".equals(cmProperty) || "warn".equals(cmProperty) || "fail".equals(cmProperty)) {
+            // ok
+        } else {
+            result.value = "warn";
+            result.source = "Implicit \"warn\" (unknown value \"" + cmProperty + "\")";
+        }
+
+        return result;
     }
 
 }


[02/12] karaf git commit: [KARAF-5008] maven:http-proxy command to list proxies + optional password decryption

Posted by gg...@apache.org.
[KARAF-5008] maven:http-proxy command to list proxies + optional password decryption


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

Branch: refs/heads/master-maven-commands
Commit: e254d83fbc7ad3328275c850a5bd043f2716d22b
Parents: 2dc56e4
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Wed Mar 15 11:28:19 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 .../karaf/maven/command/HttpProxyCommand.java   |  92 +++++++++++++
 .../command/MavenConfigurationSupport.java      |  75 ++++++++++-
 .../karaf/maven/command/RepoListCommand.java    |  70 ----------
 .../maven/command/RepositoryAddCommand.java     |  35 +++++
 .../command/RepositoryEditCommandSupport.java   |  35 +++++
 .../maven/command/RepositoryListCommand.java    | 135 +++++++++++++++++++
 .../maven/command/RepositoryRemoveCommand.java  |  31 +++++
 .../karaf/maven/command/SummaryCommand.java     |   4 -
 8 files changed, 397 insertions(+), 80 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
new file mode 100644
index 0000000..85eeb40
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
@@ -0,0 +1,92 @@
+/*
+ * 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.maven.command;
+
+import java.util.Dictionary;
+
+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.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+import org.apache.maven.settings.Proxy;
+
+@Command(scope = "maven", name = "http-proxy", description = "Manage HTTP proxy configuration for Maven remote repositories")
+@Service
+public class HttpProxyCommand extends MavenConfigurationSupport {
+
+    @Option(name = "--add", description = "Adds HTTP proxy configuration to Maven settings", required = false, multiValued = false)
+    boolean add;
+
+    @Option(name = "--remove", description = "Removes HTTP proxy configuration from Maven settings", required = false, multiValued = false)
+    boolean remove;
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        if (add && remove) {
+            System.err.println("Please specify only one of --add and --remove");
+            return;
+        }
+
+        if (add) {
+            // add
+        }
+
+        if (remove) {
+            // remove
+        }
+
+        // list (also after --add or --remove)
+        System.out.println();
+        if (mavenSettings != null && mavenSettings.getProxies() != null && mavenSettings.getProxies().size() > 0) {
+            ShellTable table = new ShellTable();
+            table.column("ID");
+            table.column("Host");
+            table.column("Port");
+            table.column("Username");
+            if (showPasswords) {
+                table.column("Password");
+            }
+            for (Proxy proxy : mavenSettings.getProxies()) {
+                Row row = table.addRow();
+                row.addContent(proxy.getId(), proxy.getHost(), proxy.getPort());
+                row.addContent(proxy.getUsername() != null ? proxy.getUsername() : "");
+                if (showPasswords) {
+                    if (proxyPasswords.containsKey(proxy.getId())) {
+                        row.addContent(proxyPasswords.get(proxy.getId()));
+                    } else {
+                        if (cipher.isEncryptedString(proxy.getPassword())) {
+                            row.addContent(proxy.getPassword() + " (can't decrypt)");
+                        } else {
+                            row.addContent(proxy.getPassword() == null ? "" : proxy.getPassword());
+                        }
+                    }
+                }
+            }
+            table.print(System.out);
+        } else {
+            System.out.print("No HTTP proxies configured");
+            if (settings != null && settings.value != null) {
+                System.out.print(" in " + settings.value);
+            }
+            System.out.println();
+        }
+
+        System.out.println();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index 00ca8c8..9e9bf26 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -17,6 +17,7 @@
 package org.apache.karaf.maven.command;
 
 import java.io.File;
+import java.lang.reflect.Field;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Arrays;
@@ -30,9 +31,13 @@ import java.util.Set;
 
 import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Option;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.Session;
 import org.apache.maven.settings.Profile;
+import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.building.DefaultSettingsBuilder;
 import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
@@ -41,6 +46,9 @@ import org.apache.maven.settings.building.SettingsBuildingException;
 import org.apache.maven.settings.building.SettingsBuildingRequest;
 import org.apache.maven.settings.building.SettingsBuildingResult;
 import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
+import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
+import org.apache.maven.settings.crypto.SettingsDecryptionResult;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -94,6 +102,7 @@ public abstract class MavenConfigurationSupport implements Action {
     protected SourceAnd<File> securitySettings;
     protected SettingsSecurity mavenSecuritySettings;
 
+    protected Map<String, Server> servers = new HashMap<>();
     protected Map<String, String> serverPasswords = new HashMap<>();
     protected Map<String, String> proxyPasswords = new HashMap<>();
 
@@ -101,6 +110,7 @@ public abstract class MavenConfigurationSupport implements Action {
 
     private static final String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
     protected String masterPassword;
+    protected DefaultPlexusCipher cipher;
 
     @Reference
     protected ConfigurationAdmin cm;
@@ -108,12 +118,19 @@ public abstract class MavenConfigurationSupport implements Action {
     @Reference
     protected BundleContext context;
 
+    @Reference
+    protected Session session;
+
+    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Do not hide passwords related to Maven encryption", required = false, multiValued = false)
+    boolean showPasswords;
+
     @Override
     final public Object execute() throws Exception {
         Configuration c = cm.getConfiguration(PID);
 
         if (c != null && c.getProperties() != null) {
             try {
+                cipher = new DefaultPlexusCipher();
                 securitySettings = securitySettings((String) c.getProperties().get(PID + "." + PROPERTY_SECURITY_FILE));
                 if (securitySettings != null && securitySettings.value != null) {
                     mavenSecuritySettings = readSecuritySettings(securitySettings.value);
@@ -126,6 +143,10 @@ public abstract class MavenConfigurationSupport implements Action {
 
                 localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
 
+                if (showPasswords) {
+                    decryptSettings();
+                }
+
                 doAction(PID + ".", c.getProperties());
             } catch (Exception e) {
                 System.err.println(e.getMessage());
@@ -321,7 +342,8 @@ public abstract class MavenConfigurationSupport implements Action {
     }
 
     /**
-     * Reads on demand <code>settings.xml</code> file - with password decryption
+     * Reads on demand <code>settings.xml</code> file - without password decryption. Also
+     * collects declared servers by ID.
      * @param settingsFile
      */
     protected synchronized Settings readSettings(File settingsFile) throws SettingsBuildingException {
@@ -342,7 +364,13 @@ public abstract class MavenConfigurationSupport implements Action {
                 }
                 return null;
             } else {
-                return result.getEffectiveSettings();
+                Settings settings = result.getEffectiveSettings();
+                if (settings.getServers() != null) {
+                    for (Server server : settings.getServers()) {
+                        servers.put(server.getId(), server);
+                    }
+                }
+                return settings;
             }
         } catch (Throwable e) {
             System.err.println(e.getMessage());
@@ -373,9 +401,42 @@ public abstract class MavenConfigurationSupport implements Action {
      * <p>Decrypts passwords inside correctly read <code>settings.xml</code>. Also tries to decrypt master password.</p>
      * <p>Not called implicitly for each action invocation.</p>
      */
-    protected void decryptSettings() throws Exception {
-        if (mavenSecuritySettings != null) {
-            masterPassword = new DefaultPlexusCipher().decryptDecorated(mavenSecuritySettings.getMaster(), masterMasterPassword);
+    private void decryptSettings() throws Exception {
+        if (mavenSecuritySettings != null && mavenSettings != null) {
+            masterPassword = cipher.decryptDecorated(mavenSecuritySettings.getMaster(), masterMasterPassword);
+            DefaultSecDispatcher dispatcher = new DefaultSecDispatcher();
+            DefaultSettingsDecrypter decrypter = new DefaultSettingsDecrypter();
+            try {
+                dispatcher.setConfigurationFile(securitySettings.value.getAbsolutePath());
+                Field f = dispatcher.getClass().getDeclaredField("_cipher");
+                f.setAccessible(true);
+                f.set(dispatcher, cipher);
+
+                f = decrypter.getClass().getDeclaredField("securityDispatcher");
+                f.setAccessible(true);
+                f.set(decrypter, dispatcher);
+
+                DefaultSettingsDecryptionRequest req = new DefaultSettingsDecryptionRequest(mavenSettings);
+                SettingsDecryptionResult res = decrypter.decrypt(req);
+                if (res.getProblems() != null && res.getProblems().size() > 0) {
+                    for (SettingsProblem sp : res.getProblems()) {
+                        System.err.println(sp);
+                    }
+                }
+
+                for (Proxy proxy : res.getProxies()) {
+                    if (!cipher.isEncryptedString(proxy.getPassword())) {
+                        proxyPasswords.put(proxy.getId(), proxy.getPassword());
+                    }
+                }
+                for (Server server : res.getServers()) {
+                    if (!cipher.isEncryptedString(server.getPassword())) {
+                        serverPasswords.put(server.getId(), server.getPassword());
+                    }
+                }
+            } catch (Throwable t) {
+                LOG.warn("Can't decrypt " + securitySettings.value, t);
+            }
         }
     }
 
@@ -392,7 +453,9 @@ public abstract class MavenConfigurationSupport implements Action {
 
         if (remote) {
             if (repositories.length == 0 || repositories.length > 0 && repositories[0].charAt(0) == '+') {
-                repositories[0] = repositories[0].substring(1);
+                if (repositories.length > 0) {
+                    repositories[0] = repositories[0].substring(1);
+                }
 
                 List<String> newRepositories = new LinkedList<>();
                 newRepositories.addAll(Arrays.asList(repositories));

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
deleted file mode 100644
index 7e13047..0000000
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
+++ /dev/null
@@ -1,70 +0,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.
- */
-package org.apache.karaf.maven.command;
-
-import java.util.Dictionary;
-
-import org.apache.karaf.maven.core.MavenRepositoryURL;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.apache.karaf.shell.support.table.ShellTable;
-
-@Command(scope = "maven", name = "repo-list", description = "Maven repository summary.")
-@Service
-public class RepoListCommand extends MavenConfigurationSupport {
-
-    @Override
-    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
-        ShellTable table = new ShellTable();
-        table.column("ID");
-        table.column("URL");
-        table.column("Snapshots");
-        table.column("Releases");
-        table.column("Defined in");
-
-        System.out.println("== Remote repositories");
-        MavenRepositoryURL[] repositories = repositories(config, true);
-        for (MavenRepositoryURL repoURL : repositories) {
-            table.addRow().addContent(repoURL.getId(),
-                    repoURL.getURL(),
-                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
-                    repoURL.isReleasesEnabled() ? "yes" : "no",
-                    repoURL.getFrom());
-        }
-
-        table.print(System.out);
-
-        table = new ShellTable();
-        table.column("ID");
-        table.column("URL");
-        table.column("Snapshots");
-        table.column("Releases");
-        System.out.println();
-        System.out.println("== Default repositories");
-        repositories = repositories(config, false);
-        for (MavenRepositoryURL repoURL : repositories) {
-            table.addRow().addContent(repoURL.getId(),
-                    repoURL.getURL(),
-                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
-                    repoURL.isReleasesEnabled() ? "yes" : "no",
-                    repoURL.getFrom());
-        }
-
-        table.print(System.out);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
new file mode 100644
index 0000000..13bcbdb
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+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;
+
+@Command(scope = "maven", name = "repository-add", description = "Adds Maven repository")
+@Service
+public class RepositoryAddCommand extends RepositoryEditCommandSupport {
+
+    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Do not hide passwords related to Maven encryption", required = false, multiValued = false)
+    boolean showPasswords;
+
+    @Override
+    protected void edit() {
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
new file mode 100644
index 0000000..0179b02
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+import org.apache.karaf.shell.api.action.Option;
+
+public abstract class RepositoryEditCommandSupport extends MavenConfigurationSupport {
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        edit();
+
+        session.execute("maven:repository-list");
+    }
+
+    protected abstract void edit();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
new file mode 100644
index 0000000..b2d31be
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
@@ -0,0 +1,135 @@
+/*
+ * 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.maven.command;
+
+import java.util.Dictionary;
+
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+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.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+import org.apache.maven.settings.Server;
+
+@Command(scope = "maven", name = "repository-list", description = "Maven repository summary.")
+@Service
+public class RepositoryListCommand extends MavenConfigurationSupport {
+
+    @Option(name = "-v", aliases = { "--verbose" }, description = "Show additional information (policies, source)", required = false, multiValued = false)
+    boolean verbose;
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        ShellTable table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        if (verbose) {
+            table.column("Releases");
+            table.column("Snapshots");
+            table.column("Defined in");
+        }
+        if (showPasswords) {
+            table.column("Username");
+            table.column("Password");
+        }
+
+        System.out.println();
+        System.out.println("== Remote repositories");
+        MavenRepositoryURL[] repositories = repositories(config, true);
+        for (MavenRepositoryURL repoURL : repositories) {
+            Row row = table.addRow();
+            row.addContent(repoURL.getId(), repoURL.getURL());
+            if (verbose) {
+                row.addContent(repositoryKindInfo(repoURL, false),
+                        repositoryKindInfo(repoURL, true),
+                        repoURL.getFrom());
+            }
+            if (showPasswords) {
+                if (servers.containsKey(repoURL.getId())) {
+                    Server server = servers.get(repoURL.getId());
+                    row.addContent(server.getUsername() == null ? "" : server.getUsername());
+                    if (serverPasswords.containsKey(repoURL.getId())) {
+                        row.addContent(serverPasswords.get(repoURL.getId()));
+                    } else {
+                        if (cipher.isEncryptedString(server.getPassword())) {
+                            row.addContent(server.getPassword() + " (can't decrypt)");
+                        } else {
+                            row.addContent(server.getPassword() == null ? "" : server.getPassword());
+                        }
+                    }
+                } else {
+                    row.addContent("", "");
+                }
+            }
+        }
+
+        table.print(System.out);
+
+        table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        if (verbose) {
+            table.column("Releases");
+            table.column("Snapshots");
+        }
+
+        System.out.println();
+        System.out.println("== Default repositories");
+        repositories = repositories(config, false);
+        for (MavenRepositoryURL repoURL : repositories) {
+            Row row = table.addRow();
+            row.addContent(repoURL.getId(),
+                    repoURL.getURL());
+            if (verbose) {
+                row.addContent(repositoryKindInfo(repoURL, false),
+                        repositoryKindInfo(repoURL, true),
+                        repoURL.getFrom());
+            }
+        }
+
+        table.print(System.out);
+        System.out.println();
+    }
+
+    /**
+     * Information about release/snapshot handing for give repository URL
+     * @param repoURL
+     * @param snapshots
+     * @return
+     */
+    private Object repositoryKindInfo(MavenRepositoryURL repoURL, boolean snapshots) {
+        if (snapshots) {
+            if (repoURL.isSnapshotsEnabled()) {
+                String snapshotsUpdatePolicy = repoURL.getSnapshotsUpdatePolicy();
+                return String.format("yes (%s)",
+                        snapshotsUpdatePolicy == null || "".equals(snapshotsUpdatePolicy.trim()) ? "daily" : snapshotsUpdatePolicy
+                );
+            }
+        } else {
+            if (repoURL.isReleasesEnabled()) {
+                String releasesUpdatePolicy = repoURL.getReleasesUpdatePolicy();
+                return String.format("yes (%s)",
+                        releasesUpdatePolicy == null || "".equals(releasesUpdatePolicy.trim()) ? "daily" : releasesUpdatePolicy
+                );
+            }
+        }
+
+        return "no";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
new file mode 100644
index 0000000..46f82c8
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Command(scope = "maven", name = "repository-remove", description = "Removes Maven repository")
+@Service
+public class RepositoryRemoveCommand extends RepositoryEditCommandSupport {
+
+    @Override
+    protected void edit() {
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e254d83f/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index 6892939..be71a93 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -39,9 +39,6 @@ public class SummaryCommand extends MavenConfigurationSupport {
     @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
     boolean description;
 
-    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Show passwords related to Maven encryption", required = false, multiValued = false)
-    boolean showPasswords;
-
     @Override
     protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
         ShellTable table = new ShellTable();
@@ -64,7 +61,6 @@ public class SummaryCommand extends MavenConfigurationSupport {
                 "Settings file that contain (or relocates to) master Maven password");
 
         if (showPasswords) {
-            decryptSettings();
             addRow(table, propertyIds ? "<master>" : "Master password", new SourceAnd<String>(securitySettings.source, masterPassword),
                     "Master password used to decrypt proxy and server passwords");
         }


[10/12] karaf git commit: [KARAF-5008] maven:repository-add command

Posted by gg...@apache.org.
[KARAF-5008] maven:repository-add command


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

Branch: refs/heads/master-maven-commands
Commit: 73953ccaa91017a575fe56235a849369c3ed8452
Parents: 420207b
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Wed Jun 21 09:33:51 2017 +0200
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Wed Jun 21 09:33:51 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              |   6 +
 .../command/MavenConfigurationSupport.java      |  81 +++++++-
 .../karaf/maven/command/PasswordCommand.java    |   2 +
 .../maven/command/RepositoryAddCommand.java     | 196 ++++++++++++++++++-
 .../command/RepositoryEditCommandSupport.java   |  22 ++-
 .../maven/command/RepositoryRemoveCommand.java  |   4 +-
 .../karaf/maven/command/SummaryCommand.java     |  51 -----
 .../karaf/maven/core/MavenRepositoryURL.java    |  47 +++++
 .../org/apache/karaf/maven/SettingsTest.java    |   2 +
 .../command/MavenConfigurationSupportTest.java  |   8 +-
 .../maven/core/MavenRepositoryURLTest.java      |  64 ++++++
 11 files changed, 420 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
index a2a724f..403835e 100644
--- a/maven/core/pom.xml
+++ b/maven/core/pom.xml
@@ -66,6 +66,11 @@
             <artifactId>maven-embedder</artifactId>
             <version>3.0.3</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <scope>provided</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -111,6 +116,7 @@
                             *,
                         </Import-Package>
                         <Private-Package>
+                            org.apache.felix.utils.properties;-split-package:=merge-first,
                             org.apache.karaf.maven.command,
                             org.apache.karaf.maven.core,
                             org.apache.maven.settings.*;-split-package:=merge-first,

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index 0588afd..b64e583 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -460,7 +460,7 @@ public abstract class MavenConfigurationSupport implements Action {
         String[] repositories = listOfValues((String) config.get(property));
 
         if (remote) {
-            if (repositories.length == 0 || repositories.length > 0 && repositories[0].charAt(0) == '+') {
+            if (repositories.length == 0 || repositories[0].charAt(0) == '+') {
                 if (repositories.length > 0) {
                     repositories[0] = repositories[0].substring(1);
                 }
@@ -604,13 +604,92 @@ public abstract class MavenConfigurationSupport implements Action {
         return result;
     }
 
+    /**
+     * This method controls whether passwords are tried to be decrypted.
+     * @return
+     */
     protected boolean showPasswords() {
         return false;
     }
 
+    /**
+     * Parses update policy value and returns {@link SourceAnd}<code>&lt;String&gt;</code> about the value
+     * @param policy
+     * @return
+     */
+    protected SourceAnd<String> updatePolicy(String policy) {
+        SourceAnd<String> result = new SourceAnd<>();
+        result.value = policy;
+
+        if (policy == null || "".equals(policy.trim())) {
+            result.value = "";
+            result.valid = false;
+            result.source = "Implicit \"never\", but doesn't override repository-specific value";
+            return result;
+        }
+
+        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_UPDATE_POLICY);
+        if ("always".equals(policy) || "never".equals(policy) || "daily".equals(policy)) {
+            // ok
+            result.valid = true;
+        } else if (policy.startsWith("interval")) {
+            int minutes = 1440;
+            try {
+                String n = policy.substring("interval".length() + 1);
+                minutes = Integer.parseInt(n);
+                result.valid = true;
+            } catch (Exception e) {
+                result.valid = false;
+                result.value = "interval:1440";
+                result.source = "Implicit \"interval:1440\" (error parsing \"" + policy + "\")";
+            }
+        } else {
+            result.valid = false;
+            result.value = "never";
+            result.source = "Implicit \"never\" (unknown value \"" + policy + "\")";
+        }
+
+        return result;
+    }
+
+    /**
+     * Parses checksum policy value and returns {@link SourceAnd}<code>&lt;String&gt;</code> about the value
+     * @param policy
+     * @return
+     */
+    protected SourceAnd<String> checksumPolicy(String policy) {
+        SourceAnd<String> result = new SourceAnd<>();
+        result.value = policy;
+
+        if (policy == null || "".equals(policy.trim())) {
+            result.valid = false;
+            result.value = "warn";
+            result.source = "Default \"warn\"";
+            return result;
+        }
+
+        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_CHECKSUM_POLICY);
+        if ("ignore".equals(policy) || "warn".equals(policy) || "fail".equals(policy)) {
+            // ok
+            result.valid = true;
+        } else {
+            result.valid = false;
+            result.value = "warn";
+            result.source = "Implicit \"warn\" (unknown value \"" + policy + "\")";
+        }
+
+        return result;
+    }
+
+    /**
+     * Handy class containing value and information about its origin. <code>valid</code> may be used to indicate
+     * if the value is correct. It may be implicit, but the interpretation of <code>valid </code> is not defined.
+     * @param <T>
+     */
     protected static class SourceAnd<T> {
         String source;
         T value;
+        boolean valid;
 
         public SourceAnd() {
         }

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
index ed44b35..4243212 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
@@ -61,6 +61,7 @@ public class PasswordCommand extends MavenConfigurationSupport {
             }
             String password = session.readLine("Password to encrypt: ", '*');
             System.out.println("Encrypted password: " + cipher.encryptAndDecorate(password, masterPassword));
+            System.out.println("You can use this encrypted password when defining repositories and proxies");
             return;
         }
 
@@ -79,6 +80,7 @@ public class PasswordCommand extends MavenConfigurationSupport {
                 File dataDir = context.getDataFile(".");
                 if (!dataDir.isDirectory()) {
                     System.err.println("Can't access data directory for " + context.getBundle().getSymbolicName() + " bundle");
+                    return;
                 }
                 File newSecuritySettingsFile = nextSequenceFile(dataDir, RE_SECURITY_SETTINGS, PATTERN_SECURITY_SETTINGS);
                 try (FileWriter fw = new FileWriter(newSecuritySettingsFile)) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
index 13bcbdb..11034d3 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
@@ -16,20 +16,210 @@
  */
 package org.apache.karaf.maven.command;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.felix.utils.properties.InterpolationHelper;
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+import org.apache.karaf.shell.api.action.Argument;
 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.maven.settings.Server;
+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
+import org.ops4j.pax.url.mvn.ServiceConstants;
+import org.osgi.service.cm.Configuration;
 
 @Command(scope = "maven", name = "repository-add", description = "Adds Maven repository")
 @Service
 public class RepositoryAddCommand extends RepositoryEditCommandSupport {
 
-    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Do not hide passwords related to Maven encryption", required = false, multiValued = false)
-    boolean showPasswords;
+    @Option(name = "-idx", description = "Index at which new repository is to be inserted (0-based) (defaults to last - repository will be appended)", required = false, multiValued = false)
+    int idx = -1;
+
+    @Option(name = "-s", aliases = { "--snapshots" }, description = "Enable SNAPSHOT handling in the repository", required = false, multiValued = false)
+    boolean snapshots = false;
+
+    @Option(name = "-nr", aliases = { "--no-releases" }, description = "Disable release handling in this repository", required = false, multiValued = false)
+    boolean noReleases = false;
+
+    @Option(name = "-up", aliases = { "--update-policy" }, description = "Update policy for repository (never, daily (default), interval:N, always)", required = false, multiValued = false)
+    String updatePolicy = "daily";
+
+    @Option(name = "-cp", aliases = { "--checksum-policy" }, description = "Checksum policy for repository (ignore, warn (default), fail)", required = false, multiValued = false)
+    String checksumPolicy = "warn";
+
+    @Argument(description = "Repository URI. It may be file:// based, http(s):// based, may use other known protocol or even property placeholders (like ${karaf.base})")
+    String uri;
+
+    @Option(name = "-u", aliases = { "--username" }, description = "Username for remote repository", required = false, multiValued = false)
+    String username;
+
+    @Option(name = "-p", aliases = { "--password" }, description = "Password for remote repository (may be encrypted, see \"maven:password -ep\")", required = false, multiValued = false)
+    String password;
 
     @Override
-    protected void edit() {
+    protected void edit(String prefix, Dictionary<String, Object> config) throws Exception {
+        MavenRepositoryURL[] repositories = repositories(config, !defaultRepository);
+
+        MavenRepositoryURL[] repositoriesFromPidProperty = Arrays.stream(repositories)
+                .filter((repo) -> repo.getFrom() == MavenRepositoryURL.FROM.PID)
+                .toArray(MavenRepositoryURL[]::new);
+
+        if (idx > repositoriesFromPidProperty.length) {
+            // TOCONSIDER: should we allow to add repository to settings.xml too?
+            System.err.printf("List of %s repositories has %d elements. Can't insert at position %s.\n",
+                    (defaultRepository ? "default" : "remote"), repositories.length, id);
+            return;
+        }
+
+        if (id == null || "".equals(id.trim())) {
+            System.err.println("Please specify ID of repository");
+            return;
+        }
+
+        Optional<MavenRepositoryURL> first = Arrays.stream(repositories)
+                .filter((repo) -> id.equals(repo.getId())).findAny();
+        if (first.isPresent()) {
+            System.err.printf("Repository with ID \"%s\" is already configured for URL %s\n", id, first.get().getURL());
+            return;
+        }
+
+        SourceAnd<String> up = updatePolicy(updatePolicy);
+        if (!up.valid) {
+            System.err.println("Unknown value of update policy: \"" + updatePolicy + "\"");
+            return;
+        }
+
+        SourceAnd<String> cp = checksumPolicy(checksumPolicy);
+        if (!cp.valid) {
+            System.err.println("Unknown value of checksum policy: \"" + checksumPolicy + "\"");
+            return;
+        }
+
+        if (uri == null || "".equals(uri.trim())) {
+            System.err.println("Please specify repository location");
+            return;
+        }
+        String urlResolved = InterpolationHelper.substVars(uri, "uri", null, null, context);
+        URL url = null;
+        try {
+            url = new URL(urlResolved);
+            urlResolved = url.toString();
+
+            if ("file".equals(url.getProtocol()) && new File(url.toURI()).isDirectory()) {
+                System.err.println("Location \"" + urlResolved + "\" is not accessible");
+                return;
+            }
+        } catch (MalformedURLException e) {
+            // a directory?
+            File location = new File(urlResolved);
+            if (!location.exists() || !location.isDirectory()) {
+                System.err.println("Location \"" + urlResolved + "\" is not accessible");
+                return;
+            } else {
+                url = location.toURI().toURL();
+                urlResolved = url.toString();
+            }
+        }
+
+        if (defaultRepository && !"file".equals(url.getProtocol())) {
+            System.err.println("Default repositories should be locally accessible (use file:// protocol or normal directory path)");
+            return;
+        }
+
+        boolean hasUsername = username != null && !"".equals(username.trim());
+        boolean hasPassword = password != null && !"".equals(password.trim());
+        boolean hasCredentials = hasUsername && hasPassword;
+
+        if ((hasUsername && !hasPassword) || (!hasUsername && hasPassword)) {
+            System.err.println("Please specify both username and password");
+            return;
+        }
+
+        if (defaultRepository && hasCredentials) {
+            System.out.println("User credentials won't be used for default repository");
+            // no return
+        }
+
+        // credentials for remote repository can be stored only in settings.xml
+
+        if (!defaultRepository && hasCredentials) {
+            if (!confirm("Maven settings will be updated and org.ops4j.pax.url.mvn.settings property will change. Continue? (y/N) ")) {
+                return;
+            }
+
+            File dataDir = context.getDataFile(".");
+            if (!dataDir.isDirectory()) {
+                System.err.println("Can't access data directory for " + context.getBundle().getSymbolicName() + " bundle");
+                return;
+            }
+
+            Optional<Server> existingServer = mavenSettings.getServers().stream()
+                    .filter((s) -> id.equals(s.getId())).findAny();
+            Server server = null;
+            if (existingServer.isPresent()) {
+                server = existingServer.get();
+            } else {
+                server = new Server();
+                server.setId(id);
+                mavenSettings.getServers().add(server);
+            }
+            server.setUsername(username);
+            server.setPassword(password);
+
+            // prepare configadmin configuration update
+            File newSettingsFile = nextSequenceFile(dataDir, RE_SETTINGS, PATTERN_SETTINGS);
+            config.put(prefix + PROPERTY_SETTINGS_FILE, newSettingsFile.getCanonicalPath());
+
+            try (FileWriter fw = new FileWriter(newSettingsFile)) {
+                new SettingsXpp3Writer().write(fw, mavenSettings);
+            }
+            System.out.println("New settings stored in \"" + newSettingsFile.getCanonicalPath() + "\"");
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append(urlResolved);
+        sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ID + "=" + id);
+        if (snapshots) {
+            sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ALLOW_SNAPSHOTS);
+        }
+        if (noReleases) {
+            sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_DISALLOW_RELEASES);
+        }
+        sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_UPDATE + "=" + updatePolicy);
+        sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_CHECKSUM + "=" + checksumPolicy);
+
+        MavenRepositoryURL newRepository = new MavenRepositoryURL(sb.toString());
+        List<MavenRepositoryURL> newRepos = new LinkedList<>(Arrays.asList(repositoriesFromPidProperty));
+        if (idx >= 0) {
+            newRepos.add(idx, newRepository);
+        } else {
+            newRepos.add(newRepository);
+        }
+
+        String newList = newRepos.stream().map(MavenRepositoryURL::asRepositorySpec)
+                .collect(Collectors.joining(","));
+
+        if (defaultRepository) {
+            config.put(prefix + PROPERTY_DEFAULT_REPOSITORIES, newList);
+        } else {
+            config.put(prefix + PROPERTY_REPOSITORIES, newList);
+        }
+
+        Configuration cmConfig = cm.getConfiguration(PID);
+        cmConfig.update(config);
 
+        success = true;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
index 12700d0..9f403c1 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
@@ -23,13 +23,27 @@ import org.apache.karaf.shell.api.action.Option;
 
 public abstract class RepositoryEditCommandSupport extends MavenSecuritySupport {
 
+    @Option(name = "-id", description = "Identifier of repository", required = true, multiValued = false)
+    String id;
+
+    @Option(name = "-d", aliases = { "--default" }, description = "Edit default repository instead of remote one", required = false, multiValued = false)
+    boolean defaultRepository = false;
+
+    boolean success = false;
+
     @Override
-    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
-        edit();
+    public final void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        edit(prefix, config);
 
-        session.execute("maven:repository-list");
+        if (success) {
+            if (showPasswords) {
+                session.execute("maven:repository-list -x");
+            } else {
+                session.execute("maven:repository-list");
+            }
+        }
     }
 
-    protected abstract void edit();
+    protected abstract void edit(String prefix, Dictionary<String, Object> config) throws Exception;
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
index 46f82c8..eaf62e5 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
@@ -16,6 +16,8 @@
  */
 package org.apache.karaf.maven.command;
 
+import java.util.Dictionary;
+
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 
@@ -24,7 +26,7 @@ import org.apache.karaf.shell.api.action.lifecycle.Service;
 public class RepositoryRemoveCommand extends RepositoryEditCommandSupport {
 
     @Override
-    protected void edit() {
+    protected void edit(String prefix, Dictionary<String, Object> config) throws Exception {
 
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index 3f7e91a..c4e4c03 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -185,55 +185,4 @@ public class SummaryCommand extends MavenSecuritySupport {
         }
     }
 
-    private SourceAnd<String> updatePolicy(String cmProperty) {
-        SourceAnd<String> result = new SourceAnd<>();
-        result.value = cmProperty;
-
-        if (cmProperty == null || "".equals(cmProperty.trim())) {
-            result.value = "";
-            result.source = "Implicit \"never\", but doesn't override repository-specific value";
-            return result;
-        }
-
-        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_UPDATE_POLICY);
-        if ("always".equals(cmProperty) || "never".equals(cmProperty) || "daily".equals(cmProperty)) {
-            // ok
-        } else if (cmProperty.startsWith("interval")) {
-            int minutes = 1440;
-            try {
-                String n = cmProperty.substring("interval".length() + 1);
-                minutes = Integer.parseInt(n);
-            } catch (Exception e) {
-                result.value = "interval:1440";
-                result.source = "Implicit \"interval:1440\" (error parsing \"" + cmProperty + "\")";
-            }
-        } else {
-            result.value = "never";
-            result.source = "Implicit \"never\" (unknown value \"" + cmProperty + "\")";
-        }
-
-        return result;
-    }
-
-    private SourceAnd<String> checksumPolicy(String cmProperty) {
-        SourceAnd<String> result = new SourceAnd<>();
-        result.value = cmProperty;
-
-        if (cmProperty == null || "".equals(cmProperty.trim())) {
-            result.value = "warn";
-            result.source = "Default \"warn\"";
-            return result;
-        }
-
-        result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_GLOBAL_CHECKSUM_POLICY);
-        if ("ignore".equals(cmProperty) || "warn".equals(cmProperty) || "fail".equals(cmProperty)) {
-            // ok
-        } else {
-            result.value = "warn";
-            result.source = "Implicit \"warn\" (unknown value \"" + cmProperty + "\")";
-        }
-
-        return result;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
index 630976b..1c422c8 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
@@ -22,6 +22,7 @@ import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.Objects;
 
 import org.ops4j.pax.url.mvn.ServiceConstants;
 import org.slf4j.Logger;
@@ -367,6 +368,52 @@ public class MavenRepositoryURL
             .toString();
     }
 
+    public String asRepositorySpec() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(m_repositoryURL.toString());
+        if (m_id != null) {
+            sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ID + "=" + m_id);
+        }
+        if (!m_releasesEnabled) {
+            sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_DISALLOW_RELEASES);
+        }
+        if (m_snapshotsEnabled) {
+            sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ALLOW_SNAPSHOTS);
+        }
+        if (m_releasesEnabled) {
+            if (!m_snapshotsEnabled) {
+                if (m_releasesUpdatePolicy != null) {
+                    sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_RELEASES_UPDATE + "=" + m_releasesUpdatePolicy);
+                }
+                if (m_releasesChecksumPolicy != null) {
+                    sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_RELEASES_CHECKSUM + "=" + m_releasesChecksumPolicy);
+                }
+            }
+        }
+        if (m_snapshotsEnabled) {
+            if (!m_releasesEnabled) {
+                if (m_snapshotsUpdatePolicy != null) {
+                    sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_SNAPSHOTS_UPDATE + "=" + m_snapshotsUpdatePolicy);
+                }
+                if (m_snapshotsChecksumPolicy != null) {
+                    sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_SNAPSHOTS_CHECKSUM + "=" + m_snapshotsChecksumPolicy);
+                }
+            }
+        }
+        if (m_snapshotsEnabled && m_releasesEnabled) {
+            // compact snapshots & release update & checksum policies?
+            if (m_releasesUpdatePolicy != null && Objects.equals(m_releasesUpdatePolicy, m_snapshotsUpdatePolicy)) {
+                sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_UPDATE + "=" + m_releasesUpdatePolicy);
+            }
+            if (m_releasesChecksumPolicy != null && Objects.equals(m_releasesChecksumPolicy, m_snapshotsChecksumPolicy)) {
+                sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_CHECKSUM + "=" + m_releasesChecksumPolicy);
+            }
+        }
+
+        return sb.toString();
+    }
+
     public static enum FROM {
         PID("PID configuration"),
         SETTINGS("Maven XML settings"),

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
index 3ecaf30..901efc3 100644
--- a/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
+++ b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
@@ -32,6 +32,8 @@ public class SettingsTest {
         Settings settings = new Settings();
         Server s = new Server();
         s.setId("id");
+        s.setUsername("admin");
+        s.setPassword("admin");
         settings.getServers().add(s);
 
         new DefaultSettingsWriter().write(System.out, null, settings);

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java b/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
index 16ffc3f..991ace1 100644
--- a/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
+++ b/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
@@ -22,11 +22,13 @@ import java.io.IOException;
 import java.util.Dictionary;
 import java.util.regex.Pattern;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Test;
 import shaded.org.apache.commons.io.FileUtils;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 public class MavenConfigurationSupportTest {
 
@@ -42,19 +44,19 @@ public class MavenConfigurationSupportTest {
         };
 
         File newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
-        assertThat(newFile.getName(), equalTo("file-0001.txt"));
+        assertTrue(Pattern.compile("^file-\\d+\\.txt$").matcher(newFile.getName()).matches());
 
         try (FileWriter fw = new FileWriter(new File(dataDir, "file-abcd.txt"))) {
             fw.write("~");
         }
         newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
-        assertThat(newFile.getName(), equalTo("file-0001.txt"));
+        assertTrue(Pattern.compile("^file-\\d+\\.txt$").matcher(newFile.getName()).matches());
 
         try (FileWriter fw = new FileWriter(new File(dataDir, "file-0004.txt"))) {
             fw.write("~");
         }
         newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
-        assertThat(newFile.getName(), equalTo("file-0005.txt"));
+        assertTrue(Pattern.compile("^file-\\d+\\.txt$").matcher(newFile.getName()).matches());
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/73953cca/maven/core/src/test/java/org/apache/karaf/maven/core/MavenRepositoryURLTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/core/MavenRepositoryURLTest.java b/maven/core/src/test/java/org/apache/karaf/maven/core/MavenRepositoryURLTest.java
new file mode 100644
index 0000000..d460e0e
--- /dev/null
+++ b/maven/core/src/test/java/org/apache/karaf/maven/core/MavenRepositoryURLTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.maven.core;
+
+import java.net.MalformedURLException;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class MavenRepositoryURLTest {
+
+    @Test
+    public void uris() throws MalformedURLException {
+        String uri1, uri2;
+        MavenRepositoryURL mavenURI;
+
+        uri1 = "http://localhost/@id=id1@snapshots@update=interval:42@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@snapshots@update=interval:42";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+
+        uri1 = "http://localhost/@id=id1@snapshots@checksum=fail@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@snapshots@checksum=fail";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+
+        uri1 = "http://localhost/@id=id1@snapshots@noreleases@update=interval:42@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@noreleases@snapshots@snapshotsUpdate=interval:42";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+
+        uri1 = "http://localhost/@id=id1@update=interval:42@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@releasesUpdate=interval:42";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+
+        uri1 = "http://localhost/@id=id1@snapshots@noreleases@checksum=fail@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@noreleases@snapshots@snapshotsChecksum=fail";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+
+        uri1 = "http://localhost/@id=id1@checksum=fail@_from=" + MavenRepositoryURL.FROM.SETTINGS;
+        uri2 = "http://localhost/@id=id1@releasesChecksum=fail";
+        mavenURI = new MavenRepositoryURL(uri1);
+        assertThat(mavenURI.asRepositorySpec(), equalTo(uri2));
+    }
+
+}


[11/12] karaf git commit: [KARAF-5008] maven:repository-change and maven:repository-remove commands

Posted by gg...@apache.org.
[KARAF-5008] maven:repository-change and maven:repository-remove commands


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

Branch: refs/heads/master-maven-commands
Commit: df8f29204996967607908d71b8c28aae284ea86f
Parents: 73953cc
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Wed Jun 21 13:36:40 2017 +0200
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Wed Jun 21 13:36:40 2017 +0200

----------------------------------------------------------------------
 .../command/MavenConfigurationSupport.java      |  38 +++-
 .../maven/command/RepositoryAddCommand.java     | 109 ++--------
 .../maven/command/RepositoryChangeCommand.java  | 197 +++++++++++++++++++
 .../command/RepositoryEditCommandSupport.java   | 148 +++++++++++++-
 .../maven/command/RepositoryRemoveCommand.java  |  59 +++++-
 .../karaf/maven/core/MavenRepositoryURL.java    |  46 ++++-
 6 files changed, 484 insertions(+), 113 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index b64e583..c028530 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -17,6 +17,7 @@
 package org.apache.karaf.maven.command;
 
 import java.io.File;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.net.MalformedURLException;
@@ -54,6 +55,8 @@ import org.apache.maven.settings.building.SettingsProblem;
 import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
+import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
+import org.ops4j.pax.url.mvn.ServiceConstants;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -170,8 +173,8 @@ public abstract class MavenConfigurationSupport implements Action {
     /**
      * Performs command action on <strong>existing</strong> <code>org.ops4j.pax.url.mvn</code>
      * PID configuration
-     * @param prefix
-     * @param config
+     * @param prefix prefix for properties inside <code>org.ops4j.pax.url.mvn</code> PID
+     * @param config <code>org.ops4j.pax.url.mvn</code> PID configuration taken from {@link ConfigurationAdmin}
      */
     abstract protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception;
 
@@ -491,17 +494,19 @@ public abstract class MavenConfigurationSupport implements Action {
 
                             if (repo.getReleases() != null) {
                                 if (!repo.getReleases().isEnabled()) {
-                                    builder.append("@noreleases");
+                                    builder.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_DISALLOW_RELEASES);
                                 }
-                                addPolicy(builder, repo.getReleases().getUpdatePolicy(), "releasesUpdate");
+                                SourceAnd<String> up = updatePolicy(repo.getReleases().getUpdatePolicy());
+                                addPolicy(builder, "".equals(up.val()) ? "never" : up.val(), ServiceConstants.OPTION_RELEASES_UPDATE);
                                 // not used in pax-url-aether
                                 //addPolicy(builder, repo.getReleases().getChecksumPolicy(), "releasesChecksum");
                             }
                             if (repo.getSnapshots() != null) {
                                 if (repo.getSnapshots().isEnabled()) {
-                                    builder.append("@snapshots");
+                                    builder.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ALLOW_SNAPSHOTS);
                                 }
-                                addPolicy(builder, repo.getSnapshots().getUpdatePolicy(), "snapshotsUpdate");
+                                SourceAnd<String> up = updatePolicy(repo.getSnapshots().getUpdatePolicy());
+                                addPolicy(builder, "".equals(up.val()) ? "never" : up.val(), ServiceConstants.OPTION_SNAPSHOTS_UPDATE);
                                 // not used in pax-url-aether
                                 //addPolicy(builder, repo.getSnapshots().getChecksumPolicy(), "snapshotsChecksum");
                             }
@@ -682,6 +687,27 @@ public abstract class MavenConfigurationSupport implements Action {
     }
 
     /**
+     * Stores changed {@link org.apache.maven.settings.Settings} in new settings.xml file and updates
+     * <code>org.ops4j.pax.url.mvn.settings</code> property. Does <string>not</string> update
+     * {@link org.osgi.service.cm.ConfigurationAdmin} config.
+     * @param prefix
+     * @param config
+     */
+    protected void updateSettings(String prefix, Dictionary<String, Object> config) throws IOException {
+        File dataDir = context.getDataFile(".");
+        if (!dataDir.isDirectory()) {
+            throw new RuntimeException("Can't access data directory for " + context.getBundle().getSymbolicName() + " bundle");
+        }
+        File newSettingsFile = nextSequenceFile(dataDir, RE_SETTINGS, PATTERN_SETTINGS);
+        config.put(prefix + PROPERTY_SETTINGS_FILE, newSettingsFile.getCanonicalPath());
+
+        try (FileWriter fw = new FileWriter(newSettingsFile)) {
+            new SettingsXpp3Writer().write(fw, mavenSettings);
+        }
+        System.out.println("New settings stored in \"" + newSettingsFile.getCanonicalPath() + "\"");
+    }
+
+    /**
      * Handy class containing value and information about its origin. <code>valid</code> may be used to indicate
      * if the value is correct. It may be implicit, but the interpretation of <code>valid </code> is not defined.
      * @param <T>

http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
index 11034d3..1001ade 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryAddCommand.java
@@ -16,26 +16,17 @@
  */
 package org.apache.karaf.maven.command;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
-import org.apache.felix.utils.properties.InterpolationHelper;
 import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Argument;
 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.maven.settings.Server;
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
 import org.ops4j.pax.url.mvn.ServiceConstants;
 import org.osgi.service.cm.Configuration;
 
@@ -58,36 +49,27 @@ public class RepositoryAddCommand extends RepositoryEditCommandSupport {
     @Option(name = "-cp", aliases = { "--checksum-policy" }, description = "Checksum policy for repository (ignore, warn (default), fail)", required = false, multiValued = false)
     String checksumPolicy = "warn";
 
-    @Argument(description = "Repository URI. It may be file:// based, http(s):// based, may use other known protocol or even property placeholders (like ${karaf.base})")
-    String uri;
-
     @Option(name = "-u", aliases = { "--username" }, description = "Username for remote repository", required = false, multiValued = false)
     String username;
 
     @Option(name = "-p", aliases = { "--password" }, description = "Password for remote repository (may be encrypted, see \"maven:password -ep\")", required = false, multiValued = false)
     String password;
 
-    @Override
-    protected void edit(String prefix, Dictionary<String, Object> config) throws Exception {
-        MavenRepositoryURL[] repositories = repositories(config, !defaultRepository);
+    @Argument(description = "Repository URI. It may be file:// based, http(s):// based, may use other known protocol or even property placeholders (like ${karaf.base})")
+    String uri;
 
-        MavenRepositoryURL[] repositoriesFromPidProperty = Arrays.stream(repositories)
-                .filter((repo) -> repo.getFrom() == MavenRepositoryURL.FROM.PID)
-                .toArray(MavenRepositoryURL[]::new);
+    @Override
+    protected void edit(String prefix, Dictionary<String, Object> config,
+                        MavenRepositoryURL[] allRepos, MavenRepositoryURL[] pidRepos, MavenRepositoryURL[] settingsRepos) throws Exception {
 
-        if (idx > repositoriesFromPidProperty.length) {
+        if (idx > pidRepos.length) {
             // TOCONSIDER: should we allow to add repository to settings.xml too?
             System.err.printf("List of %s repositories has %d elements. Can't insert at position %s.\n",
-                    (defaultRepository ? "default" : "remote"), repositories.length, id);
+                    (defaultRepository ? "default" : "remote"), pidRepos.length, id);
             return;
         }
 
-        if (id == null || "".equals(id.trim())) {
-            System.err.println("Please specify ID of repository");
-            return;
-        }
-
-        Optional<MavenRepositoryURL> first = Arrays.stream(repositories)
+        Optional<MavenRepositoryURL> first = Arrays.stream(allRepos)
                 .filter((repo) -> id.equals(repo.getId())).findAny();
         if (first.isPresent()) {
             System.err.printf("Repository with ID \"%s\" is already configured for URL %s\n", id, first.get().getURL());
@@ -106,34 +88,8 @@ public class RepositoryAddCommand extends RepositoryEditCommandSupport {
             return;
         }
 
-        if (uri == null || "".equals(uri.trim())) {
-            System.err.println("Please specify repository location");
-            return;
-        }
-        String urlResolved = InterpolationHelper.substVars(uri, "uri", null, null, context);
-        URL url = null;
-        try {
-            url = new URL(urlResolved);
-            urlResolved = url.toString();
-
-            if ("file".equals(url.getProtocol()) && new File(url.toURI()).isDirectory()) {
-                System.err.println("Location \"" + urlResolved + "\" is not accessible");
-                return;
-            }
-        } catch (MalformedURLException e) {
-            // a directory?
-            File location = new File(urlResolved);
-            if (!location.exists() || !location.isDirectory()) {
-                System.err.println("Location \"" + urlResolved + "\" is not accessible");
-                return;
-            } else {
-                url = location.toURI().toURL();
-                urlResolved = url.toString();
-            }
-        }
-
-        if (defaultRepository && !"file".equals(url.getProtocol())) {
-            System.err.println("Default repositories should be locally accessible (use file:// protocol or normal directory path)");
+        SourceAnd<String> urlResolved = validateRepositoryURL(uri, defaultRepository);
+        if (!urlResolved.valid) {
             return;
         }
 
@@ -152,43 +108,15 @@ public class RepositoryAddCommand extends RepositoryEditCommandSupport {
         }
 
         // credentials for remote repository can be stored only in settings.xml
-
         if (!defaultRepository && hasCredentials) {
-            if (!confirm("Maven settings will be updated and org.ops4j.pax.url.mvn.settings property will change. Continue? (y/N) ")) {
+            if (!updateCredentials(force, id, username, password, prefix, config)) {
                 return;
             }
-
-            File dataDir = context.getDataFile(".");
-            if (!dataDir.isDirectory()) {
-                System.err.println("Can't access data directory for " + context.getBundle().getSymbolicName() + " bundle");
-                return;
-            }
-
-            Optional<Server> existingServer = mavenSettings.getServers().stream()
-                    .filter((s) -> id.equals(s.getId())).findAny();
-            Server server = null;
-            if (existingServer.isPresent()) {
-                server = existingServer.get();
-            } else {
-                server = new Server();
-                server.setId(id);
-                mavenSettings.getServers().add(server);
-            }
-            server.setUsername(username);
-            server.setPassword(password);
-
-            // prepare configadmin configuration update
-            File newSettingsFile = nextSequenceFile(dataDir, RE_SETTINGS, PATTERN_SETTINGS);
-            config.put(prefix + PROPERTY_SETTINGS_FILE, newSettingsFile.getCanonicalPath());
-
-            try (FileWriter fw = new FileWriter(newSettingsFile)) {
-                new SettingsXpp3Writer().write(fw, mavenSettings);
-            }
-            System.out.println("New settings stored in \"" + newSettingsFile.getCanonicalPath() + "\"");
+            updateSettings(prefix, config);
         }
 
         StringBuilder sb = new StringBuilder();
-        sb.append(urlResolved);
+        sb.append(urlResolved.val());
         sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ID + "=" + id);
         if (snapshots) {
             sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_ALLOW_SNAPSHOTS);
@@ -200,21 +128,14 @@ public class RepositoryAddCommand extends RepositoryEditCommandSupport {
         sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_CHECKSUM + "=" + checksumPolicy);
 
         MavenRepositoryURL newRepository = new MavenRepositoryURL(sb.toString());
-        List<MavenRepositoryURL> newRepos = new LinkedList<>(Arrays.asList(repositoriesFromPidProperty));
+        List<MavenRepositoryURL> newRepos = new LinkedList<>(Arrays.asList(pidRepos));
         if (idx >= 0) {
             newRepos.add(idx, newRepository);
         } else {
             newRepos.add(newRepository);
         }
 
-        String newList = newRepos.stream().map(MavenRepositoryURL::asRepositorySpec)
-                .collect(Collectors.joining(","));
-
-        if (defaultRepository) {
-            config.put(prefix + PROPERTY_DEFAULT_REPOSITORIES, newList);
-        } else {
-            config.put(prefix + PROPERTY_REPOSITORIES, newList);
-        }
+        updatePidRepositories(prefix, config, defaultRepository, newRepos, settingsRepos.length > 0);
 
         Configuration cmConfig = cm.getConfiguration(PID);
         cmConfig.update(config);

http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryChangeCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryChangeCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryChangeCommand.java
new file mode 100644
index 0000000..e85876a
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryChangeCommand.java
@@ -0,0 +1,197 @@
+/*
+ * 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.maven.command;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+import org.apache.karaf.shell.api.action.Argument;
+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.maven.settings.Profile;
+import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.RepositoryPolicy;
+import org.osgi.service.cm.Configuration;
+
+@Command(scope = "maven", name = "repository-change", description = "Changes configuration of Maven repository")
+@Service
+public class RepositoryChangeCommand extends RepositoryEditCommandSupport {
+
+    @Option(name = "-s", aliases = { "--snapshots" }, description = "Enable SNAPSHOT handling in the repository", required = false, multiValued = false)
+    boolean snapshots = false;
+
+    @Option(name = "-nr", aliases = { "--no-releases" }, description = "Disable release handling in this repository", required = false, multiValued = false)
+    boolean noReleases = false;
+
+    @Option(name = "-up", aliases = { "--update-policy" }, description = "Update policy for repository (never, daily (default), interval:N, always)", required = false, multiValued = false)
+    String updatePolicy;
+
+    @Option(name = "-cp", aliases = { "--checksum-policy" }, description = "Checksum policy for repository (ignore, warn (default), fail)", required = false, multiValued = false)
+    String checksumPolicy;
+
+    @Option(name = "-u", aliases = { "--username" }, description = "Username for remote repository", required = false, multiValued = false)
+    String username;
+
+    @Option(name = "-p", aliases = { "--password" }, description = "Password for remote repository (may be encrypted, see \"maven:password -ep\")", required = false, multiValued = false)
+    String password;
+
+    @Argument(description = "Repository URI. It may be file:// based, http(s):// based, may use other known protocol or even property placeholders (like ${karaf.base})", required = false)
+    String uri;
+
+    @Override
+    protected void edit(String prefix, Dictionary<String, Object> config,
+                        MavenRepositoryURL[] allRepos, MavenRepositoryURL[] pidRepos, MavenRepositoryURL[] settingsRepos) throws Exception {
+
+        Optional<MavenRepositoryURL> first = Arrays.stream(allRepos)
+                .filter((repo) -> id.equals(repo.getId())).findFirst();
+        if (!first.isPresent()) {
+            System.err.printf("Can't find %s repository with ID \"%s\"\n", (defaultRepository ? "default" : "remote"), id);
+            return;
+        }
+
+        MavenRepositoryURL changedRepository = first.get();
+
+        changedRepository.setSnapshotsEnabled(snapshots);
+        changedRepository.setReleasesEnabled(!noReleases);
+
+        if (updatePolicy != null) {
+            SourceAnd<String> up = updatePolicy(updatePolicy);
+            if (!up.valid) {
+                System.err.println("Unknown value of update policy: \"" + updatePolicy + "\"");
+                return;
+            }
+            changedRepository.setReleasesUpdatePolicy(up.val());
+            changedRepository.setSnapshotsUpdatePolicy(up.val());
+        }
+
+        if (checksumPolicy != null) {
+            SourceAnd<String> cp = checksumPolicy(checksumPolicy);
+            if (!cp.valid) {
+                System.err.println("Unknown value of checksum policy: \"" + checksumPolicy + "\"");
+                return;
+            }
+            changedRepository.setReleasesChecksumPolicy(cp.val());
+            changedRepository.setSnapshotsChecksumPolicy(cp.val());
+        }
+
+        if (uri != null) {
+            SourceAnd<String> urlResolved = validateRepositoryURL(uri, defaultRepository);
+            if (!urlResolved.valid) {
+                return;
+            }
+            changedRepository.setURL(new URL(urlResolved.val()));
+        }
+
+        boolean hasUsername = username != null && !"".equals(username.trim());
+        boolean hasPassword = password != null && !"".equals(password.trim());
+        boolean hasCredentials = hasUsername && hasPassword;
+
+        if ((hasUsername && !hasPassword) || (!hasUsername && hasPassword)) {
+            System.err.println("Please specify both username and password");
+            return;
+        }
+
+        if (defaultRepository && hasCredentials) {
+            System.out.println("User credentials won't be used for default repository");
+            // no return
+        }
+
+        boolean credentialsUpdated = false;
+        // credentials for remote repository can be stored only in settings.xml
+        if (!defaultRepository && hasCredentials) {
+            if (!updateCredentials(force, id, username, password, prefix, config)) {
+                return;
+            }
+            credentialsUpdated = true;
+        }
+
+        if (!defaultRepository && changedRepository.getFrom() == MavenRepositoryURL.FROM.SETTINGS) {
+            // find <repository> in any active profile to change it
+            for (Profile profile : mavenSettings.getProfiles()) {
+                Optional<Repository> repository = profile.getRepositories().stream().filter((r) -> id.equals(r.getId())).findFirst();
+                if (repository.isPresent()) {
+                    // I can't imagine it's not...
+                    Repository r = repository.get();
+                    r.setUrl(changedRepository.getURL().toString());
+                    if (!changedRepository.isSnapshotsEnabled()) {
+                        r.setSnapshots(new RepositoryPolicy());
+                        r.getSnapshots().setEnabled(false);
+                    } else {
+                        RepositoryPolicy rp = r.getSnapshots() == null ? new RepositoryPolicy() : r.getSnapshots();
+                        rp.setEnabled(true);
+                        if (checksumPolicy != null) {
+                            rp.setChecksumPolicy(changedRepository.getSnapshotsChecksumPolicy());
+                        } else if (rp.getChecksumPolicy() == null) {
+                            rp.setChecksumPolicy("warn");
+                        }
+                        if (updatePolicy != null) {
+                            rp.setUpdatePolicy(changedRepository.getSnapshotsUpdatePolicy());
+                        } else if (rp.getUpdatePolicy() == null) {
+                            rp.setUpdatePolicy("daily");
+                        }
+                        r.setSnapshots(rp);
+                    }
+                    if (!changedRepository.isReleasesEnabled()) {
+                        r.setReleases(new RepositoryPolicy());
+                        r.getReleases().setEnabled(false);
+                    } else {
+                        RepositoryPolicy rp = r.getReleases() == null ? new RepositoryPolicy() : r.getReleases();
+                        rp.setEnabled(true);
+                        if (checksumPolicy != null) {
+                            rp.setChecksumPolicy(changedRepository.getReleasesChecksumPolicy());
+                        } else if (rp.getChecksumPolicy() == null) {
+                            rp.setChecksumPolicy("warn");
+                        }
+                        if (updatePolicy != null) {
+                            rp.setUpdatePolicy(changedRepository.getReleasesUpdatePolicy());
+                        } else if (rp.getUpdatePolicy() == null) {
+                            rp.setUpdatePolicy("daily");
+                        }
+                        r.setReleases(rp);
+                    }
+                    updateSettings(prefix, config);
+                    break;
+                }
+            }
+        } else if (changedRepository.getFrom() == MavenRepositoryURL.FROM.PID) {
+            List<MavenRepositoryURL> newRepos = new LinkedList<>();
+            for (MavenRepositoryURL repo : pidRepos) {
+                MavenRepositoryURL _r = repo;
+                if (id.equals(repo.getId())) {
+                    _r = changedRepository;
+                }
+                newRepos.add(_r);
+            }
+            updatePidRepositories(prefix, config, defaultRepository, newRepos, settingsRepos.length > 0);
+            if (credentialsUpdated) {
+                updateSettings(prefix, config);
+            }
+        }
+
+        Configuration cmConfig = cm.getConfiguration(PID);
+        cmConfig.update(config);
+
+        success = true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
index 9f403c1..32dcc8f 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
@@ -16,10 +16,21 @@
  */
 package org.apache.karaf.maven.command;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
 import java.util.Dictionary;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
+import org.apache.felix.utils.properties.InterpolationHelper;
 import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Option;
+import org.apache.maven.settings.Server;
 
 public abstract class RepositoryEditCommandSupport extends MavenSecuritySupport {
 
@@ -29,21 +40,150 @@ public abstract class RepositoryEditCommandSupport extends MavenSecuritySupport
     @Option(name = "-d", aliases = { "--default" }, description = "Edit default repository instead of remote one", required = false, multiValued = false)
     boolean defaultRepository = false;
 
+    @Option(name = "-f", aliases = { "--force" }, description = "Do not ask for confirmation", required = false, multiValued = false)
+    boolean force = false;
+
     boolean success = false;
 
     @Override
     public final void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
-        edit(prefix, config);
+        if (id == null || "".equals(id.trim())) {
+            System.err.println("Please specify ID of repository");
+            return;
+        }
+
+        MavenRepositoryURL[] repositories = repositories(config, !defaultRepository);
+
+        MavenRepositoryURL[] repositoriesFromPidProperty = Arrays.stream(repositories)
+                .filter((repo) -> repo.getFrom() == MavenRepositoryURL.FROM.PID)
+                .toArray(MavenRepositoryURL[]::new);
+
+        MavenRepositoryURL[] repositoriesFromSettings = Arrays.stream(repositories)
+                .filter((repo) -> repo.getFrom() == MavenRepositoryURL.FROM.SETTINGS)
+                .toArray(MavenRepositoryURL[]::new);
+
+        edit(prefix, config, repositories, repositoriesFromPidProperty, repositoriesFromSettings);
 
         if (success) {
             if (showPasswords) {
-                session.execute("maven:repository-list -x");
+                session.execute("maven:repository-list -v -x");
             } else {
-                session.execute("maven:repository-list");
+                session.execute("maven:repository-list -v");
             }
         }
     }
 
-    protected abstract void edit(String prefix, Dictionary<String, Object> config) throws Exception;
+    /**
+     * Peform action on repository (add, remove, change)
+     * @param prefix property prefix for <code>org.ops4j.pax.url.mvn</code> PID
+     * @param config
+     * @param allRepos
+     * @param pidRepos
+     * @param settingsRepos
+     * @throws Exception
+     */
+    protected abstract void edit(String prefix, Dictionary<String, Object> config,
+                                 MavenRepositoryURL[] allRepos, MavenRepositoryURL[] pidRepos, MavenRepositoryURL[] settingsRepos) throws Exception;
+
+    /**
+     * Stores new repository list in relevant <code>org.ops4j.pax.url.mvn</code> PID property
+     * @param prefix
+     * @param config
+     * @param defaultRepository default (<code>true</code>) or remote repositories?
+     * @param newRepos new list of repositories
+     * @param hasSettingsRepositories whether we have repositories stored in <code>settings.xml</code> as well
+     */
+    protected void updatePidRepositories(String prefix, Dictionary<String, Object> config, boolean defaultRepository,
+                                         List<MavenRepositoryURL> newRepos, boolean hasSettingsRepositories) {
+        String newList = newRepos.stream().map(MavenRepositoryURL::asRepositorySpec)
+                .collect(Collectors.joining(","));
+
+        if (defaultRepository) {
+            config.put(prefix + PROPERTY_DEFAULT_REPOSITORIES, newList);
+        } else {
+            if (hasSettingsRepositories) {
+                newList = "+" + newList;
+            }
+            config.put(prefix + PROPERTY_REPOSITORIES, newList);
+        }
+    }
+
+    /**
+     * Stores credential information in settings, without persisting them
+     * @param force
+     * @param id
+     * @param username
+     * @param password
+     * @param prefix
+     * @param config
+     */
+    protected boolean updateCredentials(boolean force, String id, String username, String password,
+                                      String prefix, Dictionary<String, Object> config) throws IOException {
+        if (!force && !confirm("Maven settings will be updated and org.ops4j.pax.url.mvn.settings property will change. Continue? (y/N) ")) {
+            return false;
+        }
+
+        Optional<Server> existingServer = mavenSettings.getServers().stream()
+                .filter((s) -> id.equals(s.getId())).findAny();
+        Server server = null;
+        if (existingServer.isPresent()) {
+            server = existingServer.get();
+        } else {
+            server = new Server();
+            server.setId(id);
+            mavenSettings.getServers().add(server);
+        }
+        server.setUsername(username);
+        server.setPassword(password);
+
+        return true;
+    }
+
+    /**
+     * Takes passed-in repository URI and performs basic validation
+     * @param uri
+     * @param defaultRepository
+     * @return
+     */
+    protected SourceAnd<String> validateRepositoryURL(String uri, boolean defaultRepository) throws URISyntaxException, MalformedURLException {
+        SourceAnd<String> result = new SourceAnd<String>();
+        result.valid = false;
+
+        if (uri == null || "".equals(uri.trim())) {
+            System.err.println("Please specify repository location");
+            return result;
+        }
+        String urlResolved = InterpolationHelper.substVars(uri, "uri", null, null, context);
+        URL url = null;
+        try {
+            url = new URL(urlResolved);
+            urlResolved = url.toString();
+
+            if ("file".equals(url.getProtocol()) && new File(url.toURI()).isDirectory()) {
+                System.err.println("Location \"" + urlResolved + "\" is not accessible");
+                return result;
+            }
+        } catch (MalformedURLException e) {
+            // a directory?
+            File location = new File(urlResolved);
+            if (!location.exists() || !location.isDirectory()) {
+                System.err.println("Location \"" + urlResolved + "\" is not accessible");
+                return result;
+            } else {
+                url = location.toURI().toURL();
+                urlResolved = url.toString();
+            }
+        }
+
+        if (defaultRepository && !"file".equals(url.getProtocol())) {
+            System.err.println("Default repositories should be locally accessible (use file:// protocol or normal directory path)");
+            return result;
+        }
+
+        result.valid = true;
+        result.value = urlResolved;
+
+        return result;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
index eaf62e5..28c0716 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryRemoveCommand.java
@@ -16,18 +16,75 @@
  */
 package org.apache.karaf.maven.command;
 
+import java.util.Arrays;
 import java.util.Dictionary;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
+import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.maven.settings.Profile;
+import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.Server;
+import org.osgi.service.cm.Configuration;
 
 @Command(scope = "maven", name = "repository-remove", description = "Removes Maven repository")
 @Service
 public class RepositoryRemoveCommand extends RepositoryEditCommandSupport {
 
     @Override
-    protected void edit(String prefix, Dictionary<String, Object> config) throws Exception {
+    protected void edit(String prefix, Dictionary<String, Object> config,
+                        MavenRepositoryURL[] allRepos, MavenRepositoryURL[] pidRepos, MavenRepositoryURL[] settingsRepos) throws Exception {
 
+        Optional<MavenRepositoryURL> first = Arrays.stream(allRepos)
+                .filter((repo) -> id.equals(repo.getId())).findAny();
+        if (!first.isPresent()) {
+            System.err.printf("Can't find %s repository with ID \"%s\"\n", (defaultRepository ? "default" : "remote"), id);
+            return;
+        }
+
+        if (force || confirm(String.format("Are you sure to remove repository with ID \"%s\" for URL %s? (y/N) ", id, first.get().getURL()))) {
+            if (!defaultRepository && first.get().getFrom() == MavenRepositoryURL.FROM.SETTINGS) {
+                // remove <server> (credentials) if available
+                List<Server> newServers = mavenSettings.getServers().stream()
+                        .filter((s) -> !id.equals(s.getId())).collect(Collectors.toList());
+                mavenSettings.setServers(newServers);
+
+                // find <repository> in any active profile and remove it
+                for (Profile profile : mavenSettings.getProfiles()) {
+                    if (profile.getRepositories().stream().anyMatch((r) -> id.equals(r.getId()))) {
+                        List<Repository> newRepos = profile.getRepositories().stream()
+                                .filter((r) -> !id.equals(r.getId())).collect(Collectors.toList());
+                        profile.setRepositories(newRepos);
+                        System.out.printf("Repository with ID \"%s\" was removed from profile \"%s\"\n", id, profile.getId());
+                        break;
+                    }
+                }
+
+                updateSettings(prefix, config);
+            } else if (first.get().getFrom() == MavenRepositoryURL.FROM.PID) {
+                List<MavenRepositoryURL> newRepos = Arrays.stream(pidRepos).filter((r) -> !id.equals(r.getId())).collect(Collectors.toList());
+
+                updatePidRepositories(prefix, config, defaultRepository, newRepos, settingsRepos.length > 0);
+
+                // if there are credentials for this repository, we have to remove them from settings.xml
+                if (mavenSettings.getServers().stream().anyMatch((s) -> id.equals(s.getId()))) {
+                    // remove <server> (credentials) if available
+                    List<Server> newServers = mavenSettings.getServers().stream()
+                            .filter((s) -> !id.equals(s.getId())).collect(Collectors.toList());
+                    mavenSettings.setServers(newServers);
+
+                    updateSettings(prefix, config);
+                }
+            }
+
+            Configuration cmConfig = cm.getConfiguration(PID);
+            cmConfig.update(config);
+
+            success = true;
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/df8f2920/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
index 1c422c8..7bc5a73 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
@@ -61,7 +61,7 @@ public class MavenRepositoryURL
     /**
      * Repository URL.
      */
-    private final URL m_repositoryURL;
+    private URL m_repositoryURL;
     /**
      * Repository file (only if URL is a file URL).
      */
@@ -69,27 +69,27 @@ public class MavenRepositoryURL
     /**
      * True if the repository contains snapshots.
      */
-    private final boolean m_snapshotsEnabled;
+    private boolean m_snapshotsEnabled;
     /**
      * True if the repository contains releases.
      */
-    private final boolean m_releasesEnabled;
+    private boolean m_releasesEnabled;
     /**
      * Repository update policy
      */
-    private final String m_releasesUpdatePolicy;
+    private String m_releasesUpdatePolicy;
     /**
      * Repository update policy
      */
-    private final String m_snapshotsUpdatePolicy;
+    private String m_snapshotsUpdatePolicy;
     /**
      * Repository checksum policy
      */
-    private final String m_releasesChecksumPolicy;
+    private String m_releasesChecksumPolicy;
     /**
      * Repository checksum policy
      */
-    private final String m_snapshotsChecksumPolicy;
+    private String m_snapshotsChecksumPolicy;
 
     private final boolean m_multi;
     /**
@@ -288,6 +288,10 @@ public class MavenRepositoryURL
         return m_repositoryURL;
     }
 
+    public void setURL(URL url) {
+        this.m_repositoryURL = url;
+    }
+
     /**
      * Getter.
      *
@@ -308,6 +312,11 @@ public class MavenRepositoryURL
         return m_releasesEnabled;
     }
 
+    public void setReleasesEnabled(boolean enabled)
+    {
+        m_releasesEnabled = enabled;
+    }
+
     /**
      * Getter.
      *
@@ -318,6 +327,11 @@ public class MavenRepositoryURL
         return m_snapshotsEnabled;
     }
 
+    public void setSnapshotsEnabled(boolean enabled)
+    {
+        m_snapshotsEnabled = enabled;
+    }
+
     public String getReleasesUpdatePolicy() {
         return m_releasesUpdatePolicy;
     }
@@ -334,6 +348,22 @@ public class MavenRepositoryURL
         return m_snapshotsChecksumPolicy;
     }
 
+    public void setReleasesUpdatePolicy(String policy) {
+        m_releasesUpdatePolicy = policy;
+    }
+
+    public void setSnapshotsUpdatePolicy(String policy) {
+        m_snapshotsUpdatePolicy = policy;
+    }
+
+    public void setReleasesChecksumPolicy(String policy) {
+        m_releasesChecksumPolicy = policy;
+    }
+
+    public void setSnapshotsChecksumPolicy(String policy) {
+        m_snapshotsChecksumPolicy = policy;
+    }
+
     public FROM getFrom() {
         return m_from;
     }
@@ -402,7 +432,7 @@ public class MavenRepositoryURL
             }
         }
         if (m_snapshotsEnabled && m_releasesEnabled) {
-            // compact snapshots & release update & checksum policies?
+            // compact snapshots & release update & checksum policies
             if (m_releasesUpdatePolicy != null && Objects.equals(m_releasesUpdatePolicy, m_snapshotsUpdatePolicy)) {
                 sb.append(ServiceConstants.SEPARATOR_OPTIONS + ServiceConstants.OPTION_UPDATE + "=" + m_releasesUpdatePolicy);
             }


[06/12] karaf git commit: [KARAF-5008] Additional maven:summary details and settings-security.xml handling

Posted by gg...@apache.org.
[KARAF-5008] Additional maven:summary details and settings-security.xml handling


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

Branch: refs/heads/master-maven-commands
Commit: 84505fb45d3a031697fc31553c9dbdc47ac1a3c7
Parents: f3fe90b
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Tue Mar 14 13:44:08 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 .../command/MavenConfigurationSupport.java      | 167 +++++++++++++------
 .../karaf/maven/command/SummaryCommand.java     |  98 +++++++----
 2 files changed, 189 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/84505fb4/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index 2a77c9d..c772913 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -36,11 +36,14 @@ import org.apache.maven.settings.building.SettingsBuildingException;
 import org.apache.maven.settings.building.SettingsBuildingRequest;
 import org.apache.maven.settings.building.SettingsBuildingResult;
 import org.apache.maven.settings.building.SettingsProblem;
+import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
+import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
 
 /**
  * <p>Base class for <code>maven:</code> commands.</p>
@@ -58,13 +61,21 @@ public abstract class MavenConfigurationSupport implements Action {
     protected static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
     protected static final String PROPERTY_REPOSITORIES = "repositories";
     protected static final String PROPERTY_SETTINGS_FILE = "settings";
+    protected static final String PROPERTY_SECURITY_FILE = "security";
     protected static final String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
     protected static final String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
     protected static final String PROPERTY_UPDATE_RELEASES = "updateReleases";
+    protected static final String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
+    protected static final String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
+    protected static final String PROPERTY_OFFLINE = "offline";
+    protected static final String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
 
     protected SourceAnd<File> localRepository;
     protected SourceAnd<File> settings;
-    protected Settings effectiveSettings;
+    protected Settings mavenSettings;
+    protected SourceAnd<File> securitySettings;
+    protected SettingsSecurity mavenSecuritySettings;
+
     protected Map<String, String> serverPasswords = new HashMap<>();
     protected Map<String, String> proxyPasswords = new HashMap<>();
 
@@ -73,15 +84,25 @@ public abstract class MavenConfigurationSupport implements Action {
     @Reference
     protected ConfigurationAdmin cm;
 
+    @Reference
+    protected BundleContext context;
+
     @Override
     final public Object execute() throws Exception {
         Configuration c = cm.getConfiguration(PID);
 
         if (c != null && c.getProperties() != null) {
+            securitySettings = securitySettings((String) c.getProperties().get(PID + "." + PROPERTY_SECURITY_FILE));
+            if (securitySettings != null && securitySettings.value != null) {
+                mavenSecuritySettings = readSecuritySettings(securitySettings.value);
+            }
+
             settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
-            if (settings.value != null) {
-                reReadSettings(settings.value);
+            if (settings != null && settings.value != null) {
+                mavenSettings = readSettings(settings.value);
+                decryptSettings(mavenSettings);
             }
+
             localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
 
             doAction(PID + ".", c.getProperties());
@@ -128,62 +149,103 @@ public abstract class MavenConfigurationSupport implements Action {
 
         // 1. PID + ".settings"
         if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SETTINGS_FILE);
             try {
                 locationUrl = new URL(cmProperty);
-                result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SETTINGS_FILE);
                 probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
                         locationUrl, PID, PROPERTY_SETTINGS_FILE);
             } catch (MalformedURLException e) {
                 File file = new File(cmProperty);
                 if (file.isFile()) {
                     result.value = file;
-                    result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SETTINGS_FILE);
                     return result;
                 }
             }
         }
 
-        // 2. System.getProperty("user.home") + "/.m2/settings.xml"
         if (locationUrl == null) {
+            // 2. System.getProperty("user.home") + "/.m2/settings.xml"
             File file = new File(System.getProperty("user.home") + "/.m2/settings.xml");
             if (file.isFile()) {
                 result.value = file;
                 result.source = "Implicit ${user.home}/.m2/settings.xml";
                 return result;
             }
-        }
 
-        // 3. System.getProperty("maven.home") + "/conf/settings.xml"
-        if (locationUrl == null) {
-            File file = new File(System.getProperty("maven.home") + "/conf/settings.xml");
+            // 3. System.getProperty("maven.home") + "/conf/settings.xml"
+            file = new File(System.getProperty("maven.home") + "/conf/settings.xml");
             if (file.isFile()) {
                 result.value = file;
                 result.source = "Implicit ${maven.home}/conf/settings.xml";
                 return result;
             }
-        }
 
-        // 4. System.getenv("M2_HOME") + "/conf/settings.xml"
-        if (locationUrl == null) {
-            File file = new File(System.getenv("M2_HOME") + "/conf/settings.xml");
+            // 4. System.getenv("M2_HOME") + "/conf/settings.xml"
+            file = new File(System.getenv("M2_HOME") + "/conf/settings.xml");
             if (file.isFile()) {
                 result.value = file;
                 result.source = "Implicit $M2_HOME/conf/settings.xml";
                 return result;
             }
+        } else {
+            File file = new File(locationUrl.getPath());
+            result.value = file;
+            if (!file.isFile()) {
+                result.source = probableErrorMessage;
+            }
+            return result;
         }
 
-        if (locationUrl != null) {
-            File file = new File(locationUrl.getPath());
+        // 5. new org.apache.maven.settings.Settings()
+        result.value = null;
+        result.source = "No implicit settings.xml location is available";
+        return result;
+    }
+
+    /**
+     * Gets effective location of <code>settings-security.xml</code> file - according to pax-url-aether rules
+     * @param cmProperty property obtained from Config Admin
+     * @return
+     */
+    protected SourceAnd<File> securitySettings(String cmProperty) {
+        SourceAnd<File> result = new SourceAnd<>();
+        URL locationUrl = null;
+        String probableErrorMessage = null;
+
+        // 1. PID + ".security"
+        if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_SECURITY_FILE);
+            try {
+                locationUrl = new URL(cmProperty);
+                probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
+                        locationUrl, PID, PROPERTY_SECURITY_FILE);
+            } catch (MalformedURLException e) {
+                File file = new File(cmProperty);
+                if (file.isFile()) {
+                    result.value = file;
+                    return result;
+                }
+            }
+        }
+
+        // 2. System.getProperty("user.home") + "/.m2/settings-security.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("user.home") + "/.m2/settings-security.xml");
             if (file.isFile()) {
                 result.value = file;
+                result.source = "Implicit ${user.home}/.m2/settings-security.xml";
                 return result;
-            } else {
-                throw new IllegalArgumentException(probableErrorMessage);
+            }
+        } else {
+            File file = new File(locationUrl.getPath());
+            result.value = file;
+            if (!file.isFile()) {
+                result.source = probableErrorMessage;
             }
         }
 
-        // 5. new org.apache.maven.settings.Settings()
+        result.value = null;
+        result.source = "No implicit settings-security.xml location is available";
         return result;
     }
 
@@ -199,33 +261,31 @@ public abstract class MavenConfigurationSupport implements Action {
 
         // 1. PID + ".localRepository"
         if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
             try {
                 locationUrl = new URL(cmProperty);
-                result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
                 probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
                         locationUrl, PID, PROPERTY_LOCAL_REPOSITORY);
             } catch (MalformedURLException e) {
                 File file = new File(cmProperty);
                 if (file.isDirectory()) {
                     result.value = file;
-                    result.source = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
                     return result;
                 }
             }
         }
 
         // 2. from settings.xml
-        if (locationUrl == null && effectiveSettings != null && effectiveSettings.getLocalRepository() != null) {
+        if (locationUrl == null && mavenSettings != null && mavenSettings.getLocalRepository() != null) {
+            result.source = String.format("Explicit <localRepository> in %s", settings.value);
             try {
-                locationUrl = new URL(effectiveSettings.getLocalRepository());
-                result.source = String.format("Explicit <localRepository> in %s", settings.value);
+                locationUrl = new URL(mavenSettings.getLocalRepository());
                 probableErrorMessage = String.format("%s configured in %s is not accessible",
-                        effectiveSettings.getLocalRepository(), settings.value);
+                        mavenSettings.getLocalRepository(), settings.value);
             } catch (MalformedURLException e) {
-                File file = new File(effectiveSettings.getLocalRepository());
+                File file = new File(mavenSettings.getLocalRepository());
                 if (file.isDirectory()) {
                     result.value = file;
-                    result.source = String.format("Explicit <localRepository> in %s", settings.value);
                     return result;
                 }
             }
@@ -234,36 +294,30 @@ public abstract class MavenConfigurationSupport implements Action {
         // 3. System.getProperty("user.home") + "/.m2/repository";
         if (locationUrl == null) {
             File file = new File(System.getProperty("user.home") + "/.m2/repository");
+            result.value = file; // whether it exists or not
             if (file.isDirectory()) {
-                result.value = file;
                 result.source = "Implicit ${user.home}/.m2/repository";
-                return result;
-            }
-        }
-
-        if (locationUrl != null) {
-            File file = new File(locationUrl.getPath());
-            if (file.isDirectory()) {
-                result.value = file;
-                return result;
             } else {
-                throw new IllegalArgumentException(probableErrorMessage);
+                result.source = "Implicit ${user.home}/.m2/repository (not accessible)";
             }
+            return result;
         }
 
-        // 5. new org.apache.maven.settings.Settings()
-        return null;
+        File file = new File(locationUrl.getPath());
+        result.value = file;
+        if (!file.isDirectory()) {
+            result.source = probableErrorMessage;
+        }
+        return result;
     }
 
     /**
-     * Re-reads on demand <code>settings.xml</code> file - with password decryption
+     * Reads on demand <code>settings.xml</code> file - with password decryption
      * @param settingsFile
      */
-    protected synchronized void reReadSettings(File settingsFile) throws SettingsBuildingException {
-        effectiveSettings = null;
-
+    protected synchronized Settings readSettings(File settingsFile) throws SettingsBuildingException {
         if (!settingsFile.isFile() || !settingsFile.canRead()) {
-            throw new IllegalArgumentException(settingsFile + " is not accessible");
+            return null;
         }
 
         try {
@@ -277,11 +331,30 @@ public abstract class MavenConfigurationSupport implements Action {
                 for (SettingsProblem problem : result.getProblems()) {
                     System.err.println(problem);
                 }
+                return null;
             } else {
-                effectiveSettings = result.getEffectiveSettings();
-                decryptSettings(effectiveSettings);
+                return result.getEffectiveSettings();
             }
         } catch (Throwable e) {
+            System.err.println(e.getMessage());
+            LOG.error(e.getMessage(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * Re-reads on demand <code>settings-security.xml</code> file
+     * @param securitySettingsFile
+     */
+    protected synchronized SettingsSecurity readSecuritySettings(File securitySettingsFile) throws Exception {
+        if (!securitySettingsFile.isFile() || !securitySettingsFile.canRead()) {
+            return null;
+        }
+
+        try {
+            return SecUtil.read(securitySettingsFile.getAbsolutePath(), true);
+        } catch (Throwable e) {
+            System.err.println(e.getMessage());
             LOG.error(e.getMessage(), e);
             throw e;
         }

http://git-wip-us.apache.org/repos/asf/karaf/blob/84505fb4/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index 56d6118..f68c555 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -29,12 +29,12 @@ import org.apache.karaf.shell.support.table.ShellTable;
 @Service
 public class SummaryCommand extends MavenConfigurationSupport {
 
-    @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
-    boolean description;
-
     @Option(name = "-s", aliases = { "--source" }, description = "Adds information about where the value is configured", required = false, multiValued = false)
     boolean source;
 
+    @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
+    boolean description;
+
     /*
      * All options from org.ops4j.pax.url.mvn.ServiceConstants (2.5.2):
      *
@@ -42,18 +42,18 @@ public class SummaryCommand extends MavenConfigurationSupport {
      * String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
      * String PROPERTY_REPOSITORIES = "repositories";
      * +String PROPERTY_SETTINGS_FILE = "settings";
-     * String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
+     * +String PROPERTY_SECURITY = "security";
+     * +String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
      * +String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
      * +String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
      * +String PROPERTY_UPDATE_RELEASES = "updateReleases";
-     * String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote";
-     * String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
-     * String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
-     * String PROPERTY_PROXY_SUPPORT = "proxySupport";
-     * String PROPERTY_SECURITY = "security";
+     * -String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote"; // silly to use
+     * +String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
+     * +String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
+     * -String PROPERTY_PROXY_SUPPORT = "proxySupport"; // not used in "new" MavenResolver
      * String PROPERTY_TIMEOUT = "timeout";
-     * String PROPERTY_OFFLINE = "offline";
-     * String PROPERTY_PROXIES = "proxies";
+     * +String PROPERTY_OFFLINE = "offline";
+     * -String PROPERTY_PROXIES = "proxies"; // not used in "new" MavenResolver
      * String PROPERTY_SOCKET_SO_TIMEOUT = "socket.readTimeout";
      * String PROPERTY_SOCKET_SO_KEEPALIVE = "socket.keepAlive";
      * String PROPERTY_SOCKET_SO_LINGER = "socket.linger";
@@ -88,12 +88,13 @@ public class SummaryCommand extends MavenConfigurationSupport {
         }
 
         addRow(table, "Local repository", localRepository,
-                "Maven repository to store artifacts resolved in *remote repositories*",
-                source, description);
+                "Maven repository to store artifacts resolved in *remote repositories*");
 
         addRow(table, "Settings file", settings,
-                "Settings file that may contain configuration of additional repositories, http proxies and mirrors",
-                source, description);
+                "Settings file that may contain configuration of additional repositories, http proxies and mirrors");
+
+        addRow(table, "Security settings file", securitySettings,
+                "Settings file that contain (or relocates to) master Maven password");
 
         // for default update/checksum policies specified at repository URI level, see
         // org.ops4j.pax.url.mvn.internal.AetherBasedResolver.addRepo()
@@ -101,26 +102,67 @@ public class SummaryCommand extends MavenConfigurationSupport {
         // see org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer#isUpdatedRequired()
         SourceAnd<String> updatePolicy = updatePolicy((String) config.get(prefix + PROPERTY_GLOBAL_UPDATE_POLICY));
         addRow(table, "Global update policy", updatePolicy,
-                "Overrides update policy specified at repository level (if specified)",
-                source, description);
+                "Overrides update policy specified at repository level (if specified)");
 
         // see org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider#newChecksumPolicy()
         SourceAnd<String> checksumPolicy = checksumPolicy((String) config.get(prefix + PROPERTY_GLOBAL_CHECKSUM_POLICY));
         addRow(table, "Global checksum policy", checksumPolicy,
-                "Checksum policy for all repositories",
-                source, description);
+                "Checksum policy for all repositories");
 
         String updateReleasesProperty = (String) config.get(prefix + PROPERTY_UPDATE_RELEASES);
         boolean updateReleases = false;
-        String sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, PID + "." + PROPERTY_UPDATE_RELEASES);
+        String sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_UPDATE_RELEASES);
         if (updateReleasesProperty == null) {
             sourceInfo = "Default \"false\"";
         } else {
             updateReleases = "true".equals(updateReleasesProperty);
         }
         addRow(table, "Update releases", new SourceAnd<Boolean>(sourceInfo, updateReleases),
-                "Whether to download non-SNAPSHOT artifacts according to update policy",
-                source, description);
+                "Whether to download non-SNAPSHOT artifacts according to update policy");
+
+        // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.isValid()
+        // ANY non null value (even "false"!) means that we require configadmin
+        String requireConfigAdminProperty = context.getProperty(prefix + REQUIRE_CONFIG_ADMIN_CONFIG);
+        boolean requireConfigAdmin = requireConfigAdminProperty != null;
+        sourceInfo = "Default \"false\"";
+        if (requireConfigAdmin) {
+            sourceInfo = "BundleContext property (" + prefix + REQUIRE_CONFIG_ADMIN_CONFIG + ")";
+        }
+        addRow(table, "Require Config Admin", new SourceAnd<Boolean>(sourceInfo, requireConfigAdmin),
+                "Wheter MavenResolver service is registered ONLY with proper " + PID + " PID configuration");
+
+        // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.buildSettings()
+        String useFallbackRepositoriesProperty = (String) config.get(prefix + PROPERTY_USE_FALLBACK_REPOSITORIES);
+        boolean useFallbackRepositories = Boolean.parseBoolean(useFallbackRepositoriesProperty);
+        sourceInfo = "Default \"false\"";
+        if (useFallbackRepositoriesProperty != null) {
+            sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_USE_FALLBACK_REPOSITORIES);
+        }
+        addRow(table, "Use fallback repository", new SourceAnd<Boolean>(sourceInfo, useFallbackRepositories),
+                "Whether Maven Central is used as implicit, additional remote repository");
+
+        // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.enableProxy()
+        // "proxySupport" and "proxies" are not used in "new" MavenResolver
+
+        // see org.eclipse.aether.internal.impl.DefaultOfflineController#checkOffline()
+        String offlineProperty = (String) config.get(prefix + PROPERTY_OFFLINE);
+        boolean offline = Boolean.parseBoolean(offlineProperty);
+        sourceInfo = "Default \"false\"";
+        if (offlineProperty != null) {
+            sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_OFFLINE);
+        }
+        addRow(table, "Offline mode", new SourceAnd<Boolean>(sourceInfo, offline),
+                "Disables access to external remote repositories (file:// based ones are still used)");
+
+        // see org.ops4j.pax.url.mvn.internal.HttpClients.createConnManager()
+        String certificateCheckProperty = (String) config.get(prefix + PROPERTY_CERTIFICATE_CHECK);
+        boolean certificateCheck = Boolean.parseBoolean(certificateCheckProperty);
+        sourceInfo = "Default \"false\"";
+        if (certificateCheckProperty != null) {
+            sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_CERTIFICATE_CHECK);
+        }
+        addRow(table, "SSL/TLS certificate check", new SourceAnd<Boolean>(sourceInfo, certificateCheck),
+                "Turns on server certificate validation for HTTPS remote repositories");
 
         table.print(System.out);
     }
@@ -130,18 +172,16 @@ public class SummaryCommand extends MavenConfigurationSupport {
      * @param table
      * @param label
      * @param value
-     * @param description
-     * @param addSource
-     * @param addDescription
+     * @param descriptionText
      */
-    private <T> void addRow(ShellTable table, String label, SourceAnd<T> value, String description, boolean addSource, boolean addDescription) {
+    private <T> void addRow(ShellTable table, String label, SourceAnd<T> value, String descriptionText) {
         Row row = table.addRow();
         row.addContent(label, value.val());
-        if (addSource) {
+        if (source) {
             row.addContent(value.source);
         }
-        if (addDescription) {
-            row.addContent(description);
+        if (description) {
+            row.addContent(descriptionText);
         }
     }
 


[05/12] karaf git commit: [KARAF-5008] Clean up org.apache.maven.wagon.* dependencies (align to 2.10 for now)

Posted by gg...@apache.org.
[KARAF-5008] Clean up org.apache.maven.wagon.* dependencies (align to 2.10 for now)


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

Branch: refs/heads/master-maven-commands
Commit: 5c2bb4b6f076cc82169b2c94d7f75b7e6da6cf22
Parents: 2f7c5d7
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Fri Mar 10 14:05:18 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 pom.xml                                     | 16 ++++++++++++++++
 tooling/karaf-maven-plugin/pom.xml          |  1 -
 tooling/karaf-services-maven-plugin/pom.xml |  1 -
 3 files changed, 16 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/5c2bb4b6/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a507ab6..a7367d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -253,6 +253,7 @@
         <jsw.version>3.2.3</jsw.version>
         <log4j.version>1.2.17</log4j.version>
         <maven.version>3.0.3</maven.version>
+        <maven.wagon.version>2.10</maven.wagon.version>
         <org.osgi.service.jdbc.version>1.0.0</org.osgi.service.jdbc.version>
         <org.osgi.service.jpa.version>1.0.0</org.osgi.service.jpa.version>
         <osgi.version>6.0.0</osgi.version>
@@ -1081,6 +1082,21 @@
                 <version>2.2</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.maven.wagon</groupId>
+                <artifactId>wagon-provider-api</artifactId>
+                <version>${maven.wagon.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.wagon</groupId>
+                <artifactId>wagon-http</artifactId>
+                <version>${maven.wagon.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.wagon</groupId>
+                <artifactId>wagon-http-lightweight</artifactId>
+                <version>${maven.wagon.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>xerces</groupId>
                 <artifactId>xercesImpl</artifactId>
                 <version>${xerces.version}</version>

http://git-wip-us.apache.org/repos/asf/karaf/blob/5c2bb4b6/tooling/karaf-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/pom.xml b/tooling/karaf-maven-plugin/pom.xml
index 0eca8c1..ffcc052 100644
--- a/tooling/karaf-maven-plugin/pom.xml
+++ b/tooling/karaf-maven-plugin/pom.xml
@@ -83,7 +83,6 @@
         <dependency>
             <groupId>org.apache.maven.wagon</groupId>
             <artifactId>wagon-http</artifactId>
-            <version>2.10</version>
         </dependency>
         <dependency>
             <groupId>org.apache.karaf</groupId>

http://git-wip-us.apache.org/repos/asf/karaf/blob/5c2bb4b6/tooling/karaf-services-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-services-maven-plugin/pom.xml b/tooling/karaf-services-maven-plugin/pom.xml
index 4fa33e5..4dbaa56 100644
--- a/tooling/karaf-services-maven-plugin/pom.xml
+++ b/tooling/karaf-services-maven-plugin/pom.xml
@@ -82,7 +82,6 @@
         <dependency>
             <groupId>org.apache.maven.wagon</groupId>
             <artifactId>wagon-http-lightweight</artifactId>
-            <version>2.6</version>
         </dependency>
         <dependency>
             <groupId>org.sonatype.plexus</groupId>


[07/12] karaf git commit: [KARAF-5008] Initial "maven/core" module and first maven:summary command

Posted by gg...@apache.org.
[KARAF-5008] Initial "maven/core" module and first maven:summary command


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

Branch: refs/heads/master-maven-commands
Commit: 3ea2be24f2faf27892abaaf901aa4fa08242a61d
Parents: 5c2bb4b
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Mon Mar 13 15:42:53 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              | 133 ++++++++
 .../command/MavenConfigurationSupport.java      | 298 ++++++++++++++++
 .../karaf/maven/command/RepoListCommand.java    |  70 ++++
 .../karaf/maven/command/SummaryCommand.java     | 100 ++++++
 .../karaf/maven/core/MavenRepositoryURL.java    | 338 +++++++++++++++++++
 .../src/main/resources/OSGI-INF/bundle.info     |  36 ++
 maven/pom.xml                                   |  40 +++
 pom.xml                                         |  11 +
 8 files changed, 1026 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
new file mode 100644
index 0000000..a05b3d1
--- /dev/null
+++ b/maven/core/pom.xml
@@ -0,0 +1,133 @@
+<?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</groupId>
+        <artifactId>karaf</artifactId>
+        <version>4.1.1-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.maven</groupId>
+    <artifactId>org.apache.karaf.maven.core</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Maven :: Core</name>
+    <description>This bundle provides services and commands for Maven diagnostics.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ops4j.pax.url</groupId>
+            <artifactId>pax-url-aether</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings-builder</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-embedder</artifactId>
+            <version>3.0.3</version>
+        </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.karaf.tooling</groupId>
+                <artifactId>karaf-services-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Export-Package>
+                            org.apache.karaf.maven
+                        </Export-Package>
+                        <Import-Package>
+                            !org.apache.maven*,
+                            !org.codehaus.plexus*,
+                            !org.sonatype.aether*,
+                            !org.sonatype.guice*,
+                            *,
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.maven.command,
+                            org.apache.karaf.maven.core,
+                            org.apache.maven.settings.*,
+                            org.apache.maven.execution,
+                            org.apache.maven.model,
+                            org.codehaus.plexus.component.annotations,
+                            org.sonatype.plexus.components.sec.dispatcher*,
+                            org.sonatype.plexus.components.cipher,
+                            org.codehaus.plexus.interpolation,
+                            org.codehaus.plexus.util,
+                            org.codehaus.plexus.util.xml,
+                            org.codehaus.plexus.util.xml.pull,
+                            org.codehaus.plexus.interpolation.os,
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
new file mode 100644
index 0000000..dbab04a
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -0,0 +1,298 @@
+/*
+ * 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.maven.command;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.building.DefaultSettingsBuilder;
+import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingResult;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+
+/**
+ * <p>Base class for <code>maven:</code> commands.</p>
+ * <p>Even if it duplicates some code from pax-url-aether, this should be treated as verification code of how
+ * pax-url-aether should interact with <code>org.ops4j.pax.url.mvn</code> PID configuration.</p>
+ */
+public abstract class MavenConfigurationSupport implements Action {
+
+    public static Logger LOG = LoggerFactory.getLogger(MavenConfigurationSupport.class);
+    protected static final String PID = "org.ops4j.pax.url.mvn";
+
+    static final String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+    static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
+    static final String PROPERTY_REPOSITORIES = "repositories";
+    static final String PROPERTY_SETTINGS_FILE = "settings";
+
+    protected FileAndSource localRepository;
+    protected FileAndSource settings;
+    protected Settings effectiveSettings;
+    protected Map<String, String> serverPasswords = new HashMap<>();
+    protected Map<String, String> proxyPasswords = new HashMap<>();
+
+    protected List<String> warnings = new LinkedList<>();
+
+    @Reference
+    protected ConfigurationAdmin cm;
+
+    @Override
+    final public Object execute() throws Exception {
+        Configuration c = cm.getConfiguration(PID);
+
+        if (c != null && c.getProperties() != null) {
+            settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
+            if (settings.file != null) {
+                reReadSettings(settings.file);
+            }
+            localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
+
+            doAction(PID + ".", c.getProperties());
+        } else {
+            System.err.printf("Can't access \"%s\" configuration\n", PID);
+        }
+
+        return null;
+    }
+
+    /**
+     * Performs command action on <strong>existing</strong> <code>org.ops4j.pax.url.mvn</code>
+     * PID configuration
+     * @param prefix
+     * @param config
+     */
+    abstract protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception;
+
+    /**
+     * Splits comma separated list of values into String array
+     * @param list
+     * @return
+     */
+    protected String[] listOfValues(String list) {
+        if (list == null) {
+            return new String[0];
+        }
+
+        String[] values = list.split("\\s*,\\s*");
+        return Arrays.stream(values)
+                .filter((value) -> (value != null && !"".equals(value.trim())))
+                .toArray(String[]::new);
+    }
+
+    /**
+     * Gets effective location of <code>settings.xml</code> file - according to pax-url-aether rules
+     * @param cmProperty property obtained from Config Admin
+     * @return
+     */
+    protected FileAndSource settings(String cmProperty) {
+        FileAndSource result = new FileAndSource();
+        URL locationUrl = null;
+        String probableErrorMessage = null;
+
+        // 1. PID + ".settings"
+        if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            try {
+                locationUrl = new URL(cmProperty);
+                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
+                        locationUrl, PID, PROPERTY_SETTINGS_FILE);
+            } catch (MalformedURLException e) {
+                File file = new File(cmProperty);
+                if (file.isFile()) {
+                    result.file = file;
+                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_SETTINGS_FILE);
+                    return result;
+                }
+            }
+        }
+
+        // 2. System.getProperty("user.home") + "/.m2/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("user.home") + "/.m2/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit ${user.home}/.m2/settings.xml";
+                return result;
+            }
+        }
+
+        // 3. System.getProperty("maven.home") + "/conf/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("maven.home") + "/conf/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit ${maven.home}/conf/settings.xml";
+                return result;
+            }
+        }
+
+        // 4. System.getenv("M2_HOME") + "/conf/settings.xml"
+        if (locationUrl == null) {
+            File file = new File(System.getenv("M2_HOME") + "/conf/settings.xml");
+            if (file.isFile()) {
+                result.file = file;
+                result.source = "Implicit $M2_HOME/conf/settings.xml";
+                return result;
+            }
+        }
+
+        if (locationUrl != null) {
+            File file = new File(locationUrl.getPath());
+            if (file.isFile()) {
+                result.file = file;
+                return result;
+            } else {
+                throw new IllegalArgumentException(probableErrorMessage);
+            }
+        }
+
+        // 5. new org.apache.maven.settings.Settings()
+        return result;
+    }
+
+    /**
+     * Gets effective location of <em>local repository</em> - according to pax-url-aether rules
+     * @param cmProperty property obtained from Config Admin
+     * @return
+     */
+    protected FileAndSource localRepository(String cmProperty) {
+        FileAndSource result = new FileAndSource();
+        URL locationUrl = null;
+        String probableErrorMessage = null;
+
+        // 1. PID + ".localRepository"
+        if (cmProperty != null && !"".equals(cmProperty.trim())) {
+            try {
+                locationUrl = new URL(cmProperty);
+                result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                probableErrorMessage = String.format("%s configured in %s.%s is not accessible",
+                        locationUrl, PID, PROPERTY_LOCAL_REPOSITORY);
+            } catch (MalformedURLException e) {
+                File file = new File(cmProperty);
+                if (file.isDirectory()) {
+                    result.file = file;
+                    result.source = String.format("Explicit %s PID configuration (%s)", PID, PID + "." + PROPERTY_LOCAL_REPOSITORY);
+                    return result;
+                }
+            }
+        }
+
+        // 2. from settings.xml
+        if (locationUrl == null && effectiveSettings != null && effectiveSettings.getLocalRepository() != null) {
+            try {
+                locationUrl = new URL(effectiveSettings.getLocalRepository());
+                result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                probableErrorMessage = String.format("%s configured in %s is not accessible",
+                        effectiveSettings.getLocalRepository(), settings.file);
+            } catch (MalformedURLException e) {
+                File file = new File(effectiveSettings.getLocalRepository());
+                if (file.isDirectory()) {
+                    result.file = file;
+                    result.source = String.format("Explicit <localRepository> in %s", settings.file);
+                    return result;
+                }
+            }
+        }
+
+        // 3. System.getProperty("user.home") + "/.m2/repository";
+        if (locationUrl == null) {
+            File file = new File(System.getProperty("user.home") + "/.m2/repository");
+            if (file.isDirectory()) {
+                result.file = file;
+                result.source = "Implicit ${user.home}/.m2/repository";
+                return result;
+            }
+        }
+
+        if (locationUrl != null) {
+            File file = new File(locationUrl.getPath());
+            if (file.isDirectory()) {
+                result.file = file;
+                return result;
+            } else {
+                throw new IllegalArgumentException(probableErrorMessage);
+            }
+        }
+
+        // 5. new org.apache.maven.settings.Settings()
+        return null;
+    }
+
+    /**
+     * Re-reads on demand <code>settings.xml</code> file - with password decryption
+     * @param settingsFile
+     */
+    protected synchronized void reReadSettings(File settingsFile) throws SettingsBuildingException {
+        effectiveSettings = null;
+
+        if (!settingsFile.isFile() || !settingsFile.canRead()) {
+            throw new IllegalArgumentException(settingsFile + " is not accessible");
+        }
+
+        try {
+            DefaultSettingsBuilderFactory factory = new DefaultSettingsBuilderFactory();
+            DefaultSettingsBuilder builder = factory.newInstance();
+            SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+            request.setUserSettingsFile(settingsFile);
+
+            SettingsBuildingResult result = builder.build(request);
+            if (result.getProblems().size() > 0) {
+                for (SettingsProblem problem : result.getProblems()) {
+                    System.err.println(problem);
+                }
+            } else {
+                effectiveSettings = result.getEffectiveSettings();
+                decryptSettings(effectiveSettings);
+            }
+        } catch (Throwable e) {
+            LOG.error(e.getMessage(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * Decrypts passwords inside <code>&lt;proxy&gt;</code> and <code>&lt;repository&gt;</code>
+     * @param settings
+     */
+    private void decryptSettings(Settings settings) {
+        String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
+    }
+
+    protected static class FileAndSource  {
+        File file;
+        String source;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
new file mode 100644
index 0000000..02195e1
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
@@ -0,0 +1,70 @@
+/*
+ * 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.maven.command;
+
+import java.net.MalformedURLException;
+import java.util.Dictionary;
+
+import org.apache.karaf.maven.core.MavenRepositoryURL;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "maven", name = "repo-list", description = "Maven repository summary.")
+@Service
+public class RepoListCommand extends MavenConfigurationSupport {
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws MalformedURLException {
+        ShellTable table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        table.column("Snapshots");
+        table.column("Releases");
+
+        System.out.println("== Remote repositories");
+        String[] repositories = listOfValues((String) config.get(prefix + PROPERTY_REPOSITORIES));
+        for (String repo : repositories) {
+            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+            table.addRow().addContent(repoURL.getId(),
+                    repoURL.getURL(),
+                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
+                    repoURL.isReleasesEnabled() ? "yes" : "no");
+        }
+
+        table.print(System.out);
+
+        table = new ShellTable();
+        table.column("ID");
+        table.column("URL");
+        table.column("Snapshots");
+        table.column("Releases");
+        System.out.println();
+        System.out.println("== Default repositories");
+        repositories = listOfValues((String) config.get(prefix + PROPERTY_DEFAULT_REPOSITORIES));
+        for (String repo : repositories) {
+            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+            table.addRow().addContent(repoURL.getId(),
+                    repoURL.getURL(),
+                    repoURL.isSnapshotsEnabled() ? "yes" : "no",
+                    repoURL.isReleasesEnabled() ? "yes" : "no");
+        }
+
+        table.print(System.out);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
new file mode 100644
index 0000000..0e791cd
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -0,0 +1,100 @@
+/*
+ * 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.maven.command;
+
+import java.util.Dictionary;
+
+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.Col;
+import org.apache.karaf.shell.support.table.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+@Command(scope = "maven", name = "summary", description = "Maven configuration summary.")
+@Service
+public class SummaryCommand extends MavenConfigurationSupport {
+
+    @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
+    boolean description;
+
+    /*
+     * All options from org.ops4j.pax.url.mvn.ServiceConstants (2.5.2):
+     *
+     * String PROPERTY_LOCAL_REPOSITORY = "localRepository";
+     * String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
+     * String PROPERTY_REPOSITORIES = "repositories";
+     * String PROPERTY_SETTINGS_FILE = "settings";
+     * String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
+     * String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
+     * String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
+     * String PROPERTY_UPDATE_RELEASES = "updateReleases";
+     * String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote";
+     * String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
+     * String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
+     * String PROPERTY_PROXY_SUPPORT = "proxySupport";
+     * String PROPERTY_SECURITY = "security";
+     * String PROPERTY_TIMEOUT = "timeout";
+     * String PROPERTY_OFFLINE = "offline";
+     * String PROPERTY_PROXIES = "proxies";
+     * String PROPERTY_SOCKET_SO_TIMEOUT = "socket.readTimeout";
+     * String PROPERTY_SOCKET_SO_KEEPALIVE = "socket.keepAlive";
+     * String PROPERTY_SOCKET_SO_LINGER = "socket.linger";
+     * String PROPERTY_SOCKET_SO_REUSEADDRESS = "socket.reuseAddress";
+     * String PROPERTY_SOCKET_TCP_NODELAY = "socket.tcpNoDelay";
+     * String PROPERTY_SOCKET_CONNECTION_TIMEOUT = "socket.connectionTimeout";
+     * String PROPERTY_CONNECTION_BUFFER_SIZE = "connection.bufferSize";
+     * String PROPERTY_CONNECTION_RETRY_COUNT = "connection.retryCount";
+     *
+     * String OPTION_ALLOW_SNAPSHOTS = "snapshots";
+     * String OPTION_DISALLOW_RELEASES = "noreleases";
+     * String OPTION_MULTI = "multi";
+     * String OPTION_ID = "id";
+     * String OPTION_UPDATE = "update";
+     * String OPTION_RELEASES_UPDATE = "releasesUpdate";
+     * String OPTION_SNAPSHOTS_UPDATE = "snapshotsUpdate";
+     * String OPTION_CHECKSUM = "checksum";
+     * String OPTION_RELEASES_CHECKSUM = "releasesChecksum";
+     * String OPTION_SNAPSHOTS_CHECKSUM = "snapshotsChecksum";
+     */
+
+    @Override
+    protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        ShellTable table = new ShellTable();
+        table.column(new Col("Option").alignRight());
+        table.column("Value");
+        table.column("Source");
+        if (description) {
+            table.column("Description");
+        }
+
+        Row row = table.addRow();
+        row.addContent("Local repository", localRepository.file, localRepository.source);
+        if (description) {
+            row.addContent("Maven repository to store artifacts resolved in *remote repositories*");
+        }
+
+        row = table.addRow();
+        row.addContent("Settings file", settings.file, settings.source);
+        if (description) {
+            row.addContent("Settings file that may contain configuration of additional repositories, http proxies and mirrors");
+        }
+
+        table.print(System.out);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
new file mode 100644
index 0000000..858f85e
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2008 Alin Dreghiciu.
+ *
+ * Licensed  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.maven.core;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.ops4j.pax.url.mvn.ServiceConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An URL of Maven repository that knows if it contains SNAPSHOT versions and/or releases.
+ *
+ * @author Alin Dreghiciu
+ * @author Guillaume Nodet
+ * @since 0.2.1, February 07, 2008
+ */
+public class MavenRepositoryURL
+{
+
+    private static final Logger LOG = LoggerFactory.getLogger( MavenRepositoryURL.class );
+
+    /**
+     * Repository Id.
+     */
+    private final String m_id;
+    /**
+     * Repository URL.
+     */
+    private final URL m_repositoryURL;
+    /**
+     * Repository file (only if URL is a file URL).
+     */
+    private final File m_file;
+    /**
+     * True if the repository contains snapshots.
+     */
+    private final boolean m_snapshotsEnabled;
+    /**
+     * True if the repository contains releases.
+     */
+    private final boolean m_releasesEnabled;
+    /**
+     * Repository update policy
+     */
+    private final String m_releasesUpdatePolicy;
+    /**
+     * Repository update policy
+     */
+    private final String m_snapshotsUpdatePolicy;
+    /**
+     * Repository checksum policy
+     */
+    private final String m_releasesChecksumPolicy;
+    /**
+     * Repository checksum policy
+     */
+    private final String m_snapshotsChecksumPolicy;
+
+    private final boolean m_multi;
+
+    /**
+     * Creates a maven repository URL bases on a string spec. The path can be marked with @snapshots and/or @noreleases
+     * (not case sensitive).
+     *
+     * @param repositorySpec url spec of repository
+     *
+     * @throws MalformedURLException if spec contains a malformed maven repository url
+     */
+    public MavenRepositoryURL( final String repositorySpec )
+        throws MalformedURLException
+    {
+        final String[] segments = repositorySpec.split( ServiceConstants.SEPARATOR_OPTIONS );
+        final StringBuilder urlBuilder = new StringBuilder();
+        boolean snapshotEnabled = false;
+        boolean releasesEnabled = true;
+        boolean multi = false;
+
+        String name = null;
+        String update = null;
+        String updateReleases = null;
+        String updateSnapshots = null;
+        String checksum = null;
+        String checksumReleases = null;
+        String checksumSnapshots = null;
+
+        for( int i = 0; i < segments.length; i++ )
+        {
+            String segment = segments[i].trim();
+            if( segment.equalsIgnoreCase( ServiceConstants.OPTION_ALLOW_SNAPSHOTS ) )
+            {
+                snapshotEnabled = true;
+            }
+            else if( segment.equalsIgnoreCase( ServiceConstants.OPTION_DISALLOW_RELEASES ) )
+            {
+                releasesEnabled = false;
+            }
+            else if( segment.equalsIgnoreCase( ServiceConstants.OPTION_MULTI ) )
+            {
+                multi = true;
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_ID + "=" ) )
+            {
+                try {
+                    name = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_RELEASES_UPDATE + "=" ) )
+            {
+                try {
+                    updateReleases = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_SNAPSHOTS_UPDATE + "=" ) )
+            {
+                try {
+                    updateSnapshots = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_UPDATE + "=" ) )
+            {
+                try {
+                    update = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_RELEASES_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksumReleases = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_SNAPSHOTS_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksumSnapshots = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else if( segment.startsWith( ServiceConstants.OPTION_CHECKSUM + "=" ) )
+            {
+                try {
+                    checksum = segments[ i ].split( "=" )[1].trim();
+                } catch (Exception e) {
+                    LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
+                }
+            }
+            else
+            {
+                if( i > 0 )
+                {
+                    urlBuilder.append( ServiceConstants.SEPARATOR_OPTIONS );
+                }
+                urlBuilder.append( segments[ i ] );
+            }
+        }
+        String spec = buildSpec( urlBuilder );
+        m_repositoryURL = new URL( spec );
+        m_snapshotsEnabled = snapshotEnabled;
+        m_releasesEnabled = releasesEnabled;
+        m_multi = multi;
+        if (name == null) {
+            String warn = "Repository spec " + spec + " does not contain an identifier. This is deprecated & discouraged & just evil.";
+            LOG.warn( warn );
+            name = "repo_" + spec.hashCode();
+        }
+        m_id = name;
+        m_releasesUpdatePolicy = updateReleases != null ? updateReleases : update;
+        m_snapshotsUpdatePolicy = updateSnapshots != null ? updateSnapshots : update;
+        m_releasesChecksumPolicy = checksumReleases != null ? checksumReleases : checksum;
+        m_snapshotsChecksumPolicy = checksumSnapshots != null ? checksumSnapshots : checksum;
+
+        if( m_repositoryURL.getProtocol().equals( "file" ) )
+        {
+            try
+            {
+                // You must transform to URI to decode the path (manage a path with a space or non
+                // us character)
+                // like D:/documents%20and%20Settings/SESA170017/.m2/repository
+                // the path can be store in path part or in scheme specific part (if is relatif
+                // path)
+                // the anti-slash character is not a valid character for uri.
+                spec = spec.replaceAll( "\\\\", "/" );
+                spec = spec.replaceAll( " ", "%20" );
+                URI uri = new URI( spec );
+                String path = uri.getPath();
+                if( path == null )
+                    path = uri.getSchemeSpecificPart();
+                m_file = new File( path );
+
+            }
+            catch ( URISyntaxException e )
+            {
+                throw new MalformedURLException( e.getMessage() );
+            }
+        }
+        else
+        {
+            m_file = null;
+        }
+    }
+
+    private String buildSpec( StringBuilder urlBuilder )
+    {
+        String spec = urlBuilder.toString().trim();
+        if( !spec.endsWith( "\\" ) && !spec.endsWith( "/" ) )
+        {
+            spec = spec + "/";
+        }
+        return spec;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository id
+     */
+    public String getId()
+    {
+        return m_id;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository URL
+     */
+    public URL getURL()
+    {
+        return m_repositoryURL;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return repository file
+     */
+    public File getFile()
+    {
+        return m_file;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository contains releases
+     */
+    public boolean isReleasesEnabled()
+    {
+        return m_releasesEnabled;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository contains snapshots
+     */
+    public boolean isSnapshotsEnabled()
+    {
+        return m_snapshotsEnabled;
+    }
+
+    public String getReleasesUpdatePolicy() {
+        return m_releasesUpdatePolicy;
+    }
+
+    public String getSnapshotsUpdatePolicy() {
+        return m_snapshotsUpdatePolicy;
+    }
+
+    public String getReleasesChecksumPolicy() {
+        return m_releasesChecksumPolicy;
+    }
+
+    public String getSnapshotsChecksumPolicy() {
+        return m_snapshotsChecksumPolicy;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return true if the repository is a parent path of repos
+     */
+    public boolean isMulti()
+    {
+        return m_multi;
+    }
+
+    /**
+     * Getter.
+     *
+     * @return if the repository is a file based repository.
+     */
+    public boolean isFileRepository()
+    {
+        return m_file != null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return new StringBuilder()
+            .append( m_repositoryURL.toString() )
+            .append( ",releases=" ).append( m_releasesEnabled )
+            .append( ",snapshots=" ).append( m_snapshotsEnabled )
+            .toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/maven/core/src/main/resources/OSGI-INF/bundle.info b/maven/core/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..509e13b
--- /dev/null
+++ b/maven/core/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,36 @@
+#
+#
+#    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.
+#
+#
+h1. Synopsis
+
+	${project.name}
+
+	${project.description}
+
+	Maven URL:
+		[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+	This bundle is the core implementation of Maven diagnostics support and exposes commands
+	to change and examine Maven configuration managed by pax-url-aether bundle and org.ops4j.pax.url.mvn PID.
+
+h1. Commands
+
+	The bundle contains the following commands:
+\${command-list|maven|indent=8,list,cyan}

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/maven/pom.xml
----------------------------------------------------------------------
diff --git a/maven/pom.xml b/maven/pom.xml
new file mode 100644
index 0000000..a8d8369
--- /dev/null
+++ b/maven/pom.xml
@@ -0,0 +1,40 @@
+<?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</groupId>
+        <artifactId>karaf</artifactId>
+        <version>4.1.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.maven</groupId>
+    <artifactId>maven-parent</artifactId>
+    <packaging>pom</packaging>
+    <name>Apache Karaf :: Maven</name>
+
+    <modules>
+        <module>core</module>
+    </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/karaf/blob/3ea2be24/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a7367d2..2767cb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,7 @@
         <module>jdbc</module>
         <module>jms</module>
         <module>jpa</module>
+        <module>maven</module>
         <module>services</module>
         <module>subsystem</module>
         <module>profile</module>
@@ -1077,6 +1078,16 @@
                 <version>${maven.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-settings</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-settings-builder</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.apache.maven.shared</groupId>
                 <artifactId>maven-dependency-tree</artifactId>
                 <version>2.2</version>


[04/12] karaf git commit: [KARAF-5008] Clean up org.apache.maven.* dependencies (align to 3.0.3 for now)

Posted by gg...@apache.org.
[KARAF-5008] Clean up org.apache.maven.* dependencies (align to 3.0.3 for now)


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

Branch: refs/heads/master-maven-commands
Commit: 2f7c5d7cc7db73dfaa2eb970bb874b269b5aec5c
Parents: 83d4135
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Fri Mar 10 12:03:27 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 pom.xml                                     | 24 +++++++++++++++++-------
 tooling/karaf-maven-plugin/pom.xml          |  6 +-----
 tooling/karaf-services-maven-plugin/pom.xml |  6 +-----
 3 files changed, 19 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2f7c5d7c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7cf0e15..a507ab6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -252,7 +252,7 @@
         <jline.version>3.3.0</jline.version>
         <jsw.version>3.2.3</jsw.version>
         <log4j.version>1.2.17</log4j.version>
-        <maven.version>2.0.9</maven.version>
+        <maven.version>3.0.3</maven.version>
         <org.osgi.service.jdbc.version>1.0.0</org.osgi.service.jdbc.version>
         <org.osgi.service.jpa.version>1.0.0</org.osgi.service.jpa.version>
         <osgi.version>6.0.0</osgi.version>
@@ -1062,10 +1062,25 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.maven</groupId>
-                <artifactId>maven-project</artifactId>
+                <artifactId>maven-compat</artifactId>
                 <version>${maven.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-core</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven</groupId>
+                <artifactId>maven-artifact</artifactId>
+                <version>${maven.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.maven.shared</groupId>
+                <artifactId>maven-dependency-tree</artifactId>
+                <version>2.2</version>
+            </dependency>
+            <dependency>
                 <groupId>xerces</groupId>
                 <artifactId>xercesImpl</artifactId>
                 <version>${xerces.version}</version>
@@ -1177,11 +1192,6 @@
                 <version>${jline.version}</version>
             </dependency>
             <dependency>
-                <groupId>org.apache.maven.artifact</groupId>
-                <artifactId>maven-artifact</artifactId>
-                <version>3.0-alpha-1</version>
-            </dependency>
-            <dependency>
                 <groupId>org.slf4j</groupId>
                 <artifactId>slf4j-api</artifactId>
                 <version>${slf4j.version}</version>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2f7c5d7c/tooling/karaf-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/pom.xml b/tooling/karaf-maven-plugin/pom.xml
index d88899b..0eca8c1 100644
--- a/tooling/karaf-maven-plugin/pom.xml
+++ b/tooling/karaf-maven-plugin/pom.xml
@@ -42,7 +42,6 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-plugin-api</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.sonatype.aether</groupId>
@@ -67,17 +66,14 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-artifact</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-core</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-compat</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven.plugin-tools</groupId>
@@ -105,7 +101,7 @@
         <dependency>
             <groupId>org.apache.maven.shared</groupId>
             <artifactId>maven-filtering</artifactId>
-            <version>1.0-beta-4</version>
+            <version>3.1.1</version>
         </dependency>
         <dependency>
             <groupId>org.codehaus.plexus</groupId>

http://git-wip-us.apache.org/repos/asf/karaf/blob/2f7c5d7c/tooling/karaf-services-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/tooling/karaf-services-maven-plugin/pom.xml b/tooling/karaf-services-maven-plugin/pom.xml
index 728999f..4fa33e5 100644
--- a/tooling/karaf-services-maven-plugin/pom.xml
+++ b/tooling/karaf-services-maven-plugin/pom.xml
@@ -41,7 +41,6 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-plugin-api</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven.plugin-tools</groupId>
@@ -71,17 +70,14 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-artifact</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-core</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-compat</artifactId>
-            <version>3.0.3</version>
         </dependency>
         <dependency>
             <groupId>org.apache.maven.wagon</groupId>
@@ -120,7 +116,7 @@
         <dependency>
             <groupId>org.apache.maven.shared</groupId>
             <artifactId>maven-filtering</artifactId>
-            <version>1.0-beta-4</version>
+            <version>3.1.1</version>
         </dependency>
         <dependency>
             <groupId>org.codehaus.plexus</groupId>


[03/12] karaf git commit: [KARAF-5008] maven:summary for repositories, defaultRepositories and proxies

Posted by gg...@apache.org.
[KARAF-5008] maven:summary for repositories, defaultRepositories and proxies


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

Branch: refs/heads/master-maven-commands
Commit: 2dc56e46c7127b180befb83b15a09839b5f6679d
Parents: 84505fb
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Wed Mar 15 09:09:00 2017 +0100
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 08:33:47 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              |   1 +
 .../command/MavenConfigurationSupport.java      | 169 +++++++++++++++----
 .../karaf/maven/command/RepoListCommand.java    |  20 +--
 .../karaf/maven/command/SummaryCommand.java     | 106 ++++++------
 .../karaf/maven/core/MavenRepositoryURL.java    |  48 ++++++
 5 files changed, 252 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/2dc56e46/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
index 197a145..1380a56 100644
--- a/maven/core/pom.xml
+++ b/maven/core/pom.xml
@@ -114,6 +114,7 @@
                             org.sonatype.plexus.components.sec.dispatcher*,
                             org.sonatype.plexus.components.cipher,
                             org.codehaus.plexus.interpolation,
+                            org.codehaus.plexus.logging,
                             org.codehaus.plexus.util,
                             org.codehaus.plexus.util.xml,
                             org.codehaus.plexus.util.xml.pull,

http://git-wip-us.apache.org/repos/asf/karaf/blob/2dc56e46/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index c772913..00ca8c8 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -22,12 +22,17 @@ import java.net.URL;
 import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Action;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.maven.settings.Profile;
+import org.apache.maven.settings.Repository;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.building.DefaultSettingsBuilder;
 import org.apache.maven.settings.building.DefaultSettingsBuilderFactory;
@@ -41,6 +46,7 @@ import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
@@ -70,6 +76,18 @@ public abstract class MavenConfigurationSupport implements Action {
     protected static final String PROPERTY_OFFLINE = "offline";
     protected static final String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
 
+    // TODO timeout options {
+    protected static final String PROPERTY_TIMEOUT = "timeout";
+    protected static final String PROPERTY_SOCKET_SO_TIMEOUT = "socket.readTimeout";
+    protected static final String PROPERTY_SOCKET_SO_KEEPALIVE = "socket.keepAlive";
+    protected static final String PROPERTY_SOCKET_SO_LINGER = "socket.linger";
+    protected static final String PROPERTY_SOCKET_SO_REUSEADDRESS = "socket.reuseAddress";
+    protected static final String PROPERTY_SOCKET_TCP_NODELAY = "socket.tcpNoDelay";
+    protected static final String PROPERTY_SOCKET_CONNECTION_TIMEOUT = "socket.connectionTimeout";
+    protected static final String PROPERTY_CONNECTION_BUFFER_SIZE = "connection.bufferSize";
+    protected static final String PROPERTY_CONNECTION_RETRY_COUNT = "connection.retryCount";
+    // }
+
     protected SourceAnd<File> localRepository;
     protected SourceAnd<File> settings;
     protected Settings mavenSettings;
@@ -81,6 +99,9 @@ public abstract class MavenConfigurationSupport implements Action {
 
     protected List<String> warnings = new LinkedList<>();
 
+    private static final String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
+    protected String masterPassword;
+
     @Reference
     protected ConfigurationAdmin cm;
 
@@ -92,20 +113,24 @@ public abstract class MavenConfigurationSupport implements Action {
         Configuration c = cm.getConfiguration(PID);
 
         if (c != null && c.getProperties() != null) {
-            securitySettings = securitySettings((String) c.getProperties().get(PID + "." + PROPERTY_SECURITY_FILE));
-            if (securitySettings != null && securitySettings.value != null) {
-                mavenSecuritySettings = readSecuritySettings(securitySettings.value);
-            }
+            try {
+                securitySettings = securitySettings((String) c.getProperties().get(PID + "." + PROPERTY_SECURITY_FILE));
+                if (securitySettings != null && securitySettings.value != null) {
+                    mavenSecuritySettings = readSecuritySettings(securitySettings.value);
+                }
 
-            settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
-            if (settings != null && settings.value != null) {
-                mavenSettings = readSettings(settings.value);
-                decryptSettings(mavenSettings);
-            }
+                settings = settings((String) c.getProperties().get(PID + "." + PROPERTY_SETTINGS_FILE));
+                if (settings != null && settings.value != null) {
+                    mavenSettings = readSettings(settings.value);
+                }
 
-            localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
+                localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
 
-            doAction(PID + ".", c.getProperties());
+                doAction(PID + ".", c.getProperties());
+            } catch (Exception e) {
+                System.err.println(e.getMessage());
+                LOG.error(e.getMessage(), e);
+            }
         } else {
             System.err.printf("Can't access \"%s\" configuration\n", PID);
         }
@@ -122,22 +147,6 @@ public abstract class MavenConfigurationSupport implements Action {
     abstract protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception;
 
     /**
-     * Splits comma separated list of values into String array
-     * @param list
-     * @return
-     */
-    protected String[] listOfValues(String list) {
-        if (list == null) {
-            return new String[0];
-        }
-
-        String[] values = list.split("\\s*,\\s*");
-        return Arrays.stream(values)
-                .filter((value) -> (value != null && !"".equals(value.trim())))
-                .toArray(String[]::new);
-    }
-
-    /**
      * Gets effective location of <code>settings.xml</code> file - according to pax-url-aether rules
      * @param cmProperty property obtained from Config Admin
      * @return
@@ -361,11 +370,109 @@ public abstract class MavenConfigurationSupport implements Action {
     }
 
     /**
-     * Decrypts passwords inside <code>&lt;proxy&gt;</code> and <code>&lt;repository&gt;</code>
-     * @param settings
+     * <p>Decrypts passwords inside correctly read <code>settings.xml</code>. Also tries to decrypt master password.</p>
+     * <p>Not called implicitly for each action invocation.</p>
      */
-    private void decryptSettings(Settings settings) {
-        String masterMasterPassword = DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION;
+    protected void decryptSettings() throws Exception {
+        if (mavenSecuritySettings != null) {
+            masterPassword = new DefaultPlexusCipher().decryptDecorated(mavenSecuritySettings.getMaster(), masterMasterPassword);
+        }
+    }
+
+    /**
+     * Returns list of configured remote (<code>remote=true</code>) or default (<code>remote=false</code>)
+     * repositories.
+     * @param remote
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    protected MavenRepositoryURL[] repositories(Dictionary<String, Object> config, boolean remote) throws Exception {
+        String property = remote ? PID + "." + PROPERTY_REPOSITORIES : PID + "." + PROPERTY_DEFAULT_REPOSITORIES;
+        String[] repositories = listOfValues((String) config.get(property));
+
+        if (remote) {
+            if (repositories.length == 0 || repositories.length > 0 && repositories[0].charAt(0) == '+') {
+                repositories[0] = repositories[0].substring(1);
+
+                List<String> newRepositories = new LinkedList<>();
+                newRepositories.addAll(Arrays.asList(repositories));
+
+                // append all repositories from all active profiles from available settings.xml
+                if (mavenSettings != null) {
+                    // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.getRepositories()
+                    Set<String> activeProfiles = new LinkedHashSet<>(mavenSettings.getActiveProfiles());
+                    Map<String, Profile> profiles = (Map<String, Profile>)mavenSettings.getProfilesAsMap();
+                    profiles.values().stream()
+                            .filter((profile) -> profile.getActivation() != null && profile.getActivation().isActiveByDefault())
+                            .map(Profile::getId)
+                            .forEach(activeProfiles::add);
+
+                    for (String activeProfile : activeProfiles) {
+                        Profile profile = profiles.get(activeProfile);
+                        if (profile == null) {
+                            continue;
+                        }
+                        for (Repository repo : profile.getRepositories()) {
+                            StringBuilder builder = new StringBuilder();
+                            builder.append(repo.getUrl());
+                            builder.append("@id=").append(repo.getId());
+                            builder.append("@_from=").append(MavenRepositoryURL.FROM.SETTINGS);
+
+                            if (repo.getReleases() != null) {
+                                if (!repo.getReleases().isEnabled()) {
+                                    builder.append("@noreleases");
+                                }
+                                addPolicy(builder, repo.getReleases().getUpdatePolicy(), "releasesUpdate");
+                                // not used in pax-url-aether
+                                //addPolicy(builder, repo.getReleases().getChecksumPolicy(), "releasesChecksum");
+                            }
+                            if (repo.getSnapshots() != null) {
+                                if (repo.getSnapshots().isEnabled()) {
+                                    builder.append("@snapshots");
+                                }
+                                addPolicy(builder, repo.getSnapshots().getUpdatePolicy(), "snapshotsUpdate");
+                                // not used in pax-url-aether
+                                //addPolicy(builder, repo.getSnapshots().getChecksumPolicy(), "snapshotsChecksum");
+                            }
+                            newRepositories.add(builder.toString());
+                        }
+                    }
+                }
+
+                repositories = newRepositories.toArray(new String[newRepositories.size()]);
+            }
+        }
+
+        List<MavenRepositoryURL> result = new LinkedList<>();
+        for (String repo : repositories) {
+            result.add(new MavenRepositoryURL(repo));
+        }
+        return result.toArray(new MavenRepositoryURL[result.size()]);
+    }
+
+    private void addPolicy(StringBuilder builder, String policy, String option) {
+        if (policy != null && !policy.isEmpty()) {
+            builder.append("@");
+            builder.append(option);
+            builder.append("=");
+            builder.append(policy);
+        }
+    }
+
+    /**
+     * Splits comma separated list of values into String array
+     * @param list
+     * @return
+     */
+    protected String[] listOfValues(String list) {
+        if (list == null) {
+            return new String[0];
+        }
+
+        String[] values = list.split("\\s*,\\s*");
+        return Arrays.stream(values)
+                .filter((value) -> (value != null && !"".equals(value.trim())))
+                .toArray(String[]::new);
     }
 
     protected static class SourceAnd<T> {

http://git-wip-us.apache.org/repos/asf/karaf/blob/2dc56e46/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
index 02195e1..7e13047 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepoListCommand.java
@@ -16,7 +16,6 @@
  */
 package org.apache.karaf.maven.command;
 
-import java.net.MalformedURLException;
 import java.util.Dictionary;
 
 import org.apache.karaf.maven.core.MavenRepositoryURL;
@@ -29,21 +28,22 @@ import org.apache.karaf.shell.support.table.ShellTable;
 public class RepoListCommand extends MavenConfigurationSupport {
 
     @Override
-    public void doAction(String prefix, Dictionary<String, Object> config) throws MalformedURLException {
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
         ShellTable table = new ShellTable();
         table.column("ID");
         table.column("URL");
         table.column("Snapshots");
         table.column("Releases");
+        table.column("Defined in");
 
         System.out.println("== Remote repositories");
-        String[] repositories = listOfValues((String) config.get(prefix + PROPERTY_REPOSITORIES));
-        for (String repo : repositories) {
-            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+        MavenRepositoryURL[] repositories = repositories(config, true);
+        for (MavenRepositoryURL repoURL : repositories) {
             table.addRow().addContent(repoURL.getId(),
                     repoURL.getURL(),
                     repoURL.isSnapshotsEnabled() ? "yes" : "no",
-                    repoURL.isReleasesEnabled() ? "yes" : "no");
+                    repoURL.isReleasesEnabled() ? "yes" : "no",
+                    repoURL.getFrom());
         }
 
         table.print(System.out);
@@ -55,13 +55,13 @@ public class RepoListCommand extends MavenConfigurationSupport {
         table.column("Releases");
         System.out.println();
         System.out.println("== Default repositories");
-        repositories = listOfValues((String) config.get(prefix + PROPERTY_DEFAULT_REPOSITORIES));
-        for (String repo : repositories) {
-            MavenRepositoryURL repoURL = new MavenRepositoryURL(repo);
+        repositories = repositories(config, false);
+        for (MavenRepositoryURL repoURL : repositories) {
             table.addRow().addContent(repoURL.getId(),
                     repoURL.getURL(),
                     repoURL.isSnapshotsEnabled() ? "yes" : "no",
-                    repoURL.isReleasesEnabled() ? "yes" : "no");
+                    repoURL.isReleasesEnabled() ? "yes" : "no",
+                    repoURL.getFrom());
         }
 
         table.print(System.out);

http://git-wip-us.apache.org/repos/asf/karaf/blob/2dc56e46/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index f68c555..6892939 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -18,67 +18,34 @@ package org.apache.karaf.maven.command;
 
 import java.util.Dictionary;
 
+import org.apache.karaf.maven.core.MavenRepositoryURL;
 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.Col;
 import org.apache.karaf.shell.support.table.Row;
 import org.apache.karaf.shell.support.table.ShellTable;
+import org.apache.maven.settings.Proxy;
 
 @Command(scope = "maven", name = "summary", description = "Maven configuration summary.")
 @Service
 public class SummaryCommand extends MavenConfigurationSupport {
 
+    @Option(name = "-p", aliases = { "--property-ids" }, description = "Use PID property identifiers instead of their names", required = false, multiValued = false)
+    boolean propertyIds;
+
     @Option(name = "-s", aliases = { "--source" }, description = "Adds information about where the value is configured", required = false, multiValued = false)
     boolean source;
 
     @Option(name = "-d", aliases = { "--description" }, description = "Adds description of Maven configuration options", required = false, multiValued = false)
     boolean description;
 
-    /*
-     * All options from org.ops4j.pax.url.mvn.ServiceConstants (2.5.2):
-     *
-     * +String PROPERTY_LOCAL_REPOSITORY = "localRepository";
-     * String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
-     * String PROPERTY_REPOSITORIES = "repositories";
-     * +String PROPERTY_SETTINGS_FILE = "settings";
-     * +String PROPERTY_SECURITY = "security";
-     * +String REQUIRE_CONFIG_ADMIN_CONFIG = "requireConfigAdminConfig";
-     * +String PROPERTY_GLOBAL_UPDATE_POLICY = "globalUpdatePolicy";
-     * +String PROPERTY_GLOBAL_CHECKSUM_POLICY = "globalChecksumPolicy";
-     * +String PROPERTY_UPDATE_RELEASES = "updateReleases";
-     * -String PROPERTY_LOCAL_REPO_AS_REMOTE = "defaultLocalRepoAsRemote"; // silly to use
-     * +String PROPERTY_CERTIFICATE_CHECK = "certificateCheck";
-     * +String PROPERTY_USE_FALLBACK_REPOSITORIES = "useFallbackRepositories";
-     * -String PROPERTY_PROXY_SUPPORT = "proxySupport"; // not used in "new" MavenResolver
-     * String PROPERTY_TIMEOUT = "timeout";
-     * +String PROPERTY_OFFLINE = "offline";
-     * -String PROPERTY_PROXIES = "proxies"; // not used in "new" MavenResolver
-     * String PROPERTY_SOCKET_SO_TIMEOUT = "socket.readTimeout";
-     * String PROPERTY_SOCKET_SO_KEEPALIVE = "socket.keepAlive";
-     * String PROPERTY_SOCKET_SO_LINGER = "socket.linger";
-     * String PROPERTY_SOCKET_SO_REUSEADDRESS = "socket.reuseAddress";
-     * String PROPERTY_SOCKET_TCP_NODELAY = "socket.tcpNoDelay";
-     * String PROPERTY_SOCKET_CONNECTION_TIMEOUT = "socket.connectionTimeout";
-     * String PROPERTY_CONNECTION_BUFFER_SIZE = "connection.bufferSize";
-     * String PROPERTY_CONNECTION_RETRY_COUNT = "connection.retryCount";
-     *
-     * String OPTION_ALLOW_SNAPSHOTS = "snapshots";
-     * String OPTION_DISALLOW_RELEASES = "noreleases";
-     * String OPTION_MULTI = "multi";
-     * String OPTION_ID = "id";
-     * String OPTION_UPDATE = "update";
-     * String OPTION_RELEASES_UPDATE = "releasesUpdate";
-     * String OPTION_SNAPSHOTS_UPDATE = "snapshotsUpdate";
-     * String OPTION_CHECKSUM = "checksum";
-     * String OPTION_RELEASES_CHECKSUM = "releasesChecksum";
-     * String OPTION_SNAPSHOTS_CHECKSUM = "snapshotsChecksum";
-     */
+    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Show passwords related to Maven encryption", required = false, multiValued = false)
+    boolean showPasswords;
 
     @Override
     protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
         ShellTable table = new ShellTable();
-        table.column(new Col("Option").alignRight());
+        table.column("Option");
         table.column("Value");
         if (source) {
             table.column("Source");
@@ -87,26 +54,32 @@ public class SummaryCommand extends MavenConfigurationSupport {
             table.column("Description");
         }
 
-        addRow(table, "Local repository", localRepository,
+        addRow(table, propertyIds ? PROPERTY_LOCAL_REPOSITORY : "Local repository", localRepository,
                 "Maven repository to store artifacts resolved in *remote repositories*");
 
-        addRow(table, "Settings file", settings,
+        addRow(table, propertyIds ? PROPERTY_SETTINGS_FILE : "Settings file", settings,
                 "Settings file that may contain configuration of additional repositories, http proxies and mirrors");
 
-        addRow(table, "Security settings file", securitySettings,
+        addRow(table, propertyIds ? PROPERTY_SECURITY_FILE : "Security settings file", securitySettings,
                 "Settings file that contain (or relocates to) master Maven password");
 
+        if (showPasswords) {
+            decryptSettings();
+            addRow(table, propertyIds ? "<master>" : "Master password", new SourceAnd<String>(securitySettings.source, masterPassword),
+                    "Master password used to decrypt proxy and server passwords");
+        }
+
         // for default update/checksum policies specified at repository URI level, see
         // org.ops4j.pax.url.mvn.internal.AetherBasedResolver.addRepo()
 
         // see org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer#isUpdatedRequired()
         SourceAnd<String> updatePolicy = updatePolicy((String) config.get(prefix + PROPERTY_GLOBAL_UPDATE_POLICY));
-        addRow(table, "Global update policy", updatePolicy,
+        addRow(table, propertyIds ? PROPERTY_GLOBAL_UPDATE_POLICY : "Global update policy", updatePolicy,
                 "Overrides update policy specified at repository level (if specified)");
 
         // see org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider#newChecksumPolicy()
         SourceAnd<String> checksumPolicy = checksumPolicy((String) config.get(prefix + PROPERTY_GLOBAL_CHECKSUM_POLICY));
-        addRow(table, "Global checksum policy", checksumPolicy,
+        addRow(table, propertyIds ? PROPERTY_GLOBAL_CHECKSUM_POLICY : "Global checksum policy", checksumPolicy,
                 "Checksum policy for all repositories");
 
         String updateReleasesProperty = (String) config.get(prefix + PROPERTY_UPDATE_RELEASES);
@@ -117,7 +90,7 @@ public class SummaryCommand extends MavenConfigurationSupport {
         } else {
             updateReleases = "true".equals(updateReleasesProperty);
         }
-        addRow(table, "Update releases", new SourceAnd<Boolean>(sourceInfo, updateReleases),
+        addRow(table, propertyIds ? PROPERTY_UPDATE_RELEASES : "Update releases", new SourceAnd<Boolean>(sourceInfo, updateReleases),
                 "Whether to download non-SNAPSHOT artifacts according to update policy");
 
         // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.isValid()
@@ -128,7 +101,7 @@ public class SummaryCommand extends MavenConfigurationSupport {
         if (requireConfigAdmin) {
             sourceInfo = "BundleContext property (" + prefix + REQUIRE_CONFIG_ADMIN_CONFIG + ")";
         }
-        addRow(table, "Require Config Admin", new SourceAnd<Boolean>(sourceInfo, requireConfigAdmin),
+        addRow(table, propertyIds ? REQUIRE_CONFIG_ADMIN_CONFIG : "Require Config Admin", new SourceAnd<Boolean>(sourceInfo, requireConfigAdmin),
                 "Wheter MavenResolver service is registered ONLY with proper " + PID + " PID configuration");
 
         // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.buildSettings()
@@ -138,7 +111,7 @@ public class SummaryCommand extends MavenConfigurationSupport {
         if (useFallbackRepositoriesProperty != null) {
             sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_USE_FALLBACK_REPOSITORIES);
         }
-        addRow(table, "Use fallback repository", new SourceAnd<Boolean>(sourceInfo, useFallbackRepositories),
+        addRow(table, propertyIds ? PROPERTY_USE_FALLBACK_REPOSITORIES : "Use fallback repository", new SourceAnd<Boolean>(sourceInfo, useFallbackRepositories),
                 "Whether Maven Central is used as implicit, additional remote repository");
 
         // see org.ops4j.pax.url.mvn.internal.config.MavenConfigurationImpl.enableProxy()
@@ -151,7 +124,7 @@ public class SummaryCommand extends MavenConfigurationSupport {
         if (offlineProperty != null) {
             sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_OFFLINE);
         }
-        addRow(table, "Offline mode", new SourceAnd<Boolean>(sourceInfo, offline),
+        addRow(table, propertyIds ? PROPERTY_OFFLINE : "Offline mode", new SourceAnd<Boolean>(sourceInfo, offline),
                 "Disables access to external remote repositories (file:// based ones are still used)");
 
         // see org.ops4j.pax.url.mvn.internal.HttpClients.createConnManager()
@@ -161,10 +134,41 @@ public class SummaryCommand extends MavenConfigurationSupport {
         if (certificateCheckProperty != null) {
             sourceInfo = String.format(PATTERN_PID_PROPERTY, PID, prefix + PROPERTY_CERTIFICATE_CHECK);
         }
-        addRow(table, "SSL/TLS certificate check", new SourceAnd<Boolean>(sourceInfo, certificateCheck),
+        addRow(table, propertyIds ? PROPERTY_CERTIFICATE_CHECK : "SSL/TLS certificate check", new SourceAnd<Boolean>(sourceInfo, certificateCheck),
                 "Turns on server certificate validation for HTTPS remote repositories");
 
+        // repositories (short list)
+        MavenRepositoryURL[] remoteRepositories = repositories(config, true);
+        boolean first = true;
+        for (MavenRepositoryURL url : remoteRepositories) {
+            addRow(table, first ? (propertyIds ? PROPERTY_REPOSITORIES : "Remote repositories") : "", new SourceAnd<String>(url.getFrom().getSource(), url.getURL().toString()),
+                first ? "Remote repositories where artifacts are being resolved if not found locally" : "");
+            first = false;
+        }
+
+        // default repositories (short list)
+        MavenRepositoryURL[] defaultRepositories = repositories(config, false);
+        first = true;
+        for (MavenRepositoryURL url : defaultRepositories) {
+            addRow(table, first ? (propertyIds ? PROPERTY_DEFAULT_REPOSITORIES : "Default repositories") : "", new SourceAnd<String>(url.getFrom().getSource(), url.getURL().toString()),
+                    first ? "Repositories where artifacts are looked up before trying remote resolution" : "");
+            first = false;
+        }
+
+        // proxies (short list)
+        if (mavenSettings != null && mavenSettings.getProxies() != null) {
+            first = true;
+            for (Proxy proxy : mavenSettings.getProxies()) {
+                String value = String.format("%s:%s", proxy.getHost(), proxy.getPort());
+                addRow(table, first ? (propertyIds ? "<proxies>" : "HTTP proxies") : "", new SourceAnd<String>(MavenRepositoryURL.FROM.SETTINGS.getSource(), value),
+                        first ? "Maven HTTP proxies" : "");
+                first = false;
+            }
+        }
+
+        System.out.println();
         table.print(System.out);
+        System.out.println();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/karaf/blob/2dc56e46/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
index 858f85e..630976b 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/core/MavenRepositoryURL.java
@@ -33,9 +33,23 @@ import org.slf4j.LoggerFactory;
  * @author Alin Dreghiciu
  * @author Guillaume Nodet
  * @since 0.2.1, February 07, 2008
+ *
+ * @see org.ops4j.pax.url.mvn.internal.config.MavenRepositoryURL
  */
 public class MavenRepositoryURL
 {
+    /*
+     * String OPTION_ALLOW_SNAPSHOTS = "snapshots";
+     * String OPTION_DISALLOW_RELEASES = "noreleases";
+     * String OPTION_MULTI = "multi";
+     * String OPTION_ID = "id";
+     * String OPTION_UPDATE = "update";
+     * String OPTION_RELEASES_UPDATE = "releasesUpdate";
+     * String OPTION_SNAPSHOTS_UPDATE = "snapshotsUpdate";
+     * String OPTION_CHECKSUM = "checksum";
+     * String OPTION_RELEASES_CHECKSUM = "releasesChecksum";
+     * String OPTION_SNAPSHOTS_CHECKSUM = "snapshotsChecksum";
+     */
 
     private static final Logger LOG = LoggerFactory.getLogger( MavenRepositoryURL.class );
 
@@ -77,6 +91,10 @@ public class MavenRepositoryURL
     private final String m_snapshotsChecksumPolicy;
 
     private final boolean m_multi;
+    /**
+     * Where the repository was defined (PID or settings.xml)
+     */
+    private final FROM m_from;
 
     /**
      * Creates a maven repository URL bases on a string spec. The path can be marked with @snapshots and/or @noreleases
@@ -102,6 +120,7 @@ public class MavenRepositoryURL
         String checksum = null;
         String checksumReleases = null;
         String checksumSnapshots = null;
+        FROM from = null;
 
         for( int i = 0; i < segments.length; i++ )
         {
@@ -174,6 +193,13 @@ public class MavenRepositoryURL
                     LOG.warn( "Problem with segment " + segments[i] + " in " + repositorySpec );
                 }
             }
+            else if( segment.startsWith( "_from=" ) )
+            {
+                try {
+                    from = FROM.valueOf( segments[ i ].split( "=" )[1].trim() );
+                } catch (Exception ignored) {
+                }
+            }
             else
             {
                 if( i > 0 )
@@ -199,6 +225,8 @@ public class MavenRepositoryURL
         m_releasesChecksumPolicy = checksumReleases != null ? checksumReleases : checksum;
         m_snapshotsChecksumPolicy = checksumSnapshots != null ? checksumSnapshots : checksum;
 
+        m_from = from != null ? from : FROM.PID;
+
         if( m_repositoryURL.getProtocol().equals( "file" ) )
         {
             try
@@ -305,6 +333,10 @@ public class MavenRepositoryURL
         return m_snapshotsChecksumPolicy;
     }
 
+    public FROM getFrom() {
+        return m_from;
+    }
+
     /**
      * Getter.
      *
@@ -335,4 +367,20 @@ public class MavenRepositoryURL
             .toString();
     }
 
+    public static enum FROM {
+        PID("PID configuration"),
+        SETTINGS("Maven XML settings"),
+        FALLBACK("Fallback repository");
+
+        private String source;
+
+        FROM(String source) {
+            this.source = source;
+        }
+
+        public String getSource() {
+            return source;
+        }
+    }
+
 }


[09/12] karaf git commit: [KARAF-5008] maven:password command

Posted by gg...@apache.org.
[KARAF-5008] maven:password command


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

Branch: refs/heads/master-maven-commands
Commit: 420207bd697cdb5d91dae8e8c13720c702bef4b2
Parents: 045cb99
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Tue Jun 20 12:17:46 2017 +0200
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Tue Jun 20 12:18:23 2017 +0200

----------------------------------------------------------------------
 maven/core/pom.xml                              |   6 ++
 .../karaf/maven/command/HttpProxyCommand.java   |   2 +-
 .../command/MavenConfigurationSupport.java      |  60 ++++++++++-
 .../maven/command/MavenSecuritySupport.java     |  31 ++++++
 .../karaf/maven/command/PasswordCommand.java    | 103 +++++++++++++++++++
 .../command/RepositoryEditCommandSupport.java   |   2 +-
 .../maven/command/RepositoryListCommand.java    |   2 +-
 .../karaf/maven/command/SummaryCommand.java     |   2 +-
 .../org/apache/karaf/maven/SettingsTest.java    |   2 +
 .../command/MavenConfigurationSupportTest.java  |  60 +++++++++++
 maven/core/src/test/resources/log4j.properties  |  34 ++++++
 11 files changed, 295 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/pom.xml
----------------------------------------------------------------------
diff --git a/maven/core/pom.xml b/maven/core/pom.xml
index db2f2a7..a2a724f 100644
--- a/maven/core/pom.xml
+++ b/maven/core/pom.xml
@@ -66,6 +66,12 @@
             <artifactId>maven-embedder</artifactId>
             <version>3.0.3</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
index 6f8b794..129aca5 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
@@ -27,7 +27,7 @@ import org.apache.maven.settings.Proxy;
 
 @Command(scope = "maven", name = "http-proxy", description = "Manage HTTP proxy configuration for Maven remote repositories")
 @Service
-public class HttpProxyCommand extends MavenConfigurationSupport {
+public class HttpProxyCommand extends MavenSecuritySupport {
 
     @Option(name = "--add", description = "Adds HTTP proxy configuration to Maven settings", required = false, multiValued = false)
     boolean add;

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
index 4c3416a..0588afd 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenConfigurationSupport.java
@@ -17,10 +17,13 @@
 package org.apache.karaf.maven.command;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -28,10 +31,11 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
 
 import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Action;
-import org.apache.karaf.shell.api.action.Option;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.support.table.Row;
@@ -72,6 +76,12 @@ public abstract class MavenConfigurationSupport implements Action {
 
     protected static final String PATTERN_PID_PROPERTY = "Explicit %s PID configuration (%s)";
 
+    protected static final String PATTERN_SECURITY_SETTINGS = "maven-security-settings-%d.xml";
+    protected static final Pattern RE_SECURITY_SETTINGS = Pattern.compile("maven-security-settings-(\\d+)\\.xml");
+    protected static final String PATTERN_SETTINGS = "maven-settings-%d.xml";
+    protected static final Pattern RE_SETTINGS = Pattern.compile("maven-settings-(\\d+)\\.xml");
+    private static final int MAX_SEQUENCE_SIZE = 10;
+
     protected static final String PROPERTY_LOCAL_REPOSITORY = "localRepository";
     protected static final String PROPERTY_DEFAULT_REPOSITORIES = "defaultRepositories";
     protected static final String PROPERTY_REPOSITORIES = "repositories";
@@ -122,9 +132,6 @@ public abstract class MavenConfigurationSupport implements Action {
     @Reference
     protected Session session;
 
-    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Do not hide passwords related to Maven encryption", required = false, multiValued = false)
-    boolean showPasswords;
-
     @Override
     final public Object execute() throws Exception {
         Configuration c = cm.getConfiguration(PID);
@@ -144,7 +151,7 @@ public abstract class MavenConfigurationSupport implements Action {
 
                 localRepository = localRepository((String) c.getProperties().get(PID + "." + PROPERTY_LOCAL_REPOSITORY));
 
-                if (showPasswords) {
+                if (showPasswords()) {
                     decryptSettings();
                 }
 
@@ -558,6 +565,49 @@ public abstract class MavenConfigurationSupport implements Action {
         }
     }
 
+    /**
+     * Asks for confirmation (user has to press <code>y</code>) after presenting a prompt
+     * @param prompt
+     * @return
+     */
+    protected boolean confirm(String prompt) throws IOException {
+        String response = session.readLine(prompt, null);
+        return "y".equals(response);
+    }
+
+    /**
+     * Returns new {@link File} that's part of fixed-size sequence. Keeps the sequence bounded.
+     * @param dataDir
+     * @param pattern
+     * @param fileNameFormat
+     * @return
+     */
+    protected File nextSequenceFile(File dataDir, Pattern pattern, String fileNameFormat) {
+        File[] files = dataDir.listFiles((dir, name) -> pattern.matcher(name).matches());
+        File result = null;
+        if (files != null && files.length > 0) {
+            List<String> names = new ArrayList<>(Arrays.stream(files).map(File::getName)
+                    .collect(TreeSet<String>::new, TreeSet::add, TreeSet::addAll));
+
+            names.add(String.format(fileNameFormat, new Date().getTime()));
+
+            while (names.size() > MAX_SEQUENCE_SIZE) {
+                String name = names.remove(0);
+                new File(dataDir, name).delete();
+            }
+            result = new File(dataDir, names.get(names.size() - 1));
+        }
+        if (result == null) {
+            result = new File(dataDir, String.format(fileNameFormat, new Date().getTime()));
+        }
+
+        return result;
+    }
+
+    protected boolean showPasswords() {
+        return false;
+    }
+
     protected static class SourceAnd<T> {
         String source;
         T value;

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/MavenSecuritySupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/MavenSecuritySupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenSecuritySupport.java
new file mode 100644
index 0000000..6c46c9d
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/MavenSecuritySupport.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+import org.apache.karaf.shell.api.action.Option;
+
+public abstract class MavenSecuritySupport extends MavenConfigurationSupport {
+
+    @Option(name = "-x", aliases = { "--show-passwords" }, description = "Do not hide passwords related to Maven encryption", required = false, multiValued = false)
+    boolean showPasswords;
+
+    @Override
+    protected boolean showPasswords() {
+        return showPasswords;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
new file mode 100644
index 0000000..ed44b35
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/PasswordCommand.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.maven.command;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Dictionary;
+
+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.osgi.service.cm.Configuration;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
+import org.sonatype.plexus.components.sec.dispatcher.model.io.xpp3.SecurityConfigurationXpp3Writer;
+
+@Command(scope = "maven", name = "password", description = "Manage passwords for remote repositories and proxies")
+@Service
+public class PasswordCommand extends MavenConfigurationSupport {
+
+    @Option(name = "-ep", aliases = { "--encrypt-password" }, description = "Encrypts passwords to use for remote repositories and proxies, see \"mvn -ep\"", required = false, multiValued = false)
+    boolean ep;
+
+    @Option(name = "-emp", aliases = { "--encrypt-master-password" }, description = "Encrypts master password used to encrypt/decrypt other passwords, see \"mvn -emp\"", required = false, multiValued = false)
+    boolean emp;
+
+    @Option(name = "-p", aliases = { "--persist" }, description = "", required = false, multiValued = false)
+    boolean persist;
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        if (ep && emp) {
+            System.err.println("Please specify only one of --encrypt-password and --encrypt-master-password");
+            return;
+        }
+
+        if (ep && persist) {
+            System.err.println("Ordinary passwords are not persisted - use the encrypted password in either <proxy> or <server>");
+            return;
+        }
+
+        if (ep) {
+            // encrypt password using master password
+            if (masterPassword == null) {
+                System.err.println("Master password is not available");
+                return;
+            }
+            String password = session.readLine("Password to encrypt: ", '*');
+            System.out.println("Encrypted password: " + cipher.encryptAndDecorate(password, masterPassword));
+            return;
+        }
+
+        if (emp) {
+            if (persist && !confirm("Maven security settings will be stored in new file. This file will be used in org.ops4j.pax.url.mvn.security property. Continue? (y/N) ")) {
+                return;
+            }
+
+            // encrypt master password using DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION
+            String password = session.readLine("Master password to encrypt: ", '*');
+            String encryptedPassword = cipher.encryptAndDecorate(password, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION);
+            System.out.println("Encrypted master password: " + encryptedPassword);
+            if (persist) {
+                SettingsSecurity settingsSecurity = new SettingsSecurity();
+                settingsSecurity.setMaster(encryptedPassword);
+                File dataDir = context.getDataFile(".");
+                if (!dataDir.isDirectory()) {
+                    System.err.println("Can't access data directory for " + context.getBundle().getSymbolicName() + " bundle");
+                }
+                File newSecuritySettingsFile = nextSequenceFile(dataDir, RE_SECURITY_SETTINGS, PATTERN_SECURITY_SETTINGS);
+                try (FileWriter fw = new FileWriter(newSecuritySettingsFile)) {
+                    new SecurityConfigurationXpp3Writer().write(fw, settingsSecurity);
+                }
+
+                System.out.println("New security settings stored in \"" + newSecuritySettingsFile.getCanonicalPath() + "\"");
+
+                Configuration cmConfig = cm.getConfiguration(PID);
+                config.put(prefix + PROPERTY_SECURITY_FILE, newSecuritySettingsFile.getCanonicalPath());
+                cmConfig.update(config);
+            }
+            return;
+        }
+    }
+
+    @Override
+    protected boolean showPasswords() {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
index 0179b02..12700d0 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryEditCommandSupport.java
@@ -21,7 +21,7 @@ import java.util.Dictionary;
 import org.apache.karaf.maven.core.MavenRepositoryURL;
 import org.apache.karaf.shell.api.action.Option;
 
-public abstract class RepositoryEditCommandSupport extends MavenConfigurationSupport {
+public abstract class RepositoryEditCommandSupport extends MavenSecuritySupport {
 
     @Override
     public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
index 90c7c26..ddc2ea5 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/RepositoryListCommand.java
@@ -28,7 +28,7 @@ import org.apache.maven.settings.Server;
 
 @Command(scope = "maven", name = "repository-list", description = "Maven repository summary.")
 @Service
-public class RepositoryListCommand extends MavenConfigurationSupport {
+public class RepositoryListCommand extends MavenSecuritySupport {
 
     @Option(name = "-v", aliases = { "--verbose" }, description = "Show additional information (policies, source)", required = false, multiValued = false)
     boolean verbose;

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
index 1678239..3f7e91a 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/SummaryCommand.java
@@ -28,7 +28,7 @@ import org.apache.maven.settings.Proxy;
 
 @Command(scope = "maven", name = "summary", description = "Maven configuration summary.")
 @Service
-public class SummaryCommand extends MavenConfigurationSupport {
+public class SummaryCommand extends MavenSecuritySupport {
 
     @Option(name = "-p", aliases = { "--property-ids" }, description = "Use PID property identifiers instead of their names", required = false, multiValued = false)
     boolean propertyIds;

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
index b0d9110..3ecaf30 100644
--- a/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
+++ b/maven/core/src/test/java/org/apache/karaf/maven/SettingsTest.java
@@ -53,9 +53,11 @@ public class SettingsTest {
         // non-master password ('mvn -ep admin')
         DefaultPlexusCipher plexusCipher = new DefaultPlexusCipher();
         System.out.println(plexusCipher.decrypt("{EhjazkVpkMoHjAgaUKX+UxeXn9lsJGHst2uFKmhNZ8U=}", "admin"));
+        System.out.println(plexusCipher.decrypt("{oWE12FbirwYHNit93TAMA+OC/GJge2r9FuzI8kOuHlA=}", "settings.security"));
 
         // master password (`mvn -emp admin`)
         PBECipher cipher = new PBECipher();
+        System.out.println(cipher.decrypt64("EhjazkVpkMoHjAgaUKX+UxeXn9lsJGHst2uFKmhNZ8U=","admin"));
         System.out.println(cipher.decrypt64("oWE12FbirwYHNit93TAMA+OC/GJge2r9FuzI8kOuHlA=","settings.security"));
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
----------------------------------------------------------------------
diff --git a/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java b/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
new file mode 100644
index 0000000..16ffc3f
--- /dev/null
+++ b/maven/core/src/test/java/org/apache/karaf/maven/command/MavenConfigurationSupportTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.maven.command;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+import shaded.org.apache.commons.io.FileUtils;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class MavenConfigurationSupportTest {
+
+    @Test
+    public void sequenceFiles() throws IOException {
+        File dataDir = new File("target/data");
+        FileUtils.deleteDirectory(dataDir);
+        dataDir.mkdirs();
+
+        MavenConfigurationSupport support = new MavenConfigurationSupport() {
+            @Override
+            protected void doAction(String prefix, Dictionary<String, Object> config) throws Exception { }
+        };
+
+        File newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
+        assertThat(newFile.getName(), equalTo("file-0001.txt"));
+
+        try (FileWriter fw = new FileWriter(new File(dataDir, "file-abcd.txt"))) {
+            fw.write("~");
+        }
+        newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
+        assertThat(newFile.getName(), equalTo("file-0001.txt"));
+
+        try (FileWriter fw = new FileWriter(new File(dataDir, "file-0004.txt"))) {
+            fw.write("~");
+        }
+        newFile = support.nextSequenceFile(dataDir, Pattern.compile("file-(\\d+).txt"), "file-%04d.txt");
+        assertThat(newFile.getName(), equalTo("file-0005.txt"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/420207bd/maven/core/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/maven/core/src/test/resources/log4j.properties b/maven/core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..e1cbdd1
--- /dev/null
+++ b/maven/core/src/test/resources/log4j.properties
@@ -0,0 +1,34 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=DEBUG, console, file
+
+# Console will only display warnnings
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %-32.32C %4L | %m%n
+#log4j.appender.console.threshold=WARN
+
+# File appender will contain all info messages
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n
+log4j.appender.file.file=target/test.log
+log4j.appender.file.append=true


[12/12] karaf git commit: [KARAF-5008] maven:http-proxy and maven:http-proxy-list commands

Posted by gg...@apache.org.
[KARAF-5008] maven:http-proxy and maven:http-proxy-list commands


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

Branch: refs/heads/master-maven-commands
Commit: e517bad1a274ed3c5fba8cec9663b002a5da591d
Parents: df8f292
Author: Grzegorz Grzybek <gr...@gmail.com>
Authored: Wed Jun 21 15:26:45 2017 +0200
Committer: Grzegorz Grzybek <gr...@gmail.com>
Committed: Wed Jun 21 15:26:45 2017 +0200

----------------------------------------------------------------------
 .../karaf/maven/command/HttpProxyCommand.java   | 126 ++++++++++++++-----
 .../maven/command/HttpProxyListCommand.java     |  70 +++++++++++
 .../src/test/resources/reference-settings.xml   |   1 +
 3 files changed, 168 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/e517bad1/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
index 129aca5..d7a3bfa 100644
--- a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyCommand.java
@@ -17,13 +17,17 @@
 package org.apache.karaf.maven.command;
 
 import java.util.Dictionary;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
+import org.apache.karaf.shell.api.action.Argument;
 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.Row;
-import org.apache.karaf.shell.support.table.ShellTable;
 import org.apache.maven.settings.Proxy;
+import org.osgi.service.cm.Configuration;
 
 @Command(scope = "maven", name = "http-proxy", description = "Manage HTTP proxy configuration for Maven remote repositories")
 @Service
@@ -32,53 +36,117 @@ public class HttpProxyCommand extends MavenSecuritySupport {
     @Option(name = "--add", description = "Adds HTTP proxy configuration to Maven settings", required = false, multiValued = false)
     boolean add;
 
+    @Option(name = "--change", description = "Changes HTTP proxy configuration in Maven settings", required = false, multiValued = false)
+    boolean change;
+
     @Option(name = "--remove", description = "Removes HTTP proxy configuration from Maven settings", required = false, multiValued = false)
     boolean remove;
 
+    @Option(name = "-id", description = "Identifier of HTTP proxy", required = true, multiValued = false)
+    String id;
+
+    @Option(name = "-f", aliases = { "--force" }, description = "Do not ask for confirmation", required = false, multiValued = false)
+    boolean force = false;
+
+    @Option(name = "-u", aliases = { "--username" }, description = "Username for remote repository", required = false, multiValued = false)
+    String username;
+
+    @Option(name = "-p", aliases = { "--password" }, description = "Password for remote repository (may be encrypted, see \"maven:password -ep\")", required = false, multiValued = false)
+    String password;
+
+    @Option(name = "-n", aliases = { "--non-proxy-hosts" }, description = "Non-proxied hosts (in the format '192.168.*|localhost|...')", required = false, multiValued = false)
+    String nonProxyHosts;
+
+    @Argument(description = "host:port of HTTP proxy", required = false, multiValued = false)
+    String hostPort;
+
     @Override
     public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
-        if (add && remove) {
-            System.err.println("Please specify only one of --add and --remove");
+        if (add && (change || remove) || change && remove) {
+            System.err.println("Please specify only one of --add/--change/--remove");
             return;
         }
 
+        if (id == null || "".equals(id.trim())) {
+            System.err.println("Please specify ID of HTTP proxy");
+            return;
+        }
+
+        if (mavenSettings.getProxies() == null) {
+            mavenSettings.setProxies(new LinkedList<>());
+        }
+        Optional<Proxy> existingProxy = mavenSettings.getProxies().stream()
+                .filter((p) -> id.equals(p.getId())).findAny();
+
         if (add) {
-            // add
+            if (hostPort == null || "".equals(hostPort.trim())) {
+                System.err.println("Please specify host:port of new HTTP proxy");
+                return;
+            }
+            if (existingProxy.isPresent()) {
+                System.err.printf("HTTP proxy with ID \"%s\" is already configured\n", id);
+                return;
+            }
+        } else if (!existingProxy.isPresent()) {
+            System.err.printf("Can't find HTTP proxy with ID \"%s\"\n", id);
+            return;
         }
 
-        if (remove) {
+        boolean hasUsername = username != null && !"".equals(username.trim());
+        boolean hasPassword = password != null && !"".equals(password.trim());
+        boolean hasCredentials = hasUsername && hasPassword;
+
+        if ((hasUsername && !hasPassword) || (!hasUsername && hasPassword)) {
+            System.err.println("Please specify both username and password");
+            return;
+        }
+
+        Proxy proxy = null;
+        if (add) {
+            proxy = new Proxy();
+            proxy.setId(id);
+            mavenSettings.getProxies().add(proxy);
+        } else if (change) {
+            proxy = existingProxy.get(); // should be there
+        } else /*if (remove)*/ {
             // remove
+            List<Proxy> newProxies = mavenSettings.getProxies().stream()
+                    .filter((p) -> !id.equals(p.getId())).collect(Collectors.toList());
+            mavenSettings.setProxies(newProxies);
         }
 
-        // list (also after --add or --remove)
-        System.out.println();
-        if (mavenSettings != null && mavenSettings.getProxies() != null && mavenSettings.getProxies().size() > 0) {
-            ShellTable table = new ShellTable();
-            table.column("ID");
-            table.column("Host");
-            table.column("Port");
-            table.column("Username");
-            if (showPasswords) {
-                table.column("Password");
+        if (add || change) {
+            proxy.setActive(true);
+            proxy.setProtocol("http");
+            if (nonProxyHosts != null && !"".equals(nonProxyHosts.trim())) {
+                proxy.setNonProxyHosts(nonProxyHosts);
             }
-            for (Proxy proxy : mavenSettings.getProxies()) {
-                Row row = table.addRow();
-                row.addContent(proxy.getId(), proxy.getHost(), proxy.getPort());
-                row.addContent(proxy.getUsername() != null ? proxy.getUsername() : "");
-                if (showPasswords) {
-                    addPasswordInfo(row, proxyPasswords, proxy.getId(), proxy.getPassword());
+            if (hostPort != null && !"".equals(hostPort.trim())) {
+                if (hostPort.contains(":")) {
+                    proxy.setHost(hostPort.substring(0, hostPort.indexOf(':')));
+                    proxy.setPort(Integer.parseInt(hostPort.substring(hostPort.indexOf(':') + 1)));
+                } else {
+                    proxy.setHost(hostPort);
+                    proxy.setPort(3128);
                 }
             }
-            table.print(System.out);
-        } else {
-            System.out.print("No HTTP proxies configured");
-            if (settings != null && settings.value != null) {
-                System.out.print(" in " + settings.value);
+            if (hasCredentials) {
+                proxy.setUsername(username);
+                proxy.setPassword(password);
             }
-            System.out.println();
         }
 
-        System.out.println();
+        updateSettings(prefix, config);
+
+        Configuration cmConfig = cm.getConfiguration(PID);
+        cmConfig.update(config);
+
+        // list (also after --add or --remove)
+        if (showPasswords) {
+            session.execute("maven:http-proxy-list -x");
+        } else {
+            session.execute("maven:http-proxy-list");
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/e517bad1/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyListCommand.java
----------------------------------------------------------------------
diff --git a/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyListCommand.java b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyListCommand.java
new file mode 100644
index 0000000..799b0da
--- /dev/null
+++ b/maven/core/src/main/java/org/apache/karaf/maven/command/HttpProxyListCommand.java
@@ -0,0 +1,70 @@
+/*
+ * 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.maven.command;
+
+import java.util.Dictionary;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.karaf.shell.api.action.Argument;
+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.Row;
+import org.apache.karaf.shell.support.table.ShellTable;
+import org.apache.maven.settings.Proxy;
+
+@Command(scope = "maven", name = "http-proxy-list", description = "Lists HTTP proxy configurations for Maven remote repositories")
+@Service
+public class HttpProxyListCommand extends MavenSecuritySupport {
+
+    @Override
+    public void doAction(String prefix, Dictionary<String, Object> config) throws Exception {
+        System.out.println();
+        if (mavenSettings != null && mavenSettings.getProxies() != null && mavenSettings.getProxies().size() > 0) {
+            ShellTable table = new ShellTable();
+            table.column("ID");
+            table.column("Host");
+            table.column("Port");
+            table.column("Non-proxy hosts");
+            table.column("Username");
+            if (showPasswords) {
+                table.column("Password");
+            }
+            for (Proxy _p : mavenSettings.getProxies()) {
+                Row row = table.addRow();
+                row.addContent(_p.getId(), _p.getHost(), _p.getPort(), _p.getNonProxyHosts());
+                row.addContent(_p.getUsername() != null ? _p.getUsername() : "");
+                if (showPasswords) {
+                    addPasswordInfo(row, proxyPasswords, _p.getId(), _p.getPassword());
+                }
+            }
+            table.print(System.out);
+        } else {
+            System.out.print("No HTTP proxies configured");
+            if (settings != null && settings.value != null) {
+                System.out.print(" in " + settings.value);
+            }
+            System.out.println();
+        }
+
+        System.out.println();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e517bad1/maven/core/src/test/resources/reference-settings.xml
----------------------------------------------------------------------
diff --git a/maven/core/src/test/resources/reference-settings.xml b/maven/core/src/test/resources/reference-settings.xml
index 25b58fb..979ab11 100644
--- a/maven/core/src/test/resources/reference-settings.xml
+++ b/maven/core/src/test/resources/reference-settings.xml
@@ -29,6 +29,7 @@
             <protocol>http</protocol>
             <username>username</username>
             <password>password</password>
+            <nonProxyHosts></nonProxyHosts>
         </proxy>
     </proxies>