pax_global_header 0000666 0000000 0000000 00000000064 12426741743 0014524 g ustar 00root root 0000000 0000000 52 comment=da7e1eea7ffb1d08451250f5c57d1ca5748bd1a9
airline-0.7/ 0000775 0000000 0000000 00000000000 12426741743 0013015 5 ustar 00root root 0000000 0000000 airline-0.7/.gitignore 0000664 0000000 0000000 00000000312 12426741743 0015001 0 ustar 00root root 0000000 0000000 *.iml
*.ipr
*.iws
/target
pom.xml.versionsBackup
/test-output
atlassian-ide-plugin.xml
.idea
.DS_Store
.classpath
.project
.settings
.project
temp-testng-customsuite.xml
.externalToolBuilders
*~
.rvmrc
airline-0.7/.travis.yml 0000664 0000000 0000000 00000000017 12426741743 0015124 0 ustar 00root root 0000000 0000000 language: java
airline-0.7/README.md 0000664 0000000 0000000 00000015343 12426741743 0014302 0 ustar 00root root 0000000 0000000 Airline
=======
Airline is a Java annotation-based framework for parsing Git like command line structures.
Latest release is 0.6, available from Maven Central.
```xml
io.airlift
airline
0.6
```
Here is a quick example:
```java
public class Git
{
public static void main(String[] args)
{
CliBuilder builder = Cli.builder("git")
.withDescription("the stupid content tracker")
.withDefaultCommand(Help.class)
.withCommands(Help.class, Add.class);
builder.withGroup("remote")
.withDescription("Manage set of tracked repositories")
.withDefaultCommand(RemoteShow.class)
.withCommands(RemoteShow.class, RemoteAdd.class);
Cli gitParser = builder.build();
gitParser.parse(args).run();
}
public static class GitCommand implements Runnable
{
@Option(type = OptionType.GLOBAL, name = "-v", description = "Verbose mode")
public boolean verbose;
public void run()
{
System.out.println(getClass().getSimpleName());
}
}
@Command(name = "add", description = "Add file contents to the index")
public static class Add extends GitCommand
{
@Arguments(description = "Patterns of files to be added")
public List patterns;
@Option(name = "-i", description = "Add modified contents interactively.")
public boolean interactive;
}
@Command(name = "show", description = "Gives some information about the remote ")
public static class RemoteShow extends GitCommand
{
@Option(name = "-n", description = "Do not query remote heads")
public boolean noQuery;
@Arguments(description = "Remote to show")
public String remote;
}
@Command(name = "add", description = "Adds a remote")
public static class RemoteAdd extends GitCommand
{
@Option(name = "-t", description = "Track only a specific branch")
public String branch;
@Arguments(description = "Remote repository to add")
public List remote;
}
}
```
Assuming you have packaged this as an executable program named 'git', you would be able to execute the following commands:
```shell
$ git add -p file
$ git remote add origin git@github.com:airlift/airline.git
$ git -v remote show origin
```
Single Command Mode
===================
Airline can also be used for simple, single-command programs:
```java
@Command(name = "ping", description = "network test utility")
public class Ping
{
@Inject
public HelpOption helpOption;
@Option(name = {"-c", "--count"}, description = "Send count packets")
public int count = 1;
public static void main(String... args)
{
Ping ping = SingleCommand.singleCommand(Ping.class).parse(args);
if (ping.helpOption.showHelpIfRequested()) {
return;
}
ping.run();
}
public void run()
{
System.out.println("Ping count: " + count);
}
}
```
Assuming you have packaged this as an executable program named 'ping', you would be able to execute the following commands:
```shell
$ ping
$ ping -c 5
$ ping --help
```
Help System
===========
Airline contains a fully automated help system, which generates man-page-like documentation driven by the Java
annotations.
As you may have noticed in the git code above, we added `Help.class` to the cli. This command is provided by Airline and works as follows:
```shell
$ git help
usage: git [-v] []
The most commonly used git commands are:
add Add file contents to the index
help Display help information
remote Manage set of tracked repositories
See 'git help ' for more information on a specific command.
$ git help git
NAME
git - the stupid content tracker
SYNOPSIS
git [-v] []
OPTIONS
-v
Verbose mode
COMMANDS
help
Display help information
add
Add file contents to the index
remote show
Gives some information about the remote
remote add
Adds a remote
$ git help add
NAME
git add - Add file contents to the index
SYNOPSIS
git [-v] add [-i] [--] [...]
OPTIONS
-i
Add modified contents interactively.
-v
Verbose mode
--
This option can be used to separate command-line options from the
list of argument, (useful when arguments might be mistaken for
command-line options
Patterns of files to be added
$ git help remote
NAME
git remote - Manage set of tracked repositories
SYNOPSIS
git [-v] remote
git [-v] remote add [-t ]
git [-v] remote show [-n]
OPTIONS
-v
Verbose mode
COMMANDS
With no arguments, Gives some information about the remote
show
Gives some information about the remote
With -n option, Do not query remote heads
add
Adds a remote
With -t option, Track only a specific branch
$ git help remote show
NAME
git remote show - Gives some information about the remote
SYNOPSIS
git [-v] remote show [-n] [--] []
OPTIONS
-n
Do not query remote heads
-v
Verbose mode
--
This option can be used to separate command-line options from the
list of argument, (useful when arguments might be mistaken for
command-line options
Remote to show
```
We have also, add `Help.class` as the default command for git, so if you execute git without any arguments, you will see the following:
```shell
$ git help
usage: git [-v] []
The most commonly used git commands are:
add Add file contents to the index
help Display help information
remote Manage set of tracked repositories
See 'git help ' for more information on a specific command.
```
For simple, single-command programs like ping, use the `HelpOption` option as shown in the example above.
`HelpOption` handles the options `-h` and `--help` and provides the `showHelpIfRequested()` method
to automatically show the following help output:
```shell
$ ping -h
NAME
ping - network test utility
SYNOPSIS
ping [(-c | --count )] [(-h | --help)]
OPTIONS
-c , --count
Send count packets
-h, --help
Display help information
```
airline-0.7/license.txt 0000664 0000000 0000000 00000026137 12426741743 0015211 0 ustar 00root root 0000000 0000000
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
airline-0.7/notice.md 0000664 0000000 0000000 00000000203 12426741743 0014613 0 ustar 00root root 0000000 0000000 Copyright Notices
=================
Copyright 2011 Dain Sundstrom
Copyright 2010 Cedric Beust
airline-0.7/pom.xml 0000664 0000000 0000000 00000004710 12426741743 0014334 0 ustar 00root root 0000000 0000000
4.0.0
io.airlift
airbase
28
airline
jar
0.7
airline
Java annotation-based framework for parsing Git like command line structures
https://github.com/airlift/airline
2012
scm:git:git@github.com:airlift/airline.git
http://github.com/airlift/airline/tree/master
0.7
true
true
true
javax.inject
javax.inject
com.google.code.findbugs
annotations
com.google.guava
guava
org.testng
testng
test
airline-0.7/src/ 0000775 0000000 0000000 00000000000 12426741743 0013604 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/ 0000775 0000000 0000000 00000000000 12426741743 0014530 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/ 0000775 0000000 0000000 00000000000 12426741743 0015451 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/io/ 0000775 0000000 0000000 00000000000 12426741743 0016060 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/io/airlift/ 0000775 0000000 0000000 00000000000 12426741743 0017512 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/io/airlift/airline/ 0000775 0000000 0000000 00000000000 12426741743 0021135 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/io/airlift/airline/Accessor.java 0000664 0000000 0000000 00000020614 12426741743 0023545 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
public class Accessor
{
private final String name;
private final Class> javaType;
private final List path;
private boolean multiValued;
public Accessor(Field... path)
{
this(ImmutableList.copyOf(path));
}
public Accessor(Iterable path)
{
Preconditions.checkNotNull(path, "path is null");
Preconditions.checkArgument(!Iterables.isEmpty(path), "path is empty");
this.path = ImmutableList.copyOf(path);
this.name = this.path.get(0).getDeclaringClass().getSimpleName() + "." + Joiner.on('.').join(Iterables.transform(this.path, new Function()
{
public String apply(Field field)
{
return field.getName();
}
}));
Field field = this.path.get(this.path.size() - 1);
multiValued = Collection.class.isAssignableFrom(field.getType());
javaType = getItemType(name, field.getGenericType());
}
public String getName()
{
return name;
}
public Class> getJavaType()
{
return javaType;
}
public boolean isMultiValued()
{
return multiValued;
}
public Object getValue(Object instance)
{
StringBuilder pathName = new StringBuilder();
for (Field intermediateField : path.subList(0, path.size() - 1)) {
if (pathName.length() != 0) {
pathName.append(".");
}
pathName.append(intermediateField.getName());
try {
Object nextInstance = intermediateField.get(instance);
if (nextInstance == null) {
nextInstance = ParserUtil.createInstance(intermediateField.getType());
intermediateField.set(instance, nextInstance);
}
instance = nextInstance;
}
catch (Exception e) {
throw new ParseException(e, "Error getting value of %s", pathName);
}
}
return instance;
}
public void addValues(Object commandInstance, Iterable> values)
{
if (Iterables.isEmpty(values)) {
return;
}
// get the actual instance
Object instance = getValue(commandInstance);
Field field = path.get(path.size() - 1);
field.setAccessible(true);
if (Collection.class.isAssignableFrom(field.getType())) {
Collection collection = getOrCreateCollectionField(name, instance, field);
Iterables.addAll(collection, values);
}
else {
try {
field.set(instance, Iterables.getLast(values));
}
catch (Exception e) {
throw new ParseException(e, "Error setting %s for argument %s", field.getName(), name);
}
}
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Accessor accessor = (Accessor) o;
if (!path.equals(accessor.path)) {
return false;
}
return true;
}
@Override
public int hashCode()
{
return path.hashCode();
}
@Override
public String toString()
{
return name;
}
//
// Private reflection helper methods
//
@SuppressWarnings("unchecked")
private static Collection newCollection(Class> type)
{
if (Collection.class.equals(type) || List.class.equals(type)) {
return new ArrayList();
}
if (Set.class.equals(type)) {
return new HashSet();
}
if (SortedSet.class.equals(type)) {
return new TreeSet();
}
try {
return (Collection) type.getConstructor().newInstance();
}
catch (Exception ignored) {
}
throw new ParseException("Parameters of Collection type '%s' are not supported. Please use List or Set instead.", type.getSimpleName());
}
private static Collection getOrCreateCollectionField(String name, Object object, Field field)
{
Collection collection;
try {
collection = (Collection) field.get(object);
}
catch (Exception e) {
throw new ParseException(e, "Error getting collection field %s for argument %s", field.getName(), name);
}
if (collection == null) {
collection = newCollection(field.getType());
try {
field.set(object, collection);
}
catch (Exception e) {
throw new ParseException(e, "Error setting collection field %s for argument %s", field.getName(), name);
}
}
return collection;
}
private static Class> getItemType(String name, Type type)
{
Class> rawClass = getRawType(type);
if (rawClass == null) {
throw new ParseException("Type of option %s be an exact type", name);
}
if (!Collection.class.isAssignableFrom(rawClass)) {
return rawClass;
}
Type[] types = getTypeParameters(Collection.class, type);
if ((types == null) || (types.length != 1)) {
throw new ParseException("Unable to get item type of Collection option %s", name);
}
Type itemType = types[0];
if (!(itemType instanceof Class)) {
throw new ParseException("Collection type option %s must be an exact type", name);
}
return (Class>) itemType;
}
private static Class> getRawType(Type type)
{
if (type instanceof Class) {
return (Class>) type;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
return getRawType(parameterizedType.getRawType());
}
return null;
}
private static Type[] getTypeParameters(Class> desiredType, Type type)
{
if (type instanceof Class) {
Class> rawClass = (Class>) type;
// if this is the collection class we're done
if (desiredType.equals(type)) {
return null;
}
for (Type iface : rawClass.getGenericInterfaces()) {
Type[] collectionType = getTypeParameters(desiredType, iface);
if (collectionType != null) {
return collectionType;
}
}
return getTypeParameters(desiredType, rawClass.getGenericSuperclass());
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type rawType = parameterizedType.getRawType();
if (desiredType.equals(rawType)) {
return parameterizedType.getActualTypeArguments();
}
Type[] collectionTypes = getTypeParameters(desiredType, rawType);
if (collectionTypes != null) {
for (int i = 0; i < collectionTypes.length; i++) {
if (collectionTypes[i] instanceof TypeVariable) {
TypeVariable> typeVariable = (TypeVariable>) collectionTypes[i];
TypeVariable>[] rawTypeParams = ((Class>) rawType).getTypeParameters();
for (int j = 0; j < rawTypeParams.length; j++) {
if (typeVariable.getName().equals(rawTypeParams[j].getName())) {
collectionTypes[i] = parameterizedType.getActualTypeArguments()[j];
}
}
}
}
}
return collectionTypes;
}
return null;
}
}
airline-0.7/src/main/java/io/airlift/airline/Arguments.java 0000664 0000000 0000000 00000002506 12426741743 0023750 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({FIELD})
public @interface Arguments
{
/**
* Name of the arguments.
*/
String title() default "";
/**
* A description of the arguments.
*/
String description() default "";
/**
* Argument usage for help.
*/
String usage() default "";
/**
* Whether this arguments are required.
*/
boolean required() default false;
}
airline-0.7/src/main/java/io/airlift/airline/Cli.java 0000664 0000000 0000000 00000024601 12426741743 0022512 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import io.airlift.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.MetadataLoader;
import io.airlift.airline.model.OptionMetadata;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static io.airlift.airline.ParserUtil.createInstance;
public class Cli
{
public static CliBuilder builder(String name)
{
Preconditions.checkNotNull(name, "name is null");
return new CliBuilder(name);
}
@Deprecated
public static CliBuilder buildCli(String name)
{
return builder(name);
}
@Deprecated
public static CliBuilder buildCli(String name, Class commandTypes)
{
return builder(name);
}
private final GlobalMetadata metadata;
private Cli(String name,
String description,
TypeConverter typeConverter,
Class extends C> defaultCommand,
Iterable> defaultGroupCommands,
Iterable> groups)
{
Preconditions.checkNotNull(name, "name is null");
Preconditions.checkNotNull(typeConverter, "typeConverter is null");
CommandMetadata defaultCommandMetadata = null;
if (defaultCommand != null) {
defaultCommandMetadata = MetadataLoader.loadCommand(defaultCommand);
}
List defaultCommandGroup = MetadataLoader.loadCommands(defaultGroupCommands);
List commandGroups = ImmutableList.copyOf(Iterables.transform(groups, new Function, CommandGroupMetadata>()
{
public CommandGroupMetadata apply(GroupBuilder group)
{
return MetadataLoader.loadCommandGroup(group.name, group.description, MetadataLoader.loadCommand(group.defaultCommand), MetadataLoader.loadCommands(group.commands));
}
}));
this.metadata = MetadataLoader.loadGlobal(name, description, defaultCommandMetadata, defaultCommandGroup, commandGroups);
}
public GlobalMetadata getMetadata()
{
return metadata;
}
public C parse(String... args)
{
return parse(ImmutableList.copyOf(args));
}
public C parse(Iterable args)
{
Preconditions.checkNotNull(args, "args is null");
Parser parser = new Parser();
ParseState state = parser.parse(metadata, args);
if (state.getCommand() == null) {
if (state.getGroup() != null) {
state = state.withCommand(state.getGroup().getDefaultCommand());
}
else {
state = state.withCommand(metadata.getDefaultCommand());
}
}
validate(state);
CommandMetadata command = state.getCommand();
return createInstance(command.getType(),
command.getAllOptions(),
state.getParsedOptions(),
command.getArguments(),
state.getParsedArguments(),
command.getMetadataInjections(),
ImmutableMap., Object>of(GlobalMetadata.class, metadata));
}
private void validate(ParseState state)
{
CommandMetadata command = state.getCommand();
if (command == null) {
List unparsedInput = state.getUnparsedInput();
if (unparsedInput.isEmpty()) {
throw new ParseCommandMissingException();
}
else {
throw new ParseCommandUnrecognizedException(unparsedInput);
}
}
ArgumentsMetadata arguments = command.getArguments();
if (state.getParsedArguments().isEmpty() && arguments != null && arguments.isRequired()) {
throw new ParseArgumentsMissingException(arguments.getTitle());
}
if (!state.getUnparsedInput().isEmpty()) {
throw new ParseArgumentsUnexpectedException(state.getUnparsedInput());
}
if (state.getLocation() == Context.OPTION) {
throw new ParseOptionMissingValueException(state.getCurrentOption().getTitle());
}
for (OptionMetadata option : command.getAllOptions()) {
if (option.isRequired() && !state.getParsedOptions().containsKey(option)) {
throw new ParseOptionMissingException(option.getOptions().iterator().next());
}
}
}
//
// Builder Classes
//
public static class CliBuilder
{
protected final String name;
protected String description;
protected TypeConverter typeConverter = new TypeConverter();
protected String optionSeparators;
private Class extends C> defaultCommand;
private final List> defaultCommandGroupCommands = newArrayList();
protected final Map> groups = newHashMap();
public CliBuilder(String name)
{
Preconditions.checkNotNull(name, "name is null");
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
this.name = name;
}
public CliBuilder withDescription(String description)
{
Preconditions.checkNotNull(description, "description is null");
Preconditions.checkArgument(!description.isEmpty(), "description is empty");
this.description = description;
return this;
}
// public CliBuilder withTypeConverter(TypeConverter typeConverter)
// {
// Preconditions.checkNotNull(typeConverter, "typeConverter is null");
// this.typeConverter = typeConverter;
// return this;
// }
// public CliBuilder withOptionSeparators(String optionsSeparator)
// {
// Preconditions.checkNotNull(optionsSeparator, "optionsSeparator is null");
// this.optionSeparators = optionsSeparator;
// return this;
// }
public CliBuilder withDefaultCommand(Class extends C> defaultCommand)
{
this.defaultCommand = defaultCommand;
return this;
}
public CliBuilder withCommand(Class extends C> command)
{
this.defaultCommandGroupCommands.add(command);
return this;
}
public CliBuilder withCommands(Class extends C> command, Class extends C>... moreCommands)
{
this.defaultCommandGroupCommands.add(command);
this.defaultCommandGroupCommands.addAll(ImmutableList.copyOf(moreCommands));
return this;
}
public CliBuilder withCommands(Iterable> commands)
{
this.defaultCommandGroupCommands.addAll(ImmutableList.copyOf(commands));
return this;
}
public GroupBuilder withGroup(String name)
{
Preconditions.checkNotNull(name, "name is null");
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
if (groups.containsKey(name)) {
return groups.get(name);
}
GroupBuilder group = new GroupBuilder(name);
groups.put(name, group);
return group;
}
public Cli build()
{
return new Cli(name, description, typeConverter, defaultCommand, defaultCommandGroupCommands, groups.values());
}
}
public static class GroupBuilder
{
private final String name;
private String description = null;
private Class extends C> defaultCommand = null;
private final List> commands = newArrayList();
private GroupBuilder(String name)
{
Preconditions.checkNotNull(name, "name is null");
this.name = name;
}
public GroupBuilder withDescription(String description)
{
Preconditions.checkNotNull(description, "description is null");
Preconditions.checkArgument(!description.isEmpty(), "description is empty");
Preconditions.checkState(this.description == null, "description is already set");
this.description = description;
return this;
}
public GroupBuilder withDefaultCommand(Class extends C> defaultCommand)
{
Preconditions.checkNotNull(defaultCommand, "defaultCommand is null");
Preconditions.checkState(this.defaultCommand == null, "defaultCommand is already set");
this.defaultCommand = defaultCommand;
return this;
}
public GroupBuilder withCommand(Class extends C> command)
{
Preconditions.checkNotNull(command, "command is null");
commands.add(command);
return this;
}
public GroupBuilder withCommands(Class extends C> command, Class extends C>... moreCommands)
{
this.commands.add(command);
this.commands.addAll(ImmutableList.copyOf(moreCommands));
return this;
}
public GroupBuilder withCommands(Iterable> commands)
{
this.commands.addAll(ImmutableList.copyOf(commands));
return this;
}
}
}
airline-0.7/src/main/java/io/airlift/airline/Command.java 0000664 0000000 0000000 00000002635 12426741743 0023364 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Marks a class as a command.
*/
@Target(TYPE)
@Retention(RUNTIME)
@Documented
public @interface Command
{
/**
* Name of the command. Command name is split on white space to form a multi-word name.
*/
String name();
/**
* Description of the command.
*/
String description() default "";
/**
* If true, this command won't appear in the usage().
*/
boolean hidden() default false;
}
airline-0.7/src/main/java/io/airlift/airline/CommandGroupUsage.java 0000664 0000000 0000000 00000015122 12426741743 0025361 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Preconditions;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.UsageHelper.DEFAULT_COMMAND_COMPARATOR;
import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
public class CommandGroupUsage
{
private final int columnSize;
private final boolean hideGlobalOptions;
private final Comparator super OptionMetadata> optionComparator;
private final Comparator super CommandMetadata> commandComparator = DEFAULT_COMMAND_COMPARATOR;
public CommandGroupUsage()
{
this(79, false, DEFAULT_OPTION_COMPARATOR);
}
public CommandGroupUsage(int columnSize)
{
this(columnSize, false, DEFAULT_OPTION_COMPARATOR);
}
public CommandGroupUsage(int columnSize, boolean hideGlobalOptions)
{
this(columnSize, hideGlobalOptions, DEFAULT_OPTION_COMPARATOR);
}
public CommandGroupUsage(int columnSize, boolean hideGlobalOptions, @Nullable Comparator super OptionMetadata> optionComparator)
{
Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
this.columnSize = columnSize;
this.hideGlobalOptions = hideGlobalOptions;
this.optionComparator = optionComparator;
}
/**
* Display the help on System.out.
*/
public void usage(@Nullable GlobalMetadata global, CommandGroupMetadata group)
{
StringBuilder stringBuilder = new StringBuilder();
usage(global, group, stringBuilder);
System.out.println(stringBuilder.toString());
}
/**
* Store the help in the passed string builder.
*/
public void usage(@Nullable GlobalMetadata global, CommandGroupMetadata group, StringBuilder out)
{
usage(global, group, new UsagePrinter(out, columnSize));
}
public void usage(@Nullable GlobalMetadata global, CommandGroupMetadata group, UsagePrinter out)
{
//
// NAME
//
out.append("NAME").newline();
out.newIndentedPrinter(8)
.append(global.getName())
.append(group.getName())
.append("-")
.append(group.getDescription())
.newline()
.newline();
//
// SYNOPSIS
//
out.append("SYNOPSIS").newline();
UsagePrinter synopsis = out.newIndentedPrinter(8).newPrinterWithHangingIndent(8);
List commands = newArrayList(group.getCommands());
Collections.sort(commands, commandComparator);
if (group.getDefaultCommand() != null) {
CommandMetadata command = group.getDefaultCommand();
if (global != null) {
synopsis.append(global.getName());
if (!hideGlobalOptions) {
synopsis.appendWords(UsageHelper.toSynopsisUsage(command.getGlobalOptions()));
}
}
synopsis.append(group.getName()).appendWords(UsageHelper.toSynopsisUsage(command.getGroupOptions()));
synopsis.newline();
}
for (CommandMetadata command : commands) {
if (global != null) {
synopsis.append(global.getName());
if (!hideGlobalOptions) {
synopsis.appendWords(UsageHelper.toSynopsisUsage(command.getGlobalOptions()));
}
}
synopsis.append(group.getName()).appendWords(UsageHelper.toSynopsisUsage(command.getGroupOptions()));
synopsis.append(command.getName()).appendWords(UsageHelper.toSynopsisUsage(command.getCommandOptions()));
synopsis.newline();
}
synopsis.newline();
//
// OPTIONS
//
List options = newArrayList();
options.addAll(group.getOptions());
if (global != null && !hideGlobalOptions) {
options.addAll(global.getOptions());
}
if (options.size() > 0) {
if (optionComparator != null) {
Collections.sort(options, optionComparator);
}
out.append("OPTIONS").newline();
for (OptionMetadata option : options) {
// option names
UsagePrinter optionPrinter = out.newIndentedPrinter(8);
optionPrinter.append(UsageHelper.toDescription(option)).newline();
// description
UsagePrinter descriptionPrinter = optionPrinter.newIndentedPrinter(4);
descriptionPrinter.append(option.getDescription()).newline();
descriptionPrinter.newline();
}
}
//
// COMMANDS
//
if (commands.size() > 0 || group.getDefaultCommand() != null) {
out.append("COMMANDS").newline();
UsagePrinter commandPrinter = out.newIndentedPrinter(8);
if (group.getDefaultCommand() != null && group.getDefaultCommand().getDescription() != null) {
commandPrinter.append("With no arguments,")
.append(group.getDefaultCommand().getDescription())
.newline()
.newline();
}
for (CommandMetadata command : group.getCommands()) {
commandPrinter.append(command.getName()).newline();
UsagePrinter descriptionPrinter = commandPrinter.newIndentedPrinter(4);
descriptionPrinter.append(command.getDescription()).newline().newline();
for (OptionMetadata option : command.getCommandOptions()) {
if (!option.isHidden() && option.getDescription() != null) {
descriptionPrinter.append("With")
.append(longest(option.getOptions()))
.append("option,")
.append(option.getDescription())
.newline()
.newline();
}
}
}
}
}
private static String longest(Iterable iterable)
{
String longest = "";
for (String value : iterable) {
if (value.length() > longest.length()) {
longest = value;
}
}
return longest;
}
}
airline-0.7/src/main/java/io/airlift/airline/CommandSuggester.java 0000664 0000000 0000000 00000001462 12426741743 0025252 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.collect.ImmutableList;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.transform;
public class CommandSuggester
implements Suggester
{
@Inject
public CommandMetadata command;
@Override
public Iterable suggest()
{
ImmutableList.Builder suggestions = ImmutableList.builder()
.addAll(concat(transform(command.getCommandOptions(), OptionMetadata.optionsGetter())));
if (command.getArguments() != null) {
suggestions.add("--");
}
return suggestions.build();
}
}
airline-0.7/src/main/java/io/airlift/airline/CommandUsage.java 0000664 0000000 0000000 00000012575 12426741743 0024355 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Preconditions;
import io.airlift.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
import static io.airlift.airline.UsageHelper.toSynopsisUsage;
public class CommandUsage
{
private final int columnSize;
private final Comparator super OptionMetadata> optionComparator;
public CommandUsage()
{
this(79, DEFAULT_OPTION_COMPARATOR);
}
public CommandUsage(int columnSize)
{
this(columnSize, DEFAULT_OPTION_COMPARATOR);
}
public CommandUsage(int columnSize, @Nullable Comparator super OptionMetadata> optionComparator)
{
Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
this.columnSize = columnSize;
this.optionComparator = optionComparator;
}
/**
* Display the help on System.out.
*/
public void usage(@Nullable String programName, @Nullable String groupName, String commandName, CommandMetadata command)
{
StringBuilder stringBuilder = new StringBuilder();
usage(programName, groupName, commandName, command, stringBuilder);
System.out.println(stringBuilder.toString());
}
/**
* Store the help in the passed string builder.
*/
public void usage(@Nullable String programName, @Nullable String groupName, String commandName, CommandMetadata command, StringBuilder out)
{
usage(programName, groupName, commandName, command, new UsagePrinter(out, columnSize));
}
public void usage(@Nullable String programName, @Nullable String groupName, String commandName, CommandMetadata command, UsagePrinter out)
{
//
// NAME
//
out.append("NAME").newline();
out.newIndentedPrinter(8)
.append(programName)
.append(groupName)
.append(commandName)
.append("-")
.append(command.getDescription())
.newline()
.newline();
//
// SYNOPSIS
//
out.append("SYNOPSIS").newline();
UsagePrinter synopsis = out.newIndentedPrinter(8).newPrinterWithHangingIndent(8);
List options = newArrayList();
if (programName != null) {
synopsis.append(programName).appendWords(toSynopsisUsage(sortOptions(command.getGlobalOptions())));
options.addAll(command.getGlobalOptions());
}
if (groupName != null) {
synopsis.append(groupName).appendWords(toSynopsisUsage(sortOptions(command.getGroupOptions())));
options.addAll(command.getGroupOptions());
}
synopsis.append(commandName).appendWords(toSynopsisUsage(sortOptions(command.getCommandOptions())));
options.addAll(command.getCommandOptions());
// command arguments (optional)
ArgumentsMetadata arguments = command.getArguments();
if (arguments != null) {
synopsis.append("[--]")
.append(UsageHelper.toUsage(arguments));
}
synopsis.newline();
synopsis.newline();
//
// OPTIONS
//
if (options.size() > 0 || arguments != null) {
options = sortOptions(options);
out.append("OPTIONS").newline();
for (OptionMetadata option : options) {
// skip hidden options
if (option.isHidden()) {
continue;
}
// option names
UsagePrinter optionPrinter = out.newIndentedPrinter(8);
optionPrinter.append(UsageHelper.toDescription(option)).newline();
// description
UsagePrinter descriptionPrinter = optionPrinter.newIndentedPrinter(4);
descriptionPrinter.append(option.getDescription()).newline();
descriptionPrinter.newline();
}
if (arguments != null) {
// "--" option
UsagePrinter optionPrinter = out.newIndentedPrinter(8);
optionPrinter.append("--").newline();
// description
UsagePrinter descriptionPrinter = optionPrinter.newIndentedPrinter(4);
descriptionPrinter.append("This option can be used to separate command-line options from the " +
"list of argument, (useful when arguments might be mistaken for command-line options").newline();
descriptionPrinter.newline();
// arguments name
optionPrinter.append(UsageHelper.toDescription(arguments)).newline();
// description
descriptionPrinter.append(arguments.getDescription()).newline();
descriptionPrinter.newline();
}
}
}
private List sortOptions(List options)
{
if (optionComparator != null) {
options = new ArrayList(options);
Collections.sort(options, optionComparator);
}
return options;
}
}
airline-0.7/src/main/java/io/airlift/airline/Context.java 0000664 0000000 0000000 00000000136 12426741743 0023424 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
public enum Context
{
GLOBAL, GROUP, COMMAND, OPTION, ARGS
}
airline-0.7/src/main/java/io/airlift/airline/GlobalSuggester.java 0000664 0000000 0000000 00000001530 12426741743 0025070 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.transform;
public class GlobalSuggester
implements Suggester
{
@Inject
public GlobalMetadata metadata;
@Override
public Iterable suggest()
{
return concat(
transform(metadata.getCommandGroups(), CommandGroupMetadata.nameGetter()),
transform(metadata.getDefaultGroupCommands(), CommandMetadata.nameGetter()),
concat(transform(metadata.getOptions(), OptionMetadata.optionsGetter()))
);
}
}
airline-0.7/src/main/java/io/airlift/airline/GlobalUsage.java 0000664 0000000 0000000 00000010127 12426741743 0024166 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Preconditions;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.UsageHelper.DEFAULT_OPTION_COMPARATOR;
public class GlobalUsage
{
private final int columnSize;
private final Comparator super OptionMetadata> optionComparator;
public GlobalUsage()
{
this(79, DEFAULT_OPTION_COMPARATOR);
}
public GlobalUsage(int columnSize)
{
this(columnSize, DEFAULT_OPTION_COMPARATOR);
}
public GlobalUsage(int columnSize, @Nullable Comparator super OptionMetadata> optionComparator)
{
Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
this.columnSize = columnSize;
this.optionComparator = optionComparator;
}
/**
* Display the help on System.out.
*/
public void usage(GlobalMetadata global)
{
StringBuilder stringBuilder = new StringBuilder();
usage(global, stringBuilder);
System.out.println(stringBuilder.toString());
}
/**
* Store the help in the passed string builder.
*/
public void usage(GlobalMetadata global, StringBuilder out)
{
usage(global, new UsagePrinter(out, columnSize));
}
public void usage(GlobalMetadata global, UsagePrinter out)
{
//
// NAME
//
out.append("NAME").newline();
out.newIndentedPrinter(8)
.append(global.getName())
.append("-")
.append(global.getDescription())
.newline()
.newline();
//
// SYNOPSIS
//
out.append("SYNOPSIS").newline();
out.newIndentedPrinter(8).newPrinterWithHangingIndent(8)
.append(global.getName())
.appendWords(UsageHelper.toSynopsisUsage(global.getOptions()))
.append(" []")
.newline()
.newline();
//
// OPTIONS
//
List options = newArrayList(global.getOptions());
if (options.size() > 0) {
if (optionComparator != null) {
Collections.sort(options, optionComparator);
}
out.append("OPTIONS").newline();
for (OptionMetadata option : options) {
// option names
UsagePrinter optionPrinter = out.newIndentedPrinter(8);
optionPrinter.append(UsageHelper.toDescription(option)).newline();
// description
UsagePrinter descriptionPrinter = optionPrinter.newIndentedPrinter(4);
descriptionPrinter.append(option.getDescription()).newline();
descriptionPrinter.newline();
}
}
//
// COMMANDS
//
out.append("COMMANDS").newline();
UsagePrinter commandPrinter = out.newIndentedPrinter(8);
for (CommandMetadata command : global.getDefaultGroupCommands()) {
printCommandDescription(commandPrinter, null, command);
}
for (CommandGroupMetadata group : global.getCommandGroups()) {
for (CommandMetadata command : group.getCommands()) {
printCommandDescription(commandPrinter, group, command);
}
}
}
private void printCommandDescription(UsagePrinter commandPrinter, @Nullable CommandGroupMetadata group, CommandMetadata command)
{
if (group != null) {
commandPrinter.append(group.getName());
}
commandPrinter.append(command.getName()).newline();
if (command.getDescription() != null) {
commandPrinter.newIndentedPrinter(4).append(command.getDescription()).newline();
}
commandPrinter.newline();
}
}
airline-0.7/src/main/java/io/airlift/airline/GlobalUsageSummary.java 0000664 0000000 0000000 00000006701 12426741743 0025547 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.OptionMetadata;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newTreeMap;
import static io.airlift.airline.UsageHelper.toUsage;
public class GlobalUsageSummary
{
private final int columnSize;
public GlobalUsageSummary()
{
this(79);
}
public GlobalUsageSummary(int columnSize)
{
Preconditions.checkArgument(columnSize > 0, "columnSize must be greater than 0");
this.columnSize = columnSize;
}
/**
* Display the help on System.out.
*/
public void usage(GlobalMetadata global)
{
StringBuilder stringBuilder = new StringBuilder();
usage(global, stringBuilder);
System.out.println(stringBuilder.toString());
}
/**
* Store the help in the passed string builder.
*/
public void usage(GlobalMetadata global, StringBuilder out)
{
usage(global, new UsagePrinter(out, columnSize));
}
public void usage(GlobalMetadata global, UsagePrinter out)
{
//
// Usage
//
// build arguments
List commandArguments = newArrayList();
commandArguments.addAll(Collections2.transform(global.getOptions(), new Function()
{
public String apply(OptionMetadata option)
{
if (option.isHidden()) {
return null;
}
return toUsage(option);
}
}));
out.newPrinterWithHangingIndent(8)
.append("usage:")
.append(global.getName())
.appendWords(commandArguments)
.append(" []")
.newline()
.newline();
//
// Common commands
//
Map commands = newTreeMap();
for (CommandMetadata commandMetadata : global.getDefaultGroupCommands()) {
if (!commandMetadata.isHidden()) {
commands.put(commandMetadata.getName(), commandMetadata.getDescription());
}
}
for (CommandGroupMetadata commandGroupMetadata : global.getCommandGroups()) {
commands.put(commandGroupMetadata.getName(), commandGroupMetadata.getDescription());
}
out.append("The most commonly used ").append(global.getName()).append(" commands are:").newline();
out.newIndentedPrinter(4).appendTable(Iterables.transform(commands.entrySet(), new Function, Iterable>()
{
public Iterable apply(Entry entry)
{
return ImmutableList.of(entry.getKey(), Objects.firstNonNull(entry.getValue(), ""));
}
}));
out.newline();
out.append("See").append("'" + global.getName()).append("help ' for more information on a specific command.").newline();
}
}
airline-0.7/src/main/java/io/airlift/airline/GroupSuggester.java 0000664 0000000 0000000 00000001301 12426741743 0024760 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.transform;
public class GroupSuggester
implements Suggester
{
@Inject
public CommandGroupMetadata group;
@Override
public Iterable suggest()
{
return concat(
transform(group.getCommands(), CommandMetadata.nameGetter()),
concat(transform(group.getOptions(), OptionMetadata.optionsGetter()))
);
}
}
airline-0.7/src/main/java/io/airlift/airline/Help.java 0000664 0000000 0000000 00000006053 12426741743 0022674 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import javax.inject.Inject;
import java.util.List;
import java.util.concurrent.Callable;
import static com.google.common.collect.Lists.newArrayList;
@Command(name = "help", description = "Display help information")
public class Help implements Runnable, Callable
{
@Inject
public GlobalMetadata global;
@Arguments
public List command = newArrayList();
@Override
public void run()
{
help(global, command);
}
@Override
public Void call()
{
run();
return null;
}
public static void help(CommandMetadata command)
{
StringBuilder stringBuilder = new StringBuilder();
help(command, stringBuilder);
System.out.println(stringBuilder.toString());
}
public static void help(CommandMetadata command, StringBuilder out)
{
new CommandUsage().usage(null, null, command.getName(), command, out);
}
public static void help(GlobalMetadata global, List commandNames)
{
StringBuilder stringBuilder = new StringBuilder();
help(global, commandNames, stringBuilder);
System.out.println(stringBuilder.toString());
}
public static void help(GlobalMetadata global, List commandNames, StringBuilder out)
{
if (commandNames.isEmpty()) {
new GlobalUsageSummary().usage(global, out);
return;
}
String name = commandNames.get(0);
// main program?
if (name.equals(global.getName())) {
new GlobalUsage().usage(global, out);
return;
}
// command in the default group?
for (CommandMetadata command : global.getDefaultGroupCommands()) {
if (name.equals(command.getName())) {
new CommandUsage().usage(global.getName(), null, command.getName(), command, out);
return;
}
}
// command in a group?
for (CommandGroupMetadata group : global.getCommandGroups()) {
if (name.endsWith(group.getName())) {
// general group help or specific command help?
if (commandNames.size() == 1) {
new CommandGroupUsage().usage(global, group, out);
return;
}
else {
String commandName = commandNames.get(1);
for (CommandMetadata command : group.getCommands()) {
if (commandName.equals(command.getName())) {
new CommandUsage().usage(global.getName(), group.getName(), command.getName(), command, out);
return;
}
}
System.out.println("Unknown command " + name + " " + commandName);
}
}
}
System.out.println("Unknown command " + name);
}
}
airline-0.7/src/main/java/io/airlift/airline/HelpOption.java 0000664 0000000 0000000 00000000702 12426741743 0024060 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import io.airlift.airline.model.CommandMetadata;
import javax.inject.Inject;
public class HelpOption
{
@Inject
public CommandMetadata commandMetadata;
@Option(name = {"-h", "--help"}, description = "Display help information")
public Boolean help = false;
public boolean showHelpIfRequested()
{
if (help) {
Help.help(commandMetadata);
}
return help;
}
}
airline-0.7/src/main/java/io/airlift/airline/Option.java 0000664 0000000 0000000 00000003550 12426741743 0023253 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({FIELD})
public @interface Option
{
/**
* Is this a command, group or global option
*/
OptionType type() default OptionType.COMMAND;
/**
* Name use to identify the option value in documentation and error messages.
*/
String title() default "";
/**
* An array of allowed command line parameters (e.g. "-n", "--name", etc...).
*/
String[] name();
/**
* A description of this option.
*/
String description() default "";
/**
* Whether this option is required.
*/
boolean required() default false;
/**
* How many parameter values this option will consume. For example,
* an arity of 2 will allow "-pair value1 value2".
*/
int arity() default Integer.MIN_VALUE;
/**
* If true, this parameter won't appear in the usage().
*/
boolean hidden() default false;
String[] allowedValues() default {};
}
airline-0.7/src/main/java/io/airlift/airline/OptionType.java 0000664 0000000 0000000 00000000123 12426741743 0024106 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
public enum OptionType
{
GLOBAL, GROUP, COMMAND
}
airline-0.7/src/main/java/io/airlift/airline/ParseArgumentsMissingException.java 0000664 0000000 0000000 00000002162 12426741743 0030152 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseArgumentsMissingException extends ParseException
{
private final String argumentTitle;
ParseArgumentsMissingException(String argumentTitle)
{
super("Required parameters are missing: %s", argumentTitle);
this.argumentTitle = argumentTitle;
}
public String getArgumentTitle()
{
return argumentTitle;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseArgumentsUnexpectedException.java 0000664 0000000 0000000 00000002345 12426741743 0030650 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class ParseArgumentsUnexpectedException extends ParseException
{
private final List unparsedInput;
ParseArgumentsUnexpectedException(List unparsedInput)
{
super("Found unexpected parameters: %s", unparsedInput);
this.unparsedInput = ImmutableList.copyOf(unparsedInput);
}
public List getUnparsedInput()
{
return unparsedInput;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseCommandMissingException.java 0000664 0000000 0000000 00000001627 12426741743 0027570 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseCommandMissingException extends ParseException
{
ParseCommandMissingException()
{
super("No command specified");
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseCommandUnrecognizedException.java 0000664 0000000 0000000 00000002350 12426741743 0030605 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class ParseCommandUnrecognizedException extends ParseException
{
private final List unparsedInput;
ParseCommandUnrecognizedException(List unparsedInput)
{
super("Command '%s' not recognized", unparsedInput.get(0));
this.unparsedInput = ImmutableList.copyOf(unparsedInput);
}
public List getUnparsedInput()
{
return unparsedInput;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseException.java 0000664 0000000 0000000 00000002060 12426741743 0024727 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseException extends RuntimeException
{
public ParseException(String string, Object... args)
{
super(String.format(string, args));
}
public ParseException(Exception cause, String string, Object... args)
{
super(String.format(string, args), cause);
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseOptionConversionException.java 0000664 0000000 0000000 00000002632 12426741743 0030173 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseOptionConversionException extends ParseException
{
private final String optionTitle;
private final String value;
private final String typeName;
ParseOptionConversionException(String optionTitle, String value, String typeName)
{
super("%s: can not convert \"%s\" to a %s", optionTitle, value, typeName);
this.optionTitle = optionTitle;
this.value = value;
this.typeName = typeName;
}
public String getOptionTitle()
{
return optionTitle;
}
public String getValue()
{
return value;
}
public String getTypeName()
{
return typeName;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseOptionMissingException.java 0000664 0000000 0000000 00000002132 12426741743 0027452 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseOptionMissingException extends ParseException
{
private final String optionTitle;
ParseOptionMissingException(String optionTitle)
{
super("Required option '%s' is missing", optionTitle);
this.optionTitle = optionTitle;
}
public String getOptionTitle()
{
return optionTitle;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseOptionMissingValueException.java 0000664 0000000 0000000 00000002161 12426741743 0030451 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
public class ParseOptionMissingValueException extends ParseException
{
private final String optionTitle;
ParseOptionMissingValueException(String optionTitle)
{
super("Required values for option '%s' not provided", optionTitle);
this.optionTitle = optionTitle;
}
public String getOptionTitle()
{
return optionTitle;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParseState.java 0000664 0000000 0000000 00000012014 12426741743 0024051 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.OptionMetadata;
import java.util.List;
public class ParseState
{
private final List locationStack;
private final CommandGroupMetadata group;
private final CommandMetadata command;
private final ListMultimap parsedOptions;
private final List parsedArguments;
private final OptionMetadata currentOption;
private final List unparsedInput;
ParseState(CommandGroupMetadata group,
CommandMetadata command,
ListMultimap parsedOptions,
List locationStack,
List parsedArguments,
OptionMetadata currentOption,
List unparsedInput)
{
this.group = group;
this.command = command;
this.parsedOptions = parsedOptions;
this.locationStack = locationStack;
this.parsedArguments = parsedArguments;
this.currentOption = currentOption;
this.unparsedInput = unparsedInput;
}
public static ParseState newInstance()
{
return new ParseState(null, null, ArrayListMultimap.create(), ImmutableList.of(), ImmutableList.of(), null, ImmutableList.of());
}
public ParseState pushContext(Context location)
{
ImmutableList locationStack = ImmutableList.builder()
.addAll(this.locationStack)
.add(location)
.build();
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, currentOption, unparsedInput);
}
public ParseState popContext()
{
ImmutableList locationStack = ImmutableList.copyOf(this.locationStack.subList(0, this.locationStack.size() - 1));
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, currentOption, unparsedInput);
}
public ParseState withOptionValue(OptionMetadata option, Object value)
{
ImmutableListMultimap newOptions = ImmutableListMultimap.builder()
.putAll(parsedOptions)
.put(option, value)
.build();
return new ParseState(group, command, newOptions, locationStack, parsedArguments, currentOption, unparsedInput);
}
public ParseState withGroup(CommandGroupMetadata group)
{
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, currentOption, unparsedInput);
}
public ParseState withCommand(CommandMetadata command)
{
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, currentOption, unparsedInput);
}
public ParseState withOption(OptionMetadata option)
{
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, option, unparsedInput);
}
public ParseState withArgument(Object argument)
{
ImmutableList newArguments = ImmutableList.builder()
.addAll(parsedArguments)
.add(argument)
.build();
return new ParseState(group, command, parsedOptions, locationStack, newArguments, currentOption, unparsedInput);
}
public ParseState withUnparsedInput(String input)
{
ImmutableList newUnparsedInput = ImmutableList.builder()
.addAll(unparsedInput)
.add(input)
.build();
return new ParseState(group, command, parsedOptions, locationStack, parsedArguments, currentOption, newUnparsedInput);
}
@Override
public String toString()
{
return "ParseState{" +
"locationStack=" + locationStack +
", group=" + group +
", command=" + command +
", parsedOptions=" + parsedOptions +
", parsedArguments=" + parsedArguments +
", currentOption=" + currentOption +
", unparsedInput=" + unparsedInput +
'}';
}
public Context getLocation()
{
return locationStack.get(locationStack.size() - 1);
}
public CommandGroupMetadata getGroup()
{
return group;
}
public CommandMetadata getCommand()
{
return command;
}
public OptionMetadata getCurrentOption()
{
return currentOption;
}
public ListMultimap getParsedOptions()
{
return parsedOptions;
}
public List getParsedArguments()
{
return parsedArguments;
}
public List getUnparsedInput()
{
return unparsedInput;
}
}
airline-0.7/src/main/java/io/airlift/airline/Parser.java 0000664 0000000 0000000 00000024222 12426741743 0023236 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
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.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.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("-[^-].*");
// global> (option value*)* (group (option value*)*)? (command (option value* | arg)* '--'? args*)?
public ParseState parse(GlobalMetadata metadata, String... params)
{
return parse(metadata, ImmutableList.copyOf(params));
}
public ParseState parse(GlobalMetadata metadata, 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;
}
public ParseState parseCommand(CommandMetadata command, Iterable params)
{
PeekingIterator tokens = Iterators.peekingIterator(params.iterator());
ParseState state = ParseState.newInstance().pushContext(Context.GLOBAL).withCommand(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 values = ImmutableList.builder();
int count = 0;
while (count < option.getArity() && tokens.hasNext()) {
values.add(TypeConverter.newInstance().convert(option.getTitle(), option.getJavaType(), tokens.next()));
++count;
}
if (count == option.getArity()) {
state = state.withOptionValue(option, values.build()).popContext();
}
}
return state;
}
private ParseState parseLongGnuGetOpt(PeekingIterator tokens, ParseState state, List allowedOptions)
{
List parts = ImmutableList.copyOf(Splitter.on('=').limit(2).split(tokens.peek()));
if (parts.size() != 2) {
return null;
}
OptionMetadata option = findOption(allowedOptions, parts.get(0));
if (option == null || option.getArity() != 1) {
// TODO: this is not exactly correct. It should be an error condition
return null;
}
// we have a match so consume the token
tokens.next();
// update state
state = state.pushContext(Context.OPTION).withOption(option);
Object value = TypeConverter.newInstance().convert(option.getTitle(), option.getJavaType(), parts.get(1));
state = state.withOption(option).withOptionValue(option, value).popContext();
return state;
}
private ParseState parseClassicGetOpt(PeekingIterator tokens, ParseState state, List allowedOptions)
{
if (!SHORT_OPTIONS_PATTERN.matcher(tokens.peek()).matches()) {
return null;
}
// remove leading dash from token
String remainingToken = tokens.peek().substring(1);
ParseState nextState = state;
while (!remainingToken.isEmpty()) {
char tokenCharacter = remainingToken.charAt(0);
// is the current token character a single letter option?
OptionMetadata option = findOption(allowedOptions, "-" + tokenCharacter);
if (option == null) {
return null;
}
nextState = nextState.pushContext(Context.OPTION).withOption(option);
// remove current token character
remainingToken = remainingToken.substring(1);
// for no argument options, process the option and remove the character from the token
if (option.getArity() == 0) {
nextState = nextState.withOptionValue(option, Boolean.TRUE).popContext();
continue;
}
if (option.getArity() == 1) {
// we must, consume the current token so we can see the next token
tokens.next();
// if current token has more characters, this is the value; otherwise it is the next token
if (!remainingToken.isEmpty()) {
Object value = TypeConverter.newInstance().convert(option.getTitle(), option.getJavaType(), remainingToken);
nextState = nextState.withOptionValue(option, value).popContext();
}
else if (tokens.hasNext()) {
Object value = TypeConverter.newInstance().convert(option.getTitle(), option.getJavaType(), tokens.next());
nextState = nextState.withOptionValue(option, value).popContext();
}
return nextState;
}
throw new UnsupportedOperationException("Short options style can not be used with option " + option.getAllowedValues());
}
// consume the current token
tokens.next();
return nextState;
}
private ParseState parseArgs(ParseState state, PeekingIterator tokens, ArgumentsMetadata arguments)
{
if (tokens.hasNext()) {
if (tokens.peek().equals("--")) {
state = state.pushContext(Context.ARGS);
tokens.next();
// consume all args
while (tokens.hasNext()) {
state = parseArg(state, tokens, arguments);
}
}
else {
state = parseArg(state, tokens, arguments);
}
}
return state;
}
private ParseState parseArg(ParseState state, PeekingIterator tokens, ArgumentsMetadata arguments)
{
if (arguments != null) {
state = state.withArgument(TypeConverter.newInstance().convert(arguments.getTitle(), arguments.getJavaType(), tokens.next()));
}
else {
state = state.withUnparsedInput(tokens.next());
}
return state;
}
private OptionMetadata findOption(List options, String param)
{
for (OptionMetadata optionMetadata : options) {
if (optionMetadata.getOptions().contains(param)) {
return optionMetadata;
}
}
return null;
}
}
airline-0.7/src/main/java/io/airlift/airline/ParserUtil.java 0000664 0000000 0000000 00000004366 12426741743 0024103 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
import io.airlift.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.OptionMetadata;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Iterables.concat;
public class ParserUtil
{
public static T createInstance(Class type)
{
if (type != null) {
try {
return type.getConstructor().newInstance();
}
catch (Exception e) {
throw new ParseException(e, "Unable to create instance %s", type.getName());
}
}
return null;
}
public static T createInstance(Class> type,
Iterable options,
ListMultimap parsedOptions,
ArgumentsMetadata arguments,
Iterable parsedArguments,
Iterable metadataInjection,
Map, Object> bindings)
{
// create the command instance
T commandInstance = (T) ParserUtil.createInstance(type);
// inject options
for (OptionMetadata option : options) {
List> values = parsedOptions.get(option);
if (option.getArity() > 1 && !values.isEmpty()) {
// hack: flatten the collection
values = ImmutableList.copyOf(concat((Iterable>) values));
}
if (values != null && !values.isEmpty()) {
for (Accessor accessor : option.getAccessors()) {
accessor.addValues(commandInstance, values);
}
}
}
// inject args
if (arguments != null && parsedArguments != null) {
for (Accessor accessor : arguments.getAccessors()) {
accessor.addValues(commandInstance, parsedArguments);
}
}
for (Accessor accessor : metadataInjection) {
Object injectee = bindings.get(accessor.getJavaType());
if (injectee != null) {
accessor.addValues(commandInstance, ImmutableList.of(injectee));
}
}
return commandInstance;
}
}
airline-0.7/src/main/java/io/airlift/airline/SingleCommand.java 0000664 0000000 0000000 00000007206 12426741743 0024525 0 ustar 00root root 0000000 0000000 /**
* Copyright (C) 2010 the original author or authors.
* See the notice.md file distributed with this work for additional
* information regarding copyright ownership.
*
* 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 io.airlift.airline;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.MetadataLoader;
import io.airlift.airline.model.OptionMetadata;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.airlift.airline.ParserUtil.createInstance;
public class SingleCommand
{
public static SingleCommand singleCommand(Class command)
{
return new SingleCommand(command);
}
private final CommandMetadata commandMetadata;
private SingleCommand(Class command)
{
checkNotNull(command, "command is null");
commandMetadata = MetadataLoader.loadCommand(command);
}
public CommandMetadata getCommandMetadata()
{
return commandMetadata;
}
public C parse(String... args)
{
return parse(ImmutableList.copyOf(args));
}
public C parse(Iterable args)
{
checkNotNull(args, "args is null");
Parser parser = new Parser();
ParseState state = parser.parseCommand(commandMetadata, args);
validate(state);
CommandMetadata command = state.getCommand();
return createInstance(command.getType(),
command.getAllOptions(),
state.getParsedOptions(),
command.getArguments(),
state.getParsedArguments(),
command.getMetadataInjections(),
ImmutableMap., Object>of(CommandMetadata.class, commandMetadata));
}
private void validate(ParseState state)
{
CommandMetadata command = state.getCommand();
if (command == null) {
List unparsedInput = state.getUnparsedInput();
if (unparsedInput.isEmpty()) {
throw new ParseCommandMissingException();
}
else {
throw new ParseCommandUnrecognizedException(unparsedInput);
}
}
ArgumentsMetadata arguments = command.getArguments();
if (state.getParsedArguments().isEmpty() && arguments != null && arguments.isRequired()) {
throw new ParseArgumentsMissingException(arguments.getTitle());
}
if (!state.getUnparsedInput().isEmpty()) {
throw new ParseArgumentsUnexpectedException(state.getUnparsedInput());
}
if (state.getLocation() == Context.OPTION) {
throw new ParseOptionMissingValueException(state.getCurrentOption().getTitle());
}
for (OptionMetadata option : command.getAllOptions()) {
if (option.isRequired() && !state.getParsedOptions().containsKey(option)) {
throw new ParseOptionMissingException(option.getOptions().iterator().next());
}
}
}
}
airline-0.7/src/main/java/io/airlift/airline/SuggestCommand.java 0000664 0000000 0000000 00000005523 12426741743 0024725 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.airline.model.CommandGroupMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.GlobalMetadata;
import io.airlift.airline.model.MetadataLoader;
import io.airlift.airline.model.OptionMetadata;
import io.airlift.airline.model.SuggesterMetadata;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.ParserUtil.createInstance;
@Command(name = "suggest")
public class SuggestCommand
implements Runnable, Callable
{
private static final Map> BUILTIN_SUGGESTERS = ImmutableMap.>builder()
.put(Context.GLOBAL, GlobalSuggester.class)
.put(Context.GROUP, GroupSuggester.class)
.put(Context.COMMAND, CommandSuggester.class)
.build();
@Inject
public GlobalMetadata metadata;
@Arguments
public List arguments = newArrayList();
@VisibleForTesting
public Iterable generateSuggestions()
{
Parser parser = new Parser();
ParseState state = parser.parse(metadata, arguments);
Class extends Suggester> suggesterClass = BUILTIN_SUGGESTERS.get(state.getLocation());
if (suggesterClass != null) {
SuggesterMetadata suggesterMetadata = MetadataLoader.loadSuggester(suggesterClass);
if (suggesterMetadata != null) {
ImmutableMap.Builder, Object> bindings = ImmutableMap., Object>builder()
.put(GlobalMetadata.class, metadata);
if (state.getGroup() != null) {
bindings.put(CommandGroupMetadata.class, state.getGroup());
}
if (state.getCommand() != null) {
bindings.put(CommandMetadata.class, state.getCommand());
}
Suggester suggester = createInstance(suggesterMetadata.getSuggesterClass(),
ImmutableList.of(),
null,
null,
null,
suggesterMetadata.getMetadataInjections(),
bindings.build());
return suggester.suggest();
}
}
return ImmutableList.of();
}
@Override
public void run()
{
System.out.println(Joiner.on("\n").join(generateSuggestions()));
}
@Override
public Void call()
{
run();
return null;
}
}
airline-0.7/src/main/java/io/airlift/airline/Suggester.java 0000664 0000000 0000000 00000000134 12426741743 0023746 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
public interface Suggester
{
Iterable suggest();
}
airline-0.7/src/main/java/io/airlift/airline/TypeConverter.java 0000664 0000000 0000000 00000005407 12426741743 0024617 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Preconditions;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class TypeConverter
{
public static TypeConverter newInstance()
{
return new TypeConverter();
}
public Object convert(String name, Class> type, String value)
{
Preconditions.checkNotNull(name, "name is null");
Preconditions.checkNotNull(type, "type is null");
Preconditions.checkNotNull(value, "value is null");
try {
if (String.class.isAssignableFrom(type)) {
return value;
}
else if (Boolean.class.isAssignableFrom(type) || Boolean.TYPE.isAssignableFrom(type)) {
return Boolean.valueOf(value);
}
else if (Byte.class.isAssignableFrom(type) || Byte.TYPE.isAssignableFrom(type)) {
return Byte.valueOf(value);
}
else if (Short.class.isAssignableFrom(type) || Short.TYPE.isAssignableFrom(type)) {
return Short.valueOf(value);
}
else if (Integer.class.isAssignableFrom(type) || Integer.TYPE.isAssignableFrom(type)) {
return Integer.valueOf(value);
}
else if (Long.class.isAssignableFrom(type) || Long.TYPE.isAssignableFrom(type)) {
return Long.valueOf(value);
}
else if (Float.class.isAssignableFrom(type) || Float.TYPE.isAssignableFrom(type)) {
return Float.valueOf(value);
}
else if (Double.class.isAssignableFrom(type) || Double.TYPE.isAssignableFrom(type)) {
return Double.valueOf(value);
}
}
catch (Exception ignored) {
}
// Look for a static fromString(String) method
try {
Method valueOf = type.getMethod("fromString", String.class);
if (valueOf.getReturnType().isAssignableFrom(type)) {
return valueOf.invoke(null, value);
}
} catch (Throwable ignored) {
}
// Look for a static valueOf(String) method (this covers enums which have a valueOf method)
try {
Method valueOf = type.getMethod("valueOf", String.class);
if (valueOf.getReturnType().isAssignableFrom(type)) {
return valueOf.invoke(null, value);
}
}
catch (Throwable ignored) {
}
// Look for a constructor taking a string
try {
Constructor> constructor = type.getConstructor(String.class);
return constructor.newInstance(value);
}
catch (Throwable ignored) {
}
throw new ParseOptionConversionException(name, value, type.getSimpleName());
}
}
airline-0.7/src/main/java/io/airlift/airline/UsageHelper.java 0000664 0000000 0000000 00000013421 12426741743 0024205 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import io.airlift.airline.model.ArgumentsMetadata;
import io.airlift.airline.model.CommandMetadata;
import io.airlift.airline.model.OptionMetadata;
import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static io.airlift.airline.model.OptionMetadata.isHiddenPredicate;
public class UsageHelper
{
public static final Comparator DEFAULT_OPTION_COMPARATOR = new Comparator()
{
@Override
public int compare(OptionMetadata o1, OptionMetadata o2)
{
String option1 = o1.getOptions().iterator().next();
option1 = option1.replaceFirst("^-+", "");
String option2 = o2.getOptions().iterator().next();
option2 = option2.replaceFirst("^-+", "");
return ComparisonChain.start()
.compare(option1.toLowerCase(), option2.toLowerCase())
.compare(option2, option1) // print lower case letters before upper case
.compare(System.identityHashCode(o1), System.identityHashCode(o2))
.result();
}
};
public static final Comparator DEFAULT_COMMAND_COMPARATOR = new Comparator()
{
@Override
public int compare(CommandMetadata o1, CommandMetadata o2)
{
return ComparisonChain.start()
.compare(o1.getName().toLowerCase(), o2.getName().toLowerCase())
.compare(o2.getName(), o1.getName()) // print lower case letters before upper case
.compare(System.identityHashCode(o1), System.identityHashCode(o2))
.result();
}
};
public static String toDescription(OptionMetadata option)
{
Set options = option.getOptions();
StringBuilder stringBuilder = new StringBuilder();
final String argumentString;
if (option.getArity() > 0) {
argumentString = Joiner.on(" ").join(Lists.transform(ImmutableList.of(option.getTitle()), new Function()
{
public String apply(@Nullable String argument)
{
return "<" + argument + ">";
}
}));
} else {
argumentString = null;
}
Joiner.on(", ").appendTo(stringBuilder, transform(options, new Function()
{
public String apply(@Nullable String option)
{
if (argumentString != null) {
return option + " " + argumentString;
}
return option;
}
}));
return stringBuilder.toString();
}
public static String toDescription(ArgumentsMetadata arguments)
{
if (!arguments.getUsage().isEmpty()) {
return arguments.getUsage();
}
return "<" + arguments.getTitle() + ">";
}
public static String toUsage(OptionMetadata option)
{
Set options = option.getOptions();
boolean required = option.isRequired();
StringBuilder stringBuilder = new StringBuilder();
if (!required) {
stringBuilder.append('[');
}
if (options.size() > 1) {
stringBuilder.append('(');
}
final String argumentString;
if (option.getArity() > 0) {
argumentString = Joiner.on(" ").join(transform(ImmutableList.of(option.getTitle()), new Function()
{
public String apply(@Nullable String argument)
{
return "<" + argument + ">";
}
}));
}
else {
argumentString = null;
}
Joiner.on(" | ").appendTo(stringBuilder, transform(options, new Function()
{
public String apply(@Nullable String option)
{
if (argumentString != null) {
return option + " " + argumentString;
}
else {
return option;
}
}
}));
if (options.size() > 1) {
stringBuilder.append(')');
}
if (option.isMultiValued()) {
stringBuilder.append("...");
}
if (!required) {
stringBuilder.append(']');
}
return stringBuilder.toString();
}
public static String toUsage(ArgumentsMetadata arguments)
{
if (!arguments.getUsage().isEmpty()) {
return arguments.getUsage();
}
boolean required = arguments.isRequired();
StringBuilder stringBuilder = new StringBuilder();
if (!required) {
stringBuilder.append('[');
}
stringBuilder.append("<").append(arguments.getTitle()).append(">");
if (arguments.isMultiValued()) {
stringBuilder.append("...");
}
if (!required) {
stringBuilder.append(']');
}
return stringBuilder.toString();
}
public static List toSynopsisUsage(List options)
{
return ImmutableList.copyOf(transform(filter(options, isHiddenPredicate()), new Function()
{
public String apply(OptionMetadata option)
{
return toUsage(option);
}
}));
}
}
airline-0.7/src/main/java/io/airlift/airline/UsagePrinter.java 0000664 0000000 0000000 00000007411 12426741743 0024413 0 ustar 00root root 0000000 0000000 package io.airlift.airline;
import com.google.common.base.Splitter;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static com.google.common.collect.Lists.newArrayList;
public class UsagePrinter
{
private final StringBuilder out;
private final int maxSize;
private final int indent;
private final int hangingIndent;
private final AtomicInteger currentPosition;
public UsagePrinter(StringBuilder out)
{
this(out, 79);
}
public UsagePrinter(StringBuilder out, int maxSize)
{
this(out, maxSize, 0, 0, new AtomicInteger());
}
public UsagePrinter(StringBuilder out, int maxSize, int indent, int hangingIndent, AtomicInteger currentPosition)
{
this.out = out;
this.maxSize = maxSize;
this.indent = indent;
this.hangingIndent = hangingIndent;
this.currentPosition = currentPosition;
}
public UsagePrinter newIndentedPrinter(int size)
{
return new UsagePrinter(out, maxSize, indent + size, hangingIndent, currentPosition);
}
public UsagePrinter newPrinterWithHangingIndent(int size)
{
return new UsagePrinter(out, maxSize, indent, hangingIndent + size, currentPosition);
}
public UsagePrinter newline()
{
out.append("\n");
currentPosition.set(0);
return this;
}
public UsagePrinter appendTable(Iterable extends Iterable> table)
{
List columnSizes = newArrayList();
for (Iterable row : table) {
int column = 0;
for (String value : row) {
while (column >= columnSizes.size()) {
columnSizes.add(0);
}
columnSizes.set(column, Math.max(value.length(), columnSizes.get(column)));
column++;
}
}
if (currentPosition.get() != 0) {
currentPosition.set(0);
out.append("\n");
}
for (Iterable row : table) {
int column = 0;
StringBuilder line = new StringBuilder();
for (String value : row) {
int columnSize = columnSizes.get(column);
line.append(value);
line.append(spaces(columnSize - value.length()));
line.append(" ");
column++;
}
out.append(spaces(indent)).append(line.toString().trim()).append("\n");
}
return this;
}
public UsagePrinter append(String value)
{
if (value == null) {
return this;
}
return appendWords(Splitter.onPattern("\\s+").omitEmptyStrings().trimResults().split(String.valueOf(value)));
}
public UsagePrinter appendWords(Iterable words)
{
for (String word : words) {
if (currentPosition.get() == 0) {
// beginning of line
out.append(spaces(indent));
currentPosition.getAndAdd((indent));
}
else if (word.length() > maxSize || currentPosition.get() + word.length() <= maxSize) {
// between words
out.append(" ");
currentPosition.getAndIncrement();
}
else {
// wrap line
out.append("\n").append(spaces(indent)).append(spaces(hangingIndent));
currentPosition.set(indent);
}
out.append(word);
currentPosition.getAndAdd((word.length()));
}
return this;
}
private static String spaces(int count)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < count; i++) {
result.append(" ");
}
return result.toString();
}
}
airline-0.7/src/main/java/io/airlift/airline/model/ 0000775 0000000 0000000 00000000000 12426741743 0022235 5 ustar 00root root 0000000 0000000 airline-0.7/src/main/java/io/airlift/airline/model/ArgumentsMetadata.java 0000664 0000000 0000000 00000007570 12426741743 0026517 0 ustar 00root root 0000000 0000000 package io.airlift.airline.model;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import io.airlift.airline.Accessor;
import java.lang.reflect.Field;
import java.util.Set;
import static com.google.common.collect.Sets.newHashSet;
public class ArgumentsMetadata
{
private final String title;
private final String description;
private final String usage;
private final boolean required;
private final Set accessors;
public ArgumentsMetadata(String title, String description, String usage, boolean required, Iterable path)
{
Preconditions.checkNotNull(title, "title is null");
Preconditions.checkNotNull(path, "path is null");
Preconditions.checkArgument(!Iterables.isEmpty(path), "path is empty");
this.title = title;
this.description = description;
this.usage = usage;
this.required = required;
this.accessors = ImmutableSet.of(new Accessor(path));
}
public ArgumentsMetadata(Iterable arguments)
{
Preconditions.checkNotNull(arguments, "arguments is null");
Preconditions.checkArgument(!Iterables.isEmpty(arguments), "arguments is empty");
ArgumentsMetadata first = arguments.iterator().next();
this.title = first.title;
this.description = first.description;
this.usage = first.usage;
this.required = first.required;
Set accessors = newHashSet();
for (ArgumentsMetadata other : arguments) {
Preconditions.checkArgument(first.equals(other),
"Conflicting arguments definitions: %s, %s", first, other);
accessors.addAll(other.getAccessors());
}
this.accessors = ImmutableSet.copyOf(accessors);
}
public String getTitle()
{
return title;
}
public String getDescription()
{
return description;
}
public String getUsage()
{
return usage;
}
public boolean isRequired()
{
return required;
}
public Set getAccessors()
{
return accessors;
}
public boolean isMultiValued()
{
return accessors.iterator().next().isMultiValued();
}
public Class> getJavaType()
{
return accessors.iterator().next().getJavaType();
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ArgumentsMetadata that = (ArgumentsMetadata) o;
if (required != that.required) {
return false;
}
if (description != null ? !description.equals(that.description) : that.description != null) {
return false;
}
if (!title.equals(that.title)) {
return false;
}
if (usage != null ? !usage.equals(that.usage) : that.usage != null) {
return false;
}
return true;
}
@Override
public int hashCode()
{
int result = title.hashCode();
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (usage != null ? usage.hashCode() : 0);
result = 31 * result + (required ? 1 : 0);
return result;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("ArgumentsMetadata");
sb.append("{title='").append(title).append('\'');
sb.append(", description='").append(description).append('\'');
sb.append(", usage='").append(usage).append('\'');
sb.append(", required=").append(required);
sb.append(", accessors=").append(accessors);
sb.append('}');
return sb.toString();
}
}
airline-0.7/src/main/java/io/airlift/airline/model/CommandGroupMetadata.java 0000664 0000000 0000000 00000003706 12426741743 0027142 0 ustar 00root root 0000000 0000000 package io.airlift.airline.model;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class CommandGroupMetadata
{
private final String name;
private final String description;
private final List options;
private final CommandMetadata defaultCommand;
private final List commands;
public CommandGroupMetadata(String name, String description, Iterable options, CommandMetadata defaultCommand, Iterable commands)
{
this.name = name;
this.description = description;
this.options = ImmutableList.copyOf(options);
this.defaultCommand = defaultCommand;
this.commands = ImmutableList.copyOf(commands);
}
public String getName()
{
return name;
}
public String getDescription()
{
return description;
}
public List getOptions()
{
return options;
}
public CommandMetadata getDefaultCommand()
{
return defaultCommand;
}
public List getCommands()
{
return commands;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("CommandGroupMetadata");
sb.append("{name='").append(name).append('\'');
sb.append(", description='").append(description).append('\'');
sb.append(", options=").append(options);
sb.append(", defaultCommand=").append(defaultCommand);
sb.append(", commands=").append(commands);
sb.append('}');
return sb.toString();
}
public static Function nameGetter()
{
return new Function()
{
public String apply(CommandGroupMetadata input)
{
return input.getName();
}
};
}
}
airline-0.7/src/main/java/io/airlift/airline/model/CommandMetadata.java 0000664 0000000 0000000 00000006346 12426741743 0026130 0 ustar 00root root 0000000 0000000 package io.airlift.airline.model;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import io.airlift.airline.Accessor;
import java.util.List;
public class CommandMetadata
{
private final String name;
private final String description;
private final boolean hidden;
private final List globalOptions;
private final List groupOptions;
private final List commandOptions;
private final ArgumentsMetadata arguments;
private final List metadataInjections;
private final Class> type;
public CommandMetadata(String name,
String description,
boolean hidden, Iterable globalOptions,
Iterable groupOptions,
Iterable commandOptions,
ArgumentsMetadata arguments,
Iterable metadataInjections,
Class> type)
{
this.name = name;
this.description = description;
this.hidden = hidden;
this.globalOptions = ImmutableList.copyOf(globalOptions);
this.groupOptions = ImmutableList.copyOf(groupOptions);
this.commandOptions = ImmutableList.copyOf(commandOptions);
this.arguments = arguments;
this.metadataInjections = ImmutableList.copyOf(metadataInjections);
this.type = type;
}
public String getName()
{
return name;
}
public String getDescription()
{
return description;
}
public boolean isHidden()
{
return hidden;
}
public List getAllOptions()
{
return ImmutableList.builder().addAll(globalOptions).addAll(groupOptions).addAll(commandOptions).build();
}
public List getGlobalOptions()
{
return globalOptions;
}
public List getGroupOptions()
{
return groupOptions;
}
public List getCommandOptions()
{
return commandOptions;
}
public ArgumentsMetadata getArguments()
{
return arguments;
}
public List getMetadataInjections()
{
return metadataInjections;
}
public Class> getType()
{
return type;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("CommandMetadata");
sb.append("{name='").append(name).append('\'');
sb.append(", description='").append(description).append('\'');
sb.append(", globalOptions=").append(globalOptions);
sb.append(", groupOptions=").append(groupOptions);
sb.append(", commandOptions=").append(commandOptions);
sb.append(", arguments=").append(arguments);
sb.append(", metadataInjections=").append(metadataInjections);
sb.append(", type=").append(type);
sb.append('}');
return sb.toString();
}
public static Function nameGetter()
{
return new Function()
{
public String apply(CommandMetadata input)
{
return input.getName();
}
};
}
}
airline-0.7/src/main/java/io/airlift/airline/model/GlobalMetadata.java 0000664 0000000 0000000 00000004121 12426741743 0025737 0 ustar 00root root 0000000 0000000 package io.airlift.airline.model;
import com.google.common.collect.ImmutableList;
import java.util.List;
public class GlobalMetadata
{
private final String name;
private final String description;
private final List options;
private final CommandMetadata defaultCommand;
private final List defaultGroupCommands;
private final List commandGroups;
public GlobalMetadata(String name,
String description,
Iterable options,
CommandMetadata defaultCommand,
Iterable defaultGroupCommands,
Iterable commandGroups)
{
this.name = name;
this.description = description;
this.options = ImmutableList.copyOf(options);
this.defaultCommand = defaultCommand;
this.defaultGroupCommands = ImmutableList.copyOf(defaultGroupCommands);
this.commandGroups = ImmutableList.copyOf(commandGroups);
}
public String getName()
{
return name;
}
public String getDescription()
{
return description;
}
public List getOptions()
{
return options;
}
public CommandMetadata getDefaultCommand()
{
return defaultCommand;
}
public List getDefaultGroupCommands()
{
return defaultGroupCommands;
}
public List getCommandGroups()
{
return commandGroups;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
sb.append("GlobalMetadata");
sb.append("{name='").append(name).append('\'');
sb.append(", description='").append(description).append('\'');
sb.append(", options=").append(options);
sb.append(", defaultCommand=").append(defaultCommand);
sb.append(", defaultGroupCommands=").append(defaultGroupCommands);
sb.append(", commandGroups=").append(commandGroups);
sb.append('}');
return sb.toString();
}
}
airline-0.7/src/main/java/io/airlift/airline/model/MetadataLoader.java 0000664 0000000 0000000 00000025755 12426741743 0025765 0 ustar 00root root 0000000 0000000 package io.airlift.airline.model;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import io.airlift.airline.Accessor;
import io.airlift.airline.Arguments;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import io.airlift.airline.OptionType;
import io.airlift.airline.Suggester;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
public class MetadataLoader
{
public static GlobalMetadata loadGlobal(String name,
String description,
CommandMetadata defaultCommand,
Iterable defaultGroupCommands,
Iterable groups)
{
ImmutableList.Builder globalOptionsBuilder = ImmutableList.builder();
if (defaultCommand != null) {
globalOptionsBuilder.addAll(defaultCommand.getGlobalOptions());
}
for (CommandMetadata command : defaultGroupCommands) {
globalOptionsBuilder.addAll(command.getGlobalOptions());
}
for (CommandGroupMetadata group : groups) {
for (CommandMetadata command : group.getCommands()) {
globalOptionsBuilder.addAll(command.getGlobalOptions());
}
}
List globalOptions = mergeOptionSet(globalOptionsBuilder.build());
return new GlobalMetadata(name, description, globalOptions, defaultCommand, defaultGroupCommands, groups);
}
public static CommandGroupMetadata loadCommandGroup(String name, String description, CommandMetadata defaultCommand, Iterable commands)
{
ImmutableList.Builder groupOptionsBuilder = ImmutableList.builder();
if (defaultCommand != null) {
groupOptionsBuilder.addAll(defaultCommand.getGroupOptions());
}
for (CommandMetadata command : commands) {
groupOptionsBuilder.addAll(command.getGroupOptions());
}
List groupOptions = mergeOptionSet(groupOptionsBuilder.build());
return new CommandGroupMetadata(name, description, groupOptions, defaultCommand, commands);
}
public static ImmutableList loadCommands(Iterable> defaultCommands)
{
return ImmutableList.copyOf(Iterables.transform(defaultCommands, new Function, CommandMetadata>()
{
public CommandMetadata apply(Class> commandType)
{
return loadCommand(commandType);
}
}));
}
public static CommandMetadata loadCommand(Class> commandType)
{
Command command = null;
for (Class> cls = commandType; command == null && !Object.class.equals(cls); cls = cls.getSuperclass()) {
command = cls.getAnnotation(Command.class);
}
Preconditions.checkArgument(command != null, "Command %s is not annotated with @Command", commandType.getName());
String name = command.name();
String description = command.description().isEmpty() ? null : command.description();
boolean hidden = command.hidden();
InjectionMetadata injectionMetadata = loadInjectionMetadata(commandType);
CommandMetadata commandMetadata = new CommandMetadata(
name,
description,
hidden, injectionMetadata.globalOptions,
injectionMetadata.groupOptions,
injectionMetadata.commandOptions,
Iterables.getFirst(injectionMetadata.arguments, null),
injectionMetadata.metadataInjections,
commandType);
return commandMetadata;
}
public static SuggesterMetadata loadSuggester(Class extends Suggester> suggesterClass)
{
InjectionMetadata injectionMetadata = loadInjectionMetadata(suggesterClass);
return new SuggesterMetadata(suggesterClass, injectionMetadata.metadataInjections);
}
public static InjectionMetadata loadInjectionMetadata(Class> type)
{
InjectionMetadata injectionMetadata = new InjectionMetadata();
loadInjectionMetadata(type, injectionMetadata, ImmutableList.of());
injectionMetadata.compact();
return injectionMetadata;
}
public static void loadInjectionMetadata(Class> type, InjectionMetadata injectionMetadata, List fields)
{
for (Class> cls = type; !Object.class.equals(cls); cls = cls.getSuperclass()) {
for (Field field : cls.getDeclaredFields()) {
field.setAccessible(true);
ImmutableList path = concat(fields, field);
Inject injectAnnotation = field.getAnnotation(Inject.class);
if (injectAnnotation != null) {
if (field.getType().equals(GlobalMetadata.class) ||
field.getType().equals(CommandGroupMetadata.class) ||
field.getType().equals(CommandMetadata.class)) {
injectionMetadata.metadataInjections.add(new Accessor(path));
} else {
loadInjectionMetadata(field.getType(), injectionMetadata, path);
}
}
Option optionAnnotation = field.getAnnotation(Option.class);
if (optionAnnotation != null) {
OptionType optionType = optionAnnotation.type();
String name;
if (!optionAnnotation.title().isEmpty()) {
name = optionAnnotation.title();
}
else {
name = field.getName();
}
List