001 /**
002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 * You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software
010 * distributed under the License is distributed on an "AS IS" BASIS,
011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 * See the License for the specific language governing permissions and
013 * limitations under the License. See accompanying LICENSE file.
014 */
015 package org.apache.oozie.cli;
016
017 import org.apache.commons.cli.Options;
018 import org.apache.commons.cli.GnuParser;
019 import org.apache.commons.cli.ParseException;
020 import org.apache.commons.cli.CommandLine;
021 import org.apache.commons.cli.HelpFormatter;
022
023 import java.util.Map;
024 import java.util.LinkedHashMap;
025 import java.text.MessageFormat;
026 import java.io.PrintWriter;
027
028 /**
029 * Command line parser based on Apache common-cli 1.x that supports subcommands.
030 */
031 public class CLIParser {
032 private static final String LEFT_PADDING = " ";
033
034 private String cliName;
035 private String[] cliHelp;
036 private Map<String, Options> commands = new LinkedHashMap<String, Options>();
037 private Map<String, Boolean> commandWithArgs = new LinkedHashMap<String, Boolean>();
038 private Map<String, String> commandsHelp = new LinkedHashMap<String, String>();
039
040 /**
041 * Create a parser.
042 *
043 * @param cliName name of the parser, for help purposes.
044 * @param cliHelp help for the CLI.
045 */
046 public CLIParser(String cliName, String[] cliHelp) {
047 this.cliName = cliName;
048 this.cliHelp = cliHelp;
049 }
050
051 /**
052 * Add a command to the parser.
053 *
054 * @param command comand name.
055 * @param argsHelp command arguments help.
056 * @param commandHelp command description.
057 * @param commandOptions command options.
058 * @param hasArguments
059 */
060 public void addCommand(String command, String argsHelp, String commandHelp, Options commandOptions,
061 boolean hasArguments) {
062 String helpMsg = argsHelp + ((hasArguments) ? "<ARGS> " : "") + ": " + commandHelp;
063 commandsHelp.put(command, helpMsg);
064 commands.put(command, commandOptions);
065 commandWithArgs.put(command, hasArguments);
066 }
067
068 /**
069 * Bean that represents a parsed command.
070 */
071 public class Command {
072 private String name;
073 private CommandLine commandLine;
074
075 private Command(String name, CommandLine commandLine) {
076 this.name = name;
077 this.commandLine = commandLine;
078 }
079
080 /**
081 * Return the command name.
082 *
083 * @return the command name.
084 */
085 public String getName() {
086 return name;
087 }
088
089 /**
090 * Return the command line.
091 *
092 * @return the command line.
093 */
094 public CommandLine getCommandLine() {
095 return commandLine;
096 }
097 }
098
099 /**
100 * Parse a array of arguments into a command.
101 *
102 * @param args array of arguments.
103 * @return the parsed Command.
104 * @throws ParseException thrown if the arguments could not be parsed.
105 */
106 public Command parse(String[] args) throws ParseException {
107 if (args.length == 0) {
108 throw new ParseException("missing sub-command");
109 }
110 else {
111 if (commands.containsKey(args[0])) {
112 GnuParser parser = new GnuParser();
113 String[] minusCommand = new String[args.length - 1];
114 System.arraycopy(args, 1, minusCommand, 0, minusCommand.length);
115 return new Command(args[0], parser.parse(commands.get(args[0]), minusCommand,
116 commandWithArgs.get(args[0])));
117 }
118 else {
119 throw new ParseException(MessageFormat.format("invalid sub-command [{0}]", args[0]));
120 }
121 }
122 }
123
124 public String shortHelp() {
125 return "use 'help' sub-command for help details";
126 }
127
128 /**
129 * Print the help for the parser to standard output.
130 */
131 public void showHelp() {
132 PrintWriter pw = new PrintWriter(System.out);
133 pw.println("usage: ");
134 for (String s : cliHelp) {
135 pw.println(LEFT_PADDING + s);
136 }
137 pw.println();
138 HelpFormatter formatter = new HelpFormatter();
139 for (Map.Entry<String, Options> entry : commands.entrySet()) {
140 String s = LEFT_PADDING + cliName + " " + entry.getKey() + " ";
141 if (entry.getValue().getOptions().size() > 0) {
142 pw.println(s + "<OPTIONS> " + commandsHelp.get(entry.getKey()));
143 formatter.printOptions(pw, 100, entry.getValue(), s.length(), 3);
144 }
145 else {
146 pw.println(s + commandsHelp.get(entry.getKey()));
147 }
148 pw.println();
149 }
150 pw.flush();
151 }
152
153 }
154