KivaKit command line analysis – Java Code Geeks

[ad_1]

The kivakit command line module provides the switch and argument parsing used by application-kivakit. Let’s see how it works. When an application starts (see KivaKit apps), the Application.run (String[] arguments) method uses the kivakit command line module to analyze the array of arguments passed to main (). Conceptually, this code looks like this:

public final void run(String[] arguments)
{
    onRunning();
    
    [...]

    commandLine = new CommandLineParser(this)
            .addSwitchParsers(switchParsers())
            .addArgumentParsers(argumentParsers())
            .parse(arguments);

In Course(), a AnalyzerLineOrder the instance is created and configured with the switch applications and analyzers argument, as returned by switchParsors () and argument analyzers () in our subclass of applications. Then when the parse (String[]) method is called, the command line is parsed. The resultant Command line the model is stored in Application, and is used later by our application to retrieve the values ​​of arguments and switches.

To analyse

An overview of the classes used in command line analysis can be seen in this abbreviated UML diagram:

The AnalyzerLineOrder class a references SwitchParserList And one ArgumentParserList. When he is parse (String[]) method is called, it uses these parsers to parse the switches and arguments of the given string array in a Switching list And one Argument list. Then it returns a Command line object populated with these values.

Note that all switches must be of the form -switch-name =[value]. If a string in the argument array is not of this form, it is considered an argument and not a switch.

Once a Command line has been successfully analyzed, it is available via Application.CommandLine (). The values ​​of specific arguments and switches can be retrieved via its to have() and argument() methods. The Application The class provides convenient methods for the call to command line() can often be omitted for brevity.

Example

In the example in KivaKit apps, the argument and switch parsers returned by the sample app were declared like this:

import static com.telenav.kivakit.commandline.SwitchParser.booleanSwitchParser;
import static com.telenav.kivakit.filesystem.File.fileArgumentParser;

[...]

private ArgumentParser<File> INPUT =
        fileArgumentParser("Input text file")
                .required()
                .build();

private SwitchParser<Boolean> SHOW_FILE_SIZE =
        booleanSwitchParser("show-file-size", "Show the file size in bytes")
                .optional()
                .defaultValue(false)
                .build();

The Application the subclass then provides these parsers to KivaKit like this:

@Override
protected List<ArgumentParser<?>> argumentParsers()
{
    return List.of(INPUT);
}

@Override
protected Set<SwitchParser<?>> switchParsers()
{
    return Set.of(SHOW_FILE_SIZE);
}

Then in onRun (), the input file is retrieved by calling the argument() method with the GRAB argument analyzer:

var input = argument(INPUT);

and the boolean switch SHOW_FILE_SIZE is accessible in the same way with to have():

if (get(SHOW_FILE_SIZE))
    {
        [...]
    }

This is all that is needed to do basic switch analysis in KivaKit.

But there are a few questions to ask yourself about how this all works. How are arguments and switches validated? How? ‘Or’ What KivaKit automatically provide command line help? And how do we define new SwitchParsersand ArgumentParsers?

Order line validation

The KivaKit validation mini-framework is used to validate switches and arguments. As shown in the diagram below, argument and switch validators are implemented in (private) classes ArgumentListValidator and SwitchListValidator, respectively. When arguments and switches are parsed by AnalyzerLineOrder these validators are used to ensure that the resulting parsed values ​​are valid.

For the list of switches, SwitchListValidator ensure that:

  1. No required switches are omitted
  2. No switch value is invalid (as determined by switch analyzer validation)
  3. No duplicate switch is present (this is not allowed)
  4. All switches present are recognized by a switch analyzer

For the list of arguments, ArgumentListValidator ensures that the number of arguments is acceptable. ArgumentParser.Builder can specify a quantifier for an argument parser by calling one of these methods:

public Builder<T> oneOrMore()
public Builder<T> optional()
public Builder<T> required()
public Builder<T> twoOrMore()
public Builder<T> zeroOrMore()

Argument parsers that accept more than one argument are allowed only at the end of the list of argument parsers returned by Application.argumentParsers (). For example, this code:

private static final ArgumentParser<Boolean> RECURSE =
        booleanArgumentParser("True to search recusively")
                .required()
                .build();

private static final ArgumentParser<Folder> ROOT_FOLDER =
        folderArgumentParser("Root folder(s) to search")
                .oneOrMore()
                .build();

[...]

@Override
protected List<ArgumentParser<?>> argumentParsers()
{
    return List.of(RECURSE, ROOT_FOLDER);
}

is valid and will parse command line arguments like this:

true /usr/bin /var /tmp

Here each root folder can be recovered with Application.argument (int index, ArgumentParser) passing in indices 1, 2 and 3.

However, it would be not be valid to return these two argument parsers in reverse order like this:

@Override
protected List<ArgumentParser<?>> argumentParsers()
{
    // NOT ALLOWED
    return List.of(ROOT_FOLDER, RECURSE);
}

since the ROOT_FOLDER parser must be the last in the list.

Command line help

Command line help for applications is provided automatically by KivaKit. For example, forgetting to pass the -deployment switch (more on deployments in a future article) to a server that is waiting for such a switch results in:

┏━━━━━━━━━━┫ COMMAND LINE ERROR(S) ┣━━━━━━━━━━┓
┋     ○ Required switch -deployment not found ┋
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
 
KivaKit 0.9.9-SNAPSHOT (beryllium gorilla)

Usage: DataServer 0.9.0-SNAPSHOT <switches> <arguments>

My cool data server.

Arguments:

  <none>

Switches:

  Required:

  -deployment=Deployment (required) : The deployment configuration to run

    ○ localpinot - Pinot on local host
    ○ development - Pinot on pinot-database.mypna.com
    ○ localtest - Test database on local host
  
  Optional:

  -port=Integer (optional, default: 8081) : The first port in the range of ports to be allocated
  -quiet=Boolean (optional, default: false) : Minimize output

Description comes from Application.description (), which we can replace in our application. Help for arguments and switches is generated from argument and switch analyzers based on their name, description, type, quantity, default, and list of valid values.

Creation of new switch and argument analyzers

Creating a new switch (or argument) analyzer is very easy if you have a KivaKit type converter for the switch. For example, in the above app, we created the SHOW_FILE_SIZE change analyzer by calling SwitchParser.booleanSwitchParser () to create a constructor. We then called optional() to make the switch optional and give it a default value of false before building the analyzer with to build():

import static com.telenav.kivakit.commandline.SwitchParser.booleanSwitchParser;

[...]

private SwitchParser<Boolean> SHOW_FILE_SIZE =
    booleanSwitchParser("show-file-size", "Show file size in bytes")
            .optional()
            .defaultValue(false)
            .build();

The SwitchParser.booleanSwitchParser static method creates a SwitchParser.Builder like that:

public static Builder<Boolean> booleanSwitchParser(String name, String description)
{
    return builder(Boolean.class)
            .name(name)
            .converter(new BooleanConverter(LOGGER))
            .description(description);
}

As we can see the Builder.converter (Converter) method is all that is needed to convert the switch from a string on the command line to one boolean value, as in:

-show-file-size=true

In general, if a String converter already exists for a type, it is trivial to create new switch analyzers for that type. As KivaKit has many handy string converters, KivaKit also provides many argument and switch parsers. Some of the types that support switch and / or argument parsers:

  • Boolean, Double, Integer, Long
  • Minimum Maximum
  • Bytes
  • To count
  • Local hour
  • Model
  • Percent
  • Version
  • Resource, ResourceList
  • File, FilePath, FileList
  • File, List of files
  • Host
  • Harbor

Coded

The complete code for the example shown here is available in the kivakit-examples deposit. The switch analysis classes are in:

<dependency>
    <groupId>com.telenav.kivakit</groupId>
    <artifactId>kivakit-commandline</artifactId>
    <version>${kivakit.version}</version>
</dependency>

but it is not normally necessary to include it directly since the application-kivakit module provides easier access to the same functionality:

<dependency>
    <groupId>com.telenav.kivakit</groupId>
    <artifactId>kivakit-application</artifactId>
    <version>${kivakit.version}</version>
</dependency>

Posted on Java Code Geeks with the permission of Jonathan Locke, partner of our JCG program. See the original article here: KivaKit Command Line Analysis

The opinions expressed by contributors to Java Code Geeks are their own.

[ad_2]

Source link