
io.airlift.command.Parser Maven / Gradle / Ivy
package io.airlift.command;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import io.airlift.command.model.ArgumentsMetadata;
import io.airlift.command.model.CommandGroupMetadata;
import io.airlift.command.model.CommandMetadata;
import io.airlift.command.model.GlobalMetadata;
import io.airlift.command.model.OptionMetadata;
import java.util.List;
import java.util.regex.Pattern;
import static com.google.common.base.Predicates.compose;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.collect.Iterables.find;
public class Parser
{
private static final Pattern SHORT_OPTIONS_PATTERN = Pattern.compile("-[^-].*");
private final GlobalMetadata metadata;
public Parser(GlobalMetadata metadata)
{
this.metadata = metadata;
}
// global> (option value*)* (group (option value*)*)? (command (option value* | arg)* '--'? args*)?
public ParseState parse(String... params)
{
return parse(ImmutableList.copyOf(params));
}
public ParseState parse(Iterable params)
{
PeekingIterator tokens = Iterators.peekingIterator(params.iterator());
ParseState state = ParseState.newInstance().pushContext(Context.GLOBAL);
// parse global options
state = parseOptions(tokens, state, metadata.getOptions());
// parse group
if (tokens.hasNext()) {
CommandGroupMetadata group = find(metadata.getCommandGroups(), compose(equalTo(tokens.peek()), CommandGroupMetadata.nameGetter()), null);
if (group != null) {
tokens.next();
state = state.withGroup(group).pushContext(Context.GROUP);
state = parseOptions(tokens, state, state.getGroup().getOptions());
}
}
// parse command
List expectedCommands = metadata.getDefaultGroupCommands();
if (state.getGroup() != null) {
expectedCommands = state.getGroup().getCommands();
}
if (tokens.hasNext()) {
CommandMetadata command = find(expectedCommands, compose(equalTo(tokens.peek()), CommandMetadata.nameGetter()), null);
if (command == null) {
while (tokens.hasNext()) {
state = state.withUnparsedInput(tokens.next());
}
}
else {
tokens.next();
state = state.withCommand(command).pushContext(Context.COMMAND);
while (tokens.hasNext()) {
state = parseOptions(tokens, state, command.getCommandOptions());
state = parseArgs(state, tokens, command.getArguments());
}
}
}
return state;
}
private ParseState parseOptions(PeekingIterator tokens, ParseState state, List allowedOptions)
{
while (tokens.hasNext()) {
//
// Try to parse next option(s) using different styles. If code matches it returns
// the next parser state, otherwise it returns null.
// Parse a simple option
ParseState nextState = parseSimpleOption(tokens, state, allowedOptions);
if (nextState != null) {
state = nextState;
continue;
}
// Parse GNU getopt long-form: --option=value
nextState = parseLongGnuGetOpt(tokens, state, allowedOptions);
if (nextState != null) {
state = nextState;
continue;
}
// Handle classic getopt syntax: -abc
nextState = parseClassicGetOpt(tokens, state, allowedOptions);
if (nextState != null) {
state = nextState;
continue;
}
// did not match an option
break;
}
return state;
}
private ParseState parseSimpleOption(PeekingIterator tokens, ParseState state, List allowedOptions)
{
OptionMetadata option = findOption(allowedOptions, tokens.peek());
if (option == null) {
return null;
}
tokens.next();
state = state.pushContext(Context.OPTION).withOption(option);
Object value;
if (option.getArity() == 0) {
state = state.withOptionValue(option, Boolean.TRUE).popContext();
}
else if (option.getArity() == 1) {
if (tokens.hasNext()) {
value = TypeConverter.newInstance().convert(option.getTitle(), option.getJavaType(), tokens.next());
state = state.withOptionValue(option, value).popContext();
}
}
else {
ImmutableList.Builder
© 2015 - 2025 Weber Informatics LLC | Privacy Policy