improve unrecognized command error

This commit is contained in:
Jonathan Shook 2022-07-26 01:15:06 -05:00
parent c20261bceb
commit bc63a28426
6 changed files with 136 additions and 88 deletions

View File

@ -16,7 +16,9 @@
package io.nosqlbench.docsys.core;
import io.nosqlbench.api.spi.BundledApp;
import io.nosqlbench.docsys.endpoints.DocsysMarkdownEndpoint;
import io.nosqlbench.nb.annotations.Service;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -27,24 +29,12 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
public class NBWebServerApp {
@Service(value=NBWebServerApp.class,selector="appserver")
public class NBWebServerApp implements BundledApp {
private static final Logger logger = LogManager.getLogger(NBWebServerApp.class);
public static void main(String[] args) {
if (args.length > 0 && args[0].contains("help")) {
showHelp();
} else if (args.length > 0 && args[0].contains("generate")) {
try {
String[] genargs = Arrays.copyOfRange(args, 1, args.length);
logger.info("Generating with args [" + String.join("][", args) + "]");
generate(genargs);
} catch (IOException e) {
logger.error("could not generate files with command " + String.join(" ", args));
e.printStackTrace();
}
} else {
runServer(args);
}
new NBWebServerApp().appMain(args);
}
private static boolean deleteDirectory(File directoryToBeDeleted) {
@ -152,4 +142,23 @@ public class NBWebServerApp {
private static void listTopics() {
}
@Override
public int appMain(String[] args) {
if (args.length > 0 && args[0].contains("help")) {
showHelp();
} else if (args.length > 0 && args[0].contains("generate")) {
try {
String[] genargs = Arrays.copyOfRange(args, 1, args.length);
logger.info("Generating with args [" + String.join("][", args) + "]");
generate(genargs);
} catch (IOException e) {
logger.error("could not generate files with command " + String.join(" ", args));
e.printStackTrace();
}
} else {
runServer(args);
}
return 0;
}
}

View File

@ -16,14 +16,21 @@
package io.nosqlbench.engine.cli;
import io.nosqlbench.api.docsapi.docexporter.BundledMarkdownExporter;
import io.nosqlbench.docsys.core.NBWebServerApp;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
import io.nosqlbench.api.content.Content;
import io.nosqlbench.api.content.NBIO;
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
import io.nosqlbench.api.errors.BasicError;
import io.nosqlbench.api.logging.NBLogLevel;
import io.nosqlbench.api.metadata.SessionNamer;
import io.nosqlbench.api.metadata.SystemId;
import io.nosqlbench.api.spi.BundledApp;
import io.nosqlbench.engine.api.activityapi.cyclelog.outputs.cyclelog.CycleLogDumperUtility;
import io.nosqlbench.engine.api.activityapi.cyclelog.outputs.cyclelog.CycleLogImporterUtility;
import io.nosqlbench.engine.api.activityapi.input.InputType;
import io.nosqlbench.engine.api.activityapi.output.OutputType;
import io.nosqlbench.engine.api.activityconfig.rawyaml.RawStmtsLoader;
import io.nosqlbench.api.engine.metrics.ActivityMetrics;
import io.nosqlbench.engine.core.annotation.Annotators;
import io.nosqlbench.engine.core.lifecycle.*;
import io.nosqlbench.engine.core.logging.LoggerConfig;
@ -35,16 +42,8 @@ import io.nosqlbench.engine.core.script.ScenariosExecutor;
import io.nosqlbench.engine.core.script.ScriptParams;
import io.nosqlbench.engine.docker.DockerMetricsManager;
import io.nosqlbench.nb.annotations.Maturity;
import io.nosqlbench.api.annotations.Annotation;
import io.nosqlbench.api.annotations.Layer;
import io.nosqlbench.api.content.Content;
import io.nosqlbench.api.content.NBIO;
import io.nosqlbench.api.errors.BasicError;
import io.nosqlbench.api.logging.NBLogLevel;
import io.nosqlbench.api.markdown.exporter.MarkdownExporter;
import io.nosqlbench.api.metadata.SessionNamer;
import io.nosqlbench.api.metadata.SystemId;
import io.nosqlbench.virtdata.userlibs.apps.VirtDataMainApp;
import io.nosqlbench.nb.annotations.Service;
import io.nosqlbench.nb.annotations.ServiceSelector;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
@ -53,15 +52,10 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -178,6 +172,20 @@ public class NBCLI implements Function<String[], Integer> {
logger.info("command-line: " + Arrays.stream(args).collect(Collectors.joining(" ")));
logger.info("client-hardware: " + SystemId.getHostSummary());
// Invoke any bundled app which matches the name of the first non-option argument, if it exists.
// If it does not, continue with no fanfare. Let it drop through to other command resolution methods.
if (args.length>0 && args[0].matches("\\w[\\w\\d-_.]+")) {
ServiceSelector<BundledApp> apploader = ServiceSelector.of(args[0], ServiceLoader.load(BundledApp.class));
BundledApp app = apploader.get().orElse(null);
if (app!=null) {
String[] appargs = Arrays.copyOfRange(args, 1, args.length);
logger.info("invoking bundled app '" + args[0] + "' (" + app.getClass().getSimpleName() + ").");
int result = app.appMain(appargs);
return result;
}
}
boolean dockerMetrics = globalOptions.wantsDockerMetrics();
String dockerMetricsAt = globalOptions.wantsDockerMetricsAt();
String reportGraphiteTo = globalOptions.wantsReportGraphiteTo();
@ -226,40 +234,6 @@ public class NBCLI implements Function<String[], Integer> {
annotatorsConfig = "[{type:'log',level:'info'}]";
}
if (args.length > 0 && args[0].toLowerCase().equals("cqlgen")) {
String exporterImpl = "io.nosqlbench.cqlgen.exporter.CGWorkloadExporter";
String[] exporterArgs = Arrays.copyOfRange(args, 1, args.length);
try {
Class<?> genclass = Class.forName(exporterImpl);
Method main = genclass.getMethod("main", new String[0].getClass());
Object result = main.invoke(null, new Object[]{exporterArgs});
} catch (ClassNotFoundException e) {
throw new RuntimeException("cql workload exporter implementation " + exporterImpl + " was not found in this runtime.");
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
System.out.println("Error in app: " + e.toString());
e.printStackTrace();
throw new RuntimeException("error while invoking " + exporterImpl + ": " + e.toString(),e);
}
return EXIT_OK;
}
if (args.length > 0 && args[0].toLowerCase().equals("export-docs")) {
BundledMarkdownExporter.main(Arrays.copyOfRange(args,1,args.length));
return EXIT_OK;
}
if (args.length > 0 && args[0].toLowerCase().equals("virtdata")) {
VirtDataMainApp.main(Arrays.copyOfRange(args, 1, args.length));
return EXIT_OK;
}
if (args.length > 0 && args[0].toLowerCase().matches("docserver|appserver")) {
NBWebServerApp.main(Arrays.copyOfRange(args, 1, args.length));
return EXIT_OK;
}
if (args.length > 0 && args[0].toLowerCase().equals(MarkdownExporter.APP_NAME)
) {
MarkdownExporter.main(Arrays.copyOfRange(args, 1, args.length));
return EXIT_OK;
}
NBCLIOptions options = new NBCLIOptions(args);
logger = LogManager.getLogger("NBCLI");
@ -282,6 +256,20 @@ public class NBCLI implements Function<String[], Integer> {
return EXIT_OK;
}
if (options.isWantsListApps()) {
ServiceLoader<BundledApp> loader = ServiceLoader.load(BundledApp.class);
for (ServiceLoader.Provider<BundledApp> provider : loader.stream().toList()) {
Class<? extends BundledApp> appType = provider.type();
String name = appType.getAnnotation(Service.class).selector();
System.out.println(String.format("%-40s %s",name,appType.getCanonicalName()));
}
return EXIT_OK;
}
if (options.getWantsListCommands()) {
NBCLICommandParser.RESERVED_WORDS.forEach(System.out::println);
return EXIT_OK;
}
if (options.wantsActivityTypes()) {
new ActivityTypeLoader().getAllSelectors().forEach(System.out::println);
return EXIT_OK;
@ -297,7 +285,7 @@ public class NBCLI implements Function<String[], Integer> {
return EXIT_OK;
}
if (options.wantsScriptList()) {
if (options.wantsListScripts()) {
NBCLIScripts.printScripts(true, options.wantsIncludes());
return EXIT_OK;
}

View File

@ -16,14 +16,19 @@
package io.nosqlbench.engine.cli;
import io.nosqlbench.engine.api.scenarios.NBCLIScenarioParser;
import io.nosqlbench.api.content.Content;
import io.nosqlbench.api.content.NBIO;
import io.nosqlbench.engine.api.scenarios.NBCLIScenarioParser;
import java.security.InvalidParameterException;
import java.util.*;
/**
* This parser will return a non-empty optional if there is no error.
* If the optional is empty, then it means some part of the command structure
* was not recognized.
*/
public class NBCLICommandParser {
private static final String FRAGMENT = "fragment";
private static final String SCRIPT = "script";
private static final String START = "start";
@ -37,21 +42,20 @@ public class NBCLICommandParser {
public static final Set<String> RESERVED_WORDS = new HashSet<>() {{
addAll(
Arrays.asList(
SCRIPT, ACTIVITY, SCENARIO, RUN, START,
FRAGMENT, STOP, AWAIT, WAIT_MILLIS
FRAGMENT, SCRIPT, START, RUN, AWAIT, STOP, ACTIVITY, SCENARIO, WAIT_MILLIS
)
);
}};
public static void parse(
public static Optional<List<Cmd>> parse(
LinkedList<String> arglist,
LinkedList<Cmd> cmdList,
String... includes
) {
List<Cmd> cmdList = new LinkedList<>();
PathCanonicalizer canonicalizer = new PathCanonicalizer(includes);
while (arglist.peekFirst() != null) {
String word = arglist.peekFirst();
Cmd cmd = null;
Cmd cmd;
switch (word) {
case FRAGMENT:
case SCRIPT:
@ -80,11 +84,12 @@ public class NBCLICommandParser {
} else if (NBCLIScenarioParser.isFoundWorkload(word, includes)) {
NBCLIScenarioParser.parseScenarioCommand(arglist, RESERVED_WORDS, includes);
} else {
throw new InvalidParameterException("unrecognized option:" + word);
return Optional.empty();
}
break;
}
}
return Optional.of(cmdList);
}
}

View File

@ -61,6 +61,7 @@ public class NBCLIOptions {
// Discovery
private static final String HELP = "--help";
private static final String LIST_COMMANDS = "--list-commands";
private static final String LIST_METRICS = "--list-metrics";
private static final String LIST_DRIVERS = "--list-drivers";
private static final String LIST_ACTIVITY_TYPES = "--list-activity-types";
@ -69,6 +70,7 @@ public class NBCLIOptions {
private static final String LIST_SCENARIOS = "--list-scenarios";
private static final String LIST_INPUT_TYPES = "--list-input-types";
private static final String LIST_OUTPUT_TYPES = "--list-output-types";
private static final String LIST_APPS = "--list-apps";
private static final String VERSION_COORDS = "--version-coords";
private static final String VERSION = "--version";
private static final String SHOW_SCRIPT = "--show-script";
@ -128,7 +130,7 @@ public class NBCLIOptions {
// private static final String DEFAULT_CONSOLE_LOGGING_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
private final LinkedList<Cmd> cmdList = new LinkedList<>();
private final List<Cmd> cmdList = new ArrayList<>();
private int logsMax = 0;
private boolean wantsVersionShort = false;
private boolean wantsVersionCoords = false;
@ -160,8 +162,8 @@ public class NBCLIOptions {
private Map<String, String> logLevelsOverrides = new HashMap<>();
private boolean enableChart = false;
private boolean dockerMetrics = false;
private boolean wantsScenariosList = false;
private boolean wantsScriptList = false;
private boolean wantsListScenarios = false;
private boolean wantsListScripts = false;
private String wantsToCopyWorkload = null;
private boolean wantsWorkloadsList = false;
private final List<String> wantsToIncludePaths = new ArrayList<>();
@ -185,7 +187,16 @@ public class NBCLIOptions {
private boolean enableAnsi = System.getenv("TERM")!=null && !System.getenv("TERM").isEmpty();
private Maturity minMaturity = Maturity.Unspecified;
private String graphitelogLevel="info";
private boolean wantsListCommands = false;
private boolean wantsListApps = false;
public boolean isWantsListApps() {
return wantsListApps;
}
public boolean getWantsListCommands() {
return wantsListCommands;
}
public String getAnnotatorsConfig() {
return annotatorsConfig;
}
@ -517,6 +528,10 @@ public class NBCLIOptions {
arglist.removeFirst();
showScript = true;
break;
case LIST_COMMANDS:
arglist.removeFirst();
this.wantsListCommands = true;
break;
case LIST_METRICS:
arglist.removeFirst();
arglist.addFirst("start");
@ -596,16 +611,20 @@ public class NBCLIOptions {
break;
case LIST_SCENARIOS:
arglist.removeFirst();
wantsScenariosList = true;
wantsListScenarios = true;
break;
case LIST_SCRIPTS:
arglist.removeFirst();
wantsScriptList = true;
wantsListScripts = true;
break;
case LIST_WORKLOADS:
arglist.removeFirst();
wantsWorkloadsList = true;
break;
case LIST_APPS:
arglist.removeFirst();
wantsListApps= true;
break;
case SCRIPT_FILE:
arglist.removeFirst();
scriptFile = readWordOrThrow(arglist, "script file");
@ -619,7 +638,31 @@ public class NBCLIOptions {
}
}
arglist = nonincludes;
NBCLICommandParser.parse(arglist, cmdList);
Optional<List<Cmd>> commands = NBCLICommandParser.parse(arglist);
if (commands.isPresent()) {
this.cmdList.addAll(commands.get());
} else {
String arg = arglist.peekFirst();
Objects.requireNonNull(arg);
String helpmsg = """
Could not recognize command 'ARG'.
This means that all of the following searches for a compatible command failed:
1. commands: no scenario command named 'ARG' is known. (start, run, await, ...)
2. scripts: no auto script named './scripts/auto/ARG.js' in the local filesystem.
3. scripts: no auto script named 'scripts/auto/ARG.js' was found in the PROG binary.
4. workloads: no workload file named ARG[.yaml] was found in the local filesystem, even in include paths INCLUDES.
5. workloads: no workload file named ARG[.yaml] was bundled in PROG binary, even in include paths INCLUDES.
6. apps: no application named ARG was bundled in PROG.
You can discover available ways to invoke PROG by using the various --list-* commands:
[ --list-commands, --list-scripts, --list-workloads (and --list-scenarios), --list-apps ]
"""
.replaceAll("ARG",arg)
.replaceAll("PROG","nb5")
.replaceAll("INCLUDES", String.join(",",this.wantsIncludes()));
throw new BasicError(helpmsg);
}
}
@ -859,11 +902,11 @@ public class NBCLIOptions {
}
public boolean wantsScenariosList() {
return wantsScenariosList;
return wantsListScenarios;
}
public boolean wantsScriptList() {
return wantsScriptList;
public boolean wantsListScripts() {
return wantsListScripts;
}
public boolean wantsToCopyResource() {

View File

@ -205,7 +205,7 @@ public class TestNBCLIOptions {
@Test
public void listScripts() {
NBCLIOptions opts = new NBCLIOptions(new String[]{ "--list-scripts"});
assertThat(opts.wantsScriptList()).isTrue();
assertThat(opts.wantsListScripts()).isTrue();
}
@Test

View File

@ -122,7 +122,10 @@ public class ScenarioExecutorEndpoint implements WebServiceObject {
}
args = substituteFilenames(rq, args);
NBCLICommandParser.parse(args, cmdList, workspace.asIncludes());
Optional<List<Cmd>> parsed = NBCLICommandParser.parse(args, workspace.asIncludes());
if (!parsed.isPresent()) {
return Response.serverError().entity("Unable to render command stream from provided command spec.").build();
}
ScriptBuffer buffer = new BasicScriptBuffer();
buffer.add(cmdList.toArray(new Cmd[0]));