/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed 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 com.android.dialer.commandline;
import android.support.annotation.Nullable;
import com.android.dialer.commandline.Command.IllegalCommandLineArgumentException;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import com.google.common.collect.UnmodifiableIterator;
/**
* Parses command line arguments into optional flags (--foo, --key=value, --key value) and required
* positionals (which must be passed in order). Flags must start with "--" and are always before
* positionals. If flags are used "--" must be placed before positionals.
*
*
--flag will be interpreted as --flag=true, and --noflag as --flag=false
*
*
Grammar:
* dialer-cmd.py
* = ( -- ) |
* = "no"?()?
* = " " | "="
*/
@AutoValue
public abstract class Arguments {
public static final Arguments EMPTY =
new AutoValue_Arguments(ImmutableMap.of(), ImmutableList.of());
public abstract ImmutableMap getFlags();
public abstract ImmutableList getPositionals();
/**
* Return the positional at {@code position}. Throw {@link IllegalCommandLineArgumentException} if
* it is absent and reports to the user {@code name} is expected.
*/
public String expectPositional(int position, String name)
throws IllegalCommandLineArgumentException {
if (getPositionals().size() <= position) {
throw new IllegalCommandLineArgumentException(name + " expected");
}
return getPositionals().get(position);
}
public Boolean getBoolean(String flag, boolean defaultValue)
throws IllegalCommandLineArgumentException {
if (!getFlags().containsKey(flag)) {
return defaultValue;
}
switch (getFlags().get(flag)) {
case "true":
return true;
case "false":
return false;
default:
throw new IllegalCommandLineArgumentException("boolean value expected for " + flag);
}
}
public static Arguments parse(@Nullable String[] rawArguments)
throws IllegalCommandLineArgumentException {
if (rawArguments == null) {
return EMPTY;
}
return parse(Iterators.forArray(rawArguments));
}
public static Arguments parse(Iterable rawArguments)
throws IllegalCommandLineArgumentException {
return parse(Iterators.unmodifiableIterator(rawArguments.iterator()));
}
public static Arguments parse(UnmodifiableIterator iterator)
throws IllegalCommandLineArgumentException {
PeekingIterator peekingIterator = Iterators.peekingIterator(iterator);
ImmutableMap flags = parseFlags(peekingIterator);
ImmutableList positionals = parsePositionals(peekingIterator);
return new AutoValue_Arguments(flags, positionals);
}
private static ImmutableMap parseFlags(PeekingIterator iterator)
throws IllegalCommandLineArgumentException {
ImmutableMap.Builder flags = ImmutableMap.builder();
if (!iterator.hasNext()) {
return flags.build();
}
if (!iterator.peek().startsWith("--")) {
return flags.build();
}
while (iterator.hasNext()) {
String peek = iterator.peek();
if (peek.equals("--")) {
iterator.next();
return flags.build();
}
if (peek.startsWith("--")) {
String key = iterator.next().substring(2);
String value;
if (iterator.hasNext() && !iterator.peek().startsWith("--")) {
value = iterator.next();
} else if (key.contains("=")) {
String[] entry = key.split("=", 2);
key = entry[0];
value = entry[1];
} else if (key.startsWith("no")) {
key = key.substring(2);
value = "false";
} else {
value = "true";
}
flags.put(key, value);
} else {
throw new IllegalCommandLineArgumentException("flag or '--' expected");
}
}
return flags.build();
}
private static ImmutableList parsePositionals(PeekingIterator iterator) {
ImmutableList.Builder positionals = ImmutableList.builder();
positionals.addAll(iterator);
return positionals.build();
}
}