1 /* 2 * Copyright 2016, Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * Neither the name of Google LLC nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 package com.android.tools.smali.util.jcommander; 32 33 import com.beust.jcommander.JCommander; 34 import com.beust.jcommander.ParameterDescription; 35 import com.beust.jcommander.Parameterized; 36 import com.beust.jcommander.Parameters; 37 38 import javax.annotation.Nonnull; 39 import javax.annotation.Nullable; 40 import java.lang.reflect.Field; 41 42 /** 43 * Utilities related to "extended" commands - JCommander commands with additional information 44 */ 45 public class ExtendedCommands { 46 47 @Nonnull getExtendedParameters(Object command)48 private static ExtendedParameters getExtendedParameters(Object command) { 49 ExtendedParameters anno = command.getClass().getAnnotation(ExtendedParameters.class); 50 if (anno == null) { 51 throw new IllegalStateException("All extended commands should have an ExtendedParameters annotation: " + 52 command.getClass().getCanonicalName()); 53 } 54 return anno; 55 } 56 57 @Nonnull commandName(JCommander jc)58 public static String commandName(JCommander jc) { 59 return getExtendedParameters(jc.getObjects().get(0)).commandName(); 60 } 61 62 @Nonnull commandName(Object command)63 public static String commandName(Object command) { 64 return getExtendedParameters(command).commandName(); 65 } 66 67 @Nonnull commandAliases(JCommander jc)68 public static String[] commandAliases(JCommander jc) { 69 return commandAliases(jc.getObjects().get(0)); 70 } 71 72 @Nonnull commandAliases(Object command)73 public static String[] commandAliases(Object command) { 74 return getExtendedParameters(command).commandAliases(); 75 } 76 includeParametersInUsage(JCommander jc)77 public static boolean includeParametersInUsage(JCommander jc) { 78 return includeParametersInUsage(jc.getObjects().get(0)); 79 } 80 includeParametersInUsage(Object command)81 public static boolean includeParametersInUsage(Object command) { 82 return getExtendedParameters(command).includeParametersInUsage(); 83 } 84 85 @Nonnull postfixDescription(JCommander jc)86 public static String postfixDescription(JCommander jc) { 87 return postfixDescription(jc.getObjects().get(0)); 88 } 89 90 @Nonnull postfixDescription(Object command)91 public static String postfixDescription(Object command) { 92 return getExtendedParameters(command).postfixDescription(); 93 } 94 addExtendedCommand(JCommander jc, Command command)95 public static void addExtendedCommand(JCommander jc, Command command) { 96 jc.addCommand(commandName(command), command, commandAliases(command)); 97 command.setupCommand(command.getJCommander()); 98 } 99 100 @Nonnull parameterArgumentNames(ParameterDescription parameterDescription)101 public static String[] parameterArgumentNames(ParameterDescription parameterDescription) { 102 Parameterized parameterized = parameterDescription.getParameterized(); 103 104 Class cls = parameterDescription.getObject().getClass(); 105 Field field = null; 106 while (cls != Object.class) { 107 try { 108 field = cls.getDeclaredField(parameterized.getName()); 109 } catch (NoSuchFieldException ex) { 110 cls = cls.getSuperclass(); 111 continue; 112 } 113 break; 114 } 115 116 assert field != null; 117 ExtendedParameter extendedParameter = field.getAnnotation(ExtendedParameter.class); 118 if (extendedParameter != null) { 119 return extendedParameter.argumentNames(); 120 } 121 122 return new String[0]; 123 } 124 125 @Nullable getSubcommand(JCommander jc, String commandName)126 public static JCommander getSubcommand(JCommander jc, String commandName) { 127 if (jc.getCommands().containsKey(commandName)) { 128 return jc.getCommands().get(commandName); 129 } else { 130 for (JCommander command : jc.getCommands().values()) { 131 for (String alias: commandAliases(command)) { 132 if (commandName.equals(alias)) { 133 return command; 134 } 135 } 136 } 137 } 138 return null; 139 } 140 141 @Nullable getCommandDescription(@onnull JCommander jc)142 public static String getCommandDescription(@Nonnull JCommander jc) { 143 Parameters parameters = jc.getObjects().get(0).getClass().getAnnotation(Parameters.class); 144 if (parameters == null) { 145 return null; 146 } 147 return parameters.commandDescription(); 148 } 149 } 150