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/22 11:15:37 UTC

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

[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/32d5c7b7
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/32d5c7b7
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/32d5c7b7

Branch: refs/heads/master
Commit: 32d5c7b769b570824cc50917a78c103ddbfa1e6c
Parents: ede23ba
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 15:31:54 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/32d5c7b7/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/32d5c7b7/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/32d5c7b7/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/32d5c7b7/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/32d5c7b7/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/32d5c7b7/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);
             }