You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by pe...@apache.org on 2021/01/26 11:24:10 UTC

[pulsar] branch branch-2.7 updated: Keep topic-level policies commands consistent with that for namespace… (#9215)

This is an automated email from the ASF dual-hosted git repository.

penghui pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/pulsar.git


The following commit(s) were added to refs/heads/branch-2.7 by this push:
     new 4fc2e07  Keep topic-level policies commands consistent with that for namespace… (#9215)
4fc2e07 is described below

commit 4fc2e077ce0f4bac14b0d4ae06313e1ec5d1614b
Author: feynmanlin <fe...@tencent.com>
AuthorDate: Tue Jan 26 15:15:40 2021 +0800

    Keep topic-level policies commands consistent with that for namespace… (#9215)
    
    Fixes #9205
    In #9108, we add some topic-level policies commands, and found some commands are not consistent with that for namespace-level.
    For example,
    On namespace-level, the policies commands are:
    ```
    get-max-producers
    set-max-producers
    remove-max-producers
    get-max-unacked-messages-per-subscription
    set-max-unacked-messages-per-subscription
    remove-max-unacked-messages-per-subscription
    ```
    On topic-level, the polices commands are:
    ```
    get-maxProducers
    set-maxProducers
    remove-maxProducers
    get-max-unacked-messages-on-subscription
    set-max-unacked-messages-on-subscription
    remove-max-unacked-messages-on-subscription
    ```
    
    Keep topic-level policies commands consistent with that for namespace
    
    (cherry picked from commit d557e0aa286866363bc6261dec87790c055db1b0)
---
 .../pulsar/admin/cli/DeprecatedCommanderTest.java  | 85 +++++++++++++++++++++
 .../pulsar/admin/cli/PulsarAdminToolTest.java      | 31 ++++++++
 .../java/org/apache/pulsar/admin/cli/CmdBase.java  |  3 +-
 .../org/apache/pulsar/admin/cli/CmdTopics.java     | 68 ++++++++++++++++-
 .../apache/pulsar/admin/cli/CmdUsageFormatter.java | 89 ++++++++++++++++++++++
 5 files changed, 274 insertions(+), 2 deletions(-)

diff --git a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/DeprecatedCommanderTest.java b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/DeprecatedCommanderTest.java
new file mode 100644
index 0000000..0a68a5f
--- /dev/null
+++ b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/DeprecatedCommanderTest.java
@@ -0,0 +1,85 @@
+/**
+ * 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.pulsar.admin.cli;
+
+
+import com.beust.jcommander.DefaultUsageFormatter;
+import org.apache.pulsar.client.admin.PulsarAdmin;
+import org.apache.pulsar.client.admin.Schemas;
+import org.apache.pulsar.client.admin.Topics;
+import org.mockito.Mockito;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+public class DeprecatedCommanderTest {
+    PulsarAdmin admin;
+    Topics mockTopics;
+    Schemas mockSchemas;
+    CmdTopics cmdTopics;
+
+    @BeforeMethod
+    public void setup() {
+        admin = Mockito.mock(PulsarAdmin.class);
+        mockTopics = mock(Topics.class);
+        when(admin.topics()).thenReturn(mockTopics);
+        mockSchemas = mock(Schemas.class);
+        when(admin.schemas()).thenReturn(mockSchemas);
+        cmdTopics = new CmdTopics(admin);
+    }
+
+    @Test
+    public void testDeprecatedCommanderWorks() throws Exception {
+
+        DefaultUsageFormatter defaultUsageFormatter = new DefaultUsageFormatter(cmdTopics.jcommander);
+        StringBuilder builder = new StringBuilder();
+        defaultUsageFormatter.usage(builder);
+        String defaultOutput = builder.toString();
+
+        StringBuilder builder2 = new StringBuilder();
+        cmdTopics.jcommander.getUsageFormatter().usage(builder2);
+        String outputWithFiltered = builder2.toString();
+
+        assertNotEquals(outputWithFiltered, defaultOutput);
+        assertFalse(outputWithFiltered.contains("enable-deduplication"));
+        assertTrue(defaultOutput.contains("enable-deduplication"));
+        assertFalse(outputWithFiltered.contains("get-max-unacked-messages-on-consumer"));
+        assertTrue(defaultOutput.contains("get-max-unacked-messages-on-consumer"));
+        assertTrue(outputWithFiltered.contains("get-deduplication"));
+        assertTrue(defaultOutput.contains("get-deduplication"));
+
+        // annotation was changed to hidden, reset it.
+        cmdTopics = new CmdTopics(admin);
+        CmdUsageFormatter formatter = (CmdUsageFormatter)cmdTopics.jcommander.getUsageFormatter();
+        formatter.clearDeprecatedCommand();
+        StringBuilder builder3 = new StringBuilder();
+        cmdTopics.jcommander.getUsageFormatter().usage(builder3);
+        String outputAfterClean = builder3.toString();
+
+        assertEquals(outputAfterClean, defaultOutput);
+
+    }
+
+}
diff --git a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
index bdd46e6..55dfdfd 100644
--- a/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
+++ b/pulsar-client-tools-test/src/test/java/org/apache/pulsar/admin/cli/PulsarAdminToolTest.java
@@ -760,8 +760,13 @@ public class PulsarAdminToolTest {
         cmdTopics.run(split("disable-deduplication persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).enableDeduplication("persistent://myprop/clust/ns1/ds1", false);
 
+        cmdTopics.run(split("set-deduplication persistent://myprop/clust/ns1/ds1 --disable"));
+        verify(mockTopics, times(2)).enableDeduplication("persistent://myprop/clust/ns1/ds1", false);
+
         cmdTopics.run(split("get-deduplication-enabled persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getDeduplicationEnabled("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("get-deduplication persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics, times(2)).getDeduplicationEnabled("persistent://myprop/clust/ns1/ds1");
 
         cmdTopics.run(split("get-offload-policies persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getOffloadPolicies("persistent://myprop/clust/ns1/ds1");
@@ -776,17 +781,29 @@ public class PulsarAdminToolTest {
 
         cmdTopics.run(split("get-max-unacked-messages-on-consumer persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("get-max-unacked-messages-per-consumer persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics, times(2)).getMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1");
         cmdTopics.run(split("remove-max-unacked-messages-on-consumer persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).removeMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("remove-max-unacked-messages-per-consumer persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics, times(2)).removeMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1");
         cmdTopics.run(split("set-max-unacked-messages-on-consumer persistent://myprop/clust/ns1/ds1 -m 999"));
         verify(mockTopics).setMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1", 999);
+        cmdTopics.run(split("set-max-unacked-messages-per-consumer persistent://myprop/clust/ns1/ds1 -m 999"));
+        verify(mockTopics, times(2)).setMaxUnackedMessagesOnConsumer("persistent://myprop/clust/ns1/ds1", 999);
 
         cmdTopics.run(split("get-max-unacked-messages-on-subscription persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("get-max-unacked-messages-per-subscription persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics, times(2)).getMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1");
         cmdTopics.run(split("remove-max-unacked-messages-on-subscription persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).removeMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("remove-max-unacked-messages-per-subscription persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics, times(2)).removeMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1");
         cmdTopics.run(split("set-max-unacked-messages-on-subscription persistent://myprop/clust/ns1/ds1 -m 99"));
         verify(mockTopics).setMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1", 99);
+        cmdTopics.run(split("set-max-unacked-messages-per-subscription persistent://myprop/clust/ns1/ds1 -m 99"));
+        verify(mockTopics, times(2)).setMaxUnackedMessagesOnSubscription("persistent://myprop/clust/ns1/ds1", 99);
 
         cmdTopics.run(split("get-max-message-size persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getMaxMessageSize("persistent://myprop/clust/ns1/ds1");
@@ -795,6 +812,20 @@ public class PulsarAdminToolTest {
         cmdTopics.run(split("set-max-message-size persistent://myprop/clust/ns1/ds1 -m 99"));
         verify(mockTopics).setMaxMessageSize("persistent://myprop/clust/ns1/ds1", 99);
 
+        cmdTopics.run(split("get-max-producers persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics).getMaxProducers("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("remove-max-producers persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics).removeMaxProducers("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("set-max-producers persistent://myprop/clust/ns1/ds1 -p 99"));
+        verify(mockTopics).setMaxProducers("persistent://myprop/clust/ns1/ds1", 99);
+
+        cmdTopics.run(split("get-max-consumers persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics).getMaxConsumers("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("remove-max-consumers persistent://myprop/clust/ns1/ds1"));
+        verify(mockTopics).removeMaxConsumers("persistent://myprop/clust/ns1/ds1");
+        cmdTopics.run(split("set-max-consumers persistent://myprop/clust/ns1/ds1 -c 99"));
+        verify(mockTopics).setMaxConsumers("persistent://myprop/clust/ns1/ds1", 99);
+
         cmdTopics.run(split("get-deduplication-snapshot-interval persistent://myprop/clust/ns1/ds1"));
         verify(mockTopics).getDeduplicationSnapshotInterval("persistent://myprop/clust/ns1/ds1");
         cmdTopics.run(split("remove-deduplication-snapshot-interval persistent://myprop/clust/ns1/ds1"));
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBase.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBase.java
index a14388b..4a4e949 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBase.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdBase.java
@@ -39,8 +39,9 @@ public abstract class CmdBase {
     public CmdBase(String cmdName, PulsarAdmin admin) {
         this.admin = admin;
         jcommander = new JCommander();
-        usageFormatter = new DefaultUsageFormatter(jcommander);
+        usageFormatter = new CmdUsageFormatter(jcommander);
         jcommander.setProgramName("pulsar-admin " + cmdName);
+        jcommander.setUsageFormatter(usageFormatter);
     }
 
     private void tryShowCommandUsage() {
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java
index 4519568..b1c3cd2 100644
--- a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdTopics.java
@@ -20,6 +20,7 @@ package org.apache.pulsar.admin.cli;
 
 import static org.apache.commons.lang3.StringUtils.isNotBlank;
 
+import com.beust.jcommander.IUsageFormatter;
 import com.beust.jcommander.Parameter;
 import com.beust.jcommander.ParameterException;
 import com.beust.jcommander.Parameters;
@@ -121,11 +122,14 @@ public class CmdTopics extends CmdBase {
         jcommander.addCommand("get-retention", new GetRetention());
         jcommander.addCommand("set-retention", new SetRetention());
         jcommander.addCommand("remove-retention", new RemoveRetention());
-
+        //deprecated commands
         jcommander.addCommand("enable-deduplication", new EnableDeduplication());
         jcommander.addCommand("disable-deduplication", new DisableDeduplication());
         jcommander.addCommand("get-deduplication-enabled", new GetDeduplicationEnabled());
 
+        jcommander.addCommand("set-deduplication", new SetDeduplication());
+        jcommander.addCommand("get-deduplication", new GetDeduplicationEnabled());
+
         jcommander.addCommand("get-deduplication-snapshot-interval", new GetDeduplicationSnapshotInterval());
         jcommander.addCommand("set-deduplication-snapshot-interval", new SetDeduplicationSnapshotInterval());
         jcommander.addCommand("remove-deduplication-snapshot-interval", new RemoveDeduplicationSnapshotInterval());
@@ -151,20 +155,34 @@ public class CmdTopics extends CmdBase {
         jcommander.addCommand("get-compaction-threshold", new GetCompactionThreshold());
         jcommander.addCommand("set-compaction-threshold", new SetCompactionThreshold());
         jcommander.addCommand("remove-compaction-threshold", new RemoveCompactionThreshold());
+
+        //deprecated commands
         jcommander.addCommand("get-max-unacked-messages-on-consumer", new GetMaxUnackedMessagesOnConsumer());
         jcommander.addCommand("set-max-unacked-messages-on-consumer", new SetMaxUnackedMessagesOnConsumer());
         jcommander.addCommand("remove-max-unacked-messages-on-consumer", new RemoveMaxUnackedMessagesOnConsumer());
         jcommander.addCommand("get-max-unacked-messages-on-subscription", new GetMaxUnackedMessagesOnSubscription());
         jcommander.addCommand("set-max-unacked-messages-on-subscription", new SetMaxUnackedMessagesOnSubscription());
         jcommander.addCommand("remove-max-unacked-messages-on-subscription", new RemoveMaxUnackedMessagesOnSubscription());
+
+        jcommander.addCommand("get-max-unacked-messages-per-consumer", new GetMaxUnackedMessagesOnConsumer());
+        jcommander.addCommand("set-max-unacked-messages-per-consumer", new SetMaxUnackedMessagesOnConsumer());
+        jcommander.addCommand("remove-max-unacked-messages-per-consumer", new RemoveMaxUnackedMessagesOnConsumer());
+        jcommander.addCommand("get-max-unacked-messages-per-subscription", new GetMaxUnackedMessagesOnSubscription());
+        jcommander.addCommand("set-max-unacked-messages-per-subscription", new SetMaxUnackedMessagesOnSubscription());
+        jcommander.addCommand("remove-max-unacked-messages-per-subscription", new RemoveMaxUnackedMessagesOnSubscription());
         jcommander.addCommand("get-publish-rate", new GetPublishRate());
         jcommander.addCommand("set-publish-rate", new SetPublishRate());
         jcommander.addCommand("remove-publish-rate", new RemovePublishRate());
 
+        //deprecated commands
         jcommander.addCommand("get-maxProducers", new GetMaxProducers());
         jcommander.addCommand("set-maxProducers", new SetMaxProducers());
         jcommander.addCommand("remove-maxProducers", new RemoveMaxProducers());
 
+        jcommander.addCommand("get-max-producers", new GetMaxProducers());
+        jcommander.addCommand("set-max-producers", new SetMaxProducers());
+        jcommander.addCommand("remove-max-producers", new RemoveMaxProducers());
+
         jcommander.addCommand("get-max-message-size", new GetMaxMessageSize());
         jcommander.addCommand("set-max-message-size", new SetMaxMessageSize());
         jcommander.addCommand("remove-max-message-size", new RemoveMaxMessageSize());
@@ -184,6 +202,30 @@ public class CmdTopics extends CmdBase {
         jcommander.addCommand("get-subscribe-rate", new GetSubscribeRate());
         jcommander.addCommand("set-subscribe-rate", new SetSubscribeRate());
         jcommander.addCommand("remove-subscribe-rate", new RemoveSubscribeRate());
+
+        initDeprecatedCommands();
+    }
+
+    private void initDeprecatedCommands() {
+        IUsageFormatter usageFormatter = jcommander.getUsageFormatter();
+        if (usageFormatter instanceof CmdUsageFormatter) {
+            CmdUsageFormatter cmdUsageFormatter = (CmdUsageFormatter) usageFormatter;
+            cmdUsageFormatter.addDeprecatedCommand("enable-deduplication");
+            cmdUsageFormatter.addDeprecatedCommand("disable-deduplication");
+            cmdUsageFormatter.addDeprecatedCommand("get-deduplication-enabled");
+
+            cmdUsageFormatter.addDeprecatedCommand("get-max-unacked-messages-on-consumer");
+            cmdUsageFormatter.addDeprecatedCommand("remove-max-unacked-messages-on-consumer");
+            cmdUsageFormatter.addDeprecatedCommand("set-max-unacked-messages-on-consumer");
+
+            cmdUsageFormatter.addDeprecatedCommand("get-max-unacked-messages-on-subscription");
+            cmdUsageFormatter.addDeprecatedCommand("remove-max-unacked-messages-on-subscription");
+            cmdUsageFormatter.addDeprecatedCommand("set-max-unacked-messages-on-subscription");
+
+            cmdUsageFormatter.addDeprecatedCommand("get-maxProducers");
+            cmdUsageFormatter.addDeprecatedCommand("set-maxProducers");
+            cmdUsageFormatter.addDeprecatedCommand("remove-maxProducers");
+        }
     }
 
     @Parameters(commandDescription = "Get the list of topics under a namespace.")
@@ -1208,6 +1250,7 @@ public class CmdTopics extends CmdBase {
         }
     }
 
+    @Deprecated
     @Parameters(commandDescription = "Enable the deduplication policy for a topic")
     private class EnableDeduplication extends CliCommand {
         @Parameter(description = "persistent://tenant/namespace/topic", required = true)
@@ -1220,6 +1263,7 @@ public class CmdTopics extends CmdBase {
         }
     }
 
+    @Deprecated
     @Parameters(commandDescription = "Disable the deduplication policy for a topic")
     private class DisableDeduplication extends CliCommand {
         @Parameter(description = "persistent://tenant/namespace/topic", required = true)
@@ -1232,6 +1276,28 @@ public class CmdTopics extends CmdBase {
         }
     }
 
+    @Parameters(commandDescription = "Enable or disable deduplication for a topic")
+    private class SetDeduplication extends CliCommand {
+        @Parameter(description = "persistent://tenant/namespace/topic", required = true)
+        private java.util.List<String> params;
+
+        @Parameter(names = { "--enable", "-e" }, description = "Enable deduplication")
+        private boolean enable = false;
+
+        @Parameter(names = { "--disable", "-d" }, description = "Disable deduplication")
+        private boolean disable = false;
+
+        @Override
+        void run() throws PulsarAdminException {
+            String persistentTopic = validatePersistentTopic(params);
+
+            if (enable == disable) {
+                throw new ParameterException("Need to specify either --enable or --disable");
+            }
+            admin.topics().enableDeduplication(persistentTopic, enable);
+        }
+    }
+
     @Parameters(commandDescription = "Get the deduplication policy for a topic")
     private class GetDeduplicationEnabled extends CliCommand {
         @Parameter(description = "persistent://tenant/namespace/topic", required = true)
diff --git a/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdUsageFormatter.java b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdUsageFormatter.java
new file mode 100644
index 0000000..edf16fd
--- /dev/null
+++ b/pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdUsageFormatter.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pulsar.admin.cli;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.beust.jcommander.DefaultUsageFormatter;
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameters;
+
+public class CmdUsageFormatter extends DefaultUsageFormatter {
+
+    /**
+     * The commands in this set are hidden and not shown to users
+     */
+    private Set<String> deprecatedCommands = new HashSet<>();
+
+    private final JCommander commander;
+
+    public CmdUsageFormatter(JCommander commander) {
+        super(commander);
+        this.commander = commander;
+    }
+
+    /**
+     * This method is copied from DefaultUsageFormatter,
+     * but the ability to skip deprecated commands is added.
+     * @param out
+     * @param indentCount
+     * @param descriptionIndent
+     * @param indent
+     */
+    @Override
+    public void appendCommands(StringBuilder out, int indentCount, int descriptionIndent, String indent) {
+        out.append(indent + "  Commands:\n");
+
+        for (Map.Entry<JCommander.ProgramName, JCommander> commands : commander.getRawCommands().entrySet()) {
+            Object arg = commands.getValue().getObjects().get(0);
+            Parameters p = arg.getClass().getAnnotation(Parameters.class);
+
+            if (p == null || !p.hidden()) {
+                JCommander.ProgramName progName = commands.getKey();
+                String dispName = progName.getDisplayName();
+                //skip the deprecated command
+                if(deprecatedCommands.contains(dispName)){
+                    continue;
+                }
+                String description = indent + s(4) + dispName + s(6) + getCommandDescription(progName.getName());
+                wrapDescription(out, indentCount + descriptionIndent, description);
+                out.append("\n");
+
+                JCommander jc = commander.findCommandByAlias(progName.getName());
+                jc.getUsageFormatter().usage(out, indent + s(6));
+                out.append("\n");
+            }
+        }
+    }
+
+    public void addDeprecatedCommand(String command) {
+        this.deprecatedCommands.add(command);
+    }
+
+    public void removeDeprecatedCommand(String command) {
+        this.deprecatedCommands.remove(command);
+    }
+
+    public void clearDeprecatedCommand(){
+        this.deprecatedCommands.clear();
+    }
+
+}