forked from loafle/openapi-generator-original
[cli] Completions command for suggestions (#213)
* [cli] Completions command for suggestions This takes airlift's 'suggest' command and reuses it as a different command name, 'completion'. This gives us in-built CLI completions which are useful in the repo-level container's docker-entrypoint.sh. This previously parsed Java files for conventional usage of Command annotations, which is potentially buggy. The new implementation relies only on CLI to provide command completion suggestions. As part of this, we can prepare for bash completion scripts which can be added to our homebrew formula. The new completion command will also complete on command options, for example: cli completion generate This will provide all short and long form switches available to the generate command. * Add piggyback license onto licensed of file borrowed from airlift/airline
This commit is contained in:
parent
43b60e667e
commit
640fd87e3b
@ -8,11 +8,19 @@ JAVA_OPTS=${JAVA_OPTS:-"-Xmx1024M -DloggerPath=conf/log4j.properties"}
|
|||||||
|
|
||||||
cli="${GEN_DIR}/modules/openapi-generator-cli"
|
cli="${GEN_DIR}/modules/openapi-generator-cli"
|
||||||
codegen="${cli}/target/openapi-generator-cli.jar"
|
codegen="${cli}/target/openapi-generator-cli.jar"
|
||||||
cmdsrc="${cli}/src/main/java/org/openapitools/codegen/cmd"
|
|
||||||
|
|
||||||
pattern="@Command(name = \"$1\""
|
# We code in a list of commands here as source processing is potentially buggy (requires undocumented conventional use of annotations).
|
||||||
if expr "x$1" : 'x[a-z][a-z-]*$' > /dev/null && fgrep -qe "$pattern" "$cmdsrc"/*.java || expr "$1" = 'help' > /dev/null; then
|
# A list of known commands helps us determine if we should compile CLI. There's an edge-case where a new command not added to this
|
||||||
# If ${GEN_DIR} has been mapped elsewhere from default, and that location has not been built
|
# list won't be considered a "real" command. We can get around that a bit by checking CLI completions beforehand if it exists.
|
||||||
|
commands="list,generate,meta,langs,help,config-help,validate,version"
|
||||||
|
|
||||||
|
# if CLI jar exists, check $1 against completions available in the CLI
|
||||||
|
if [[ -f "${codegen}" && -n "$(java ${JAVA_OPTS} -jar "${codegen}" completion | grep "^$1\$" )" ]]; then
|
||||||
|
command=$1
|
||||||
|
shift
|
||||||
|
exec java ${JAVA_OPTS} -jar "${codegen}" "${command}" "$@"
|
||||||
|
elif [[ -n "$(echo commands | tr ',' '\n' | grep "^$1\$" )" ]]; then
|
||||||
|
# If CLI jar does not exist, and $1 is a known CLI command, build the CLI jar and run that command.
|
||||||
if [[ ! -f "${codegen}" ]]; then
|
if [[ ! -f "${codegen}" ]]; then
|
||||||
(cd "${GEN_DIR}" && exec mvn -am -pl "modules/openapi-generator-cli" -Duser.home=$(dirname $MAVEN_CONFIG) package)
|
(cd "${GEN_DIR}" && exec mvn -am -pl "modules/openapi-generator-cli" -Duser.home=$(dirname $MAVEN_CONFIG) package)
|
||||||
fi
|
fi
|
||||||
@ -20,5 +28,6 @@ if expr "x$1" : 'x[a-z][a-z-]*$' > /dev/null && fgrep -qe "$pattern" "$cmdsrc"/*
|
|||||||
shift
|
shift
|
||||||
exec java ${JAVA_OPTS} -jar "${codegen}" "${command}" "$@"
|
exec java ${JAVA_OPTS} -jar "${codegen}" "${command}" "$@"
|
||||||
else
|
else
|
||||||
|
# Pass args as linux commands. This allows us to do something like: docker run -it (-e…, -v…) image ls -la
|
||||||
exec "$@"
|
exec "$@"
|
||||||
fi
|
fi
|
||||||
|
@ -23,8 +23,6 @@ import io.airlift.airline.ParseOptionMissingException;
|
|||||||
import io.airlift.airline.ParseOptionMissingValueException;
|
import io.airlift.airline.ParseOptionMissingValueException;
|
||||||
import org.openapitools.codegen.cmd.*;
|
import org.openapitools.codegen.cmd.*;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: lanwen Date: 24.03.15 Time: 17:56
|
* User: lanwen Date: 24.03.15 Time: 17:56
|
||||||
* <p>
|
* <p>
|
||||||
@ -52,10 +50,15 @@ public class OpenAPIGenerator {
|
|||||||
Help.class,
|
Help.class,
|
||||||
ConfigHelp.class,
|
ConfigHelp.class,
|
||||||
Validate.class,
|
Validate.class,
|
||||||
Version.class
|
Version.class,
|
||||||
|
CompletionCommand.class
|
||||||
);
|
);
|
||||||
|
|
||||||
// If CLI is run without a command, consider this an error.
|
try {
|
||||||
|
builder.build().parse(args).run();
|
||||||
|
|
||||||
|
// If CLI is run without a command, consider this an error. This exists after initial parse/run
|
||||||
|
// so we can present the configured "default command".
|
||||||
// We can check against empty args because unrecognized arguments/commands result in an exception.
|
// We can check against empty args because unrecognized arguments/commands result in an exception.
|
||||||
// This is useful to exit with status 1, for example, so that misconfigured scripts fail fast.
|
// This is useful to exit with status 1, for example, so that misconfigured scripts fail fast.
|
||||||
// We don't want the default command to exit internally with status 1 because when the default command is something like "list",
|
// We don't want the default command to exit internally with status 1 because when the default command is something like "list",
|
||||||
@ -64,9 +67,6 @@ public class OpenAPIGenerator {
|
|||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
builder.build().parse(args).run();
|
|
||||||
} catch (ParseOptionMissingException | ParseOptionMissingValueException e) {
|
} catch (ParseOptionMissingException | ParseOptionMissingValueException e) {
|
||||||
System.err.printf("[error] %s%n", e.getMessage());
|
System.err.printf("[error] %s%n", e.getMessage());
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 the original author or authors.
|
||||||
|
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* NOTICE: File originally taken from:
|
||||||
|
* https://github.com/airlift/airline/blob/fc7a55e34b6361cb97235de5a1b21cba9b508f4b/src/main/java/io/airlift/airline/SuggestCommand.java#L1
|
||||||
|
* Modifications have been made to fit the needs of OpenAPI Tools CLI.
|
||||||
|
*/
|
||||||
|
package org.openapitools.codegen.cmd;
|
||||||
|
|
||||||
|
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.*;
|
||||||
|
import io.airlift.airline.model.*;
|
||||||
|
|
||||||
|
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 = "completion", description = "Complete commands (for using in tooling such as Bash Completions).", hidden = true)
|
||||||
|
public class CompletionCommand
|
||||||
|
implements Runnable, Callable<Void> {
|
||||||
|
private static final Map<Context, Class<? extends Suggester>> BUILTIN_SUGGESTERS = ImmutableMap.<Context, Class<? extends Suggester>>builder()
|
||||||
|
.put(Context.GLOBAL, GlobalSuggester.class)
|
||||||
|
.put(Context.GROUP, GroupSuggester.class)
|
||||||
|
.put(Context.COMMAND, CommandSuggester.class)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public GlobalMetadata metadata;
|
||||||
|
|
||||||
|
@Arguments
|
||||||
|
public List<String> arguments = newArrayList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void call() {
|
||||||
|
run();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public Iterable<String> 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<Class<?>, Object> bindings = ImmutableMap.<Class<?>, 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.<OptionMetadata>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()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user