/soil

Primary LanguageGoMIT LicenseMIT

Bootstrapping for Golang CLI Applications

soil is using Cobra, Viper and Zerolog for doing the actual heavy lifting and adds a convenient interface on top of them.

Disclaimer: Soil currently only supports a limited subset of feature that are available using these libraries. Adding more features is not a big problem though, so if you need something please implement and provide a PR.

Getting started

Include soil in your project using modules:

go get github.com/mtrense/soil

and import it in your code:

package main

import "github.com/mtrense/soil"

A minimal skeleton for your CLI library might look like:

package main

import (
    . "github.com/mtrense/soil/config"
    l "github.com/mtrense/soil/logging"
)

var (
    version = "none"  // The current version of the program 
                      // (Set with -X main.version=${VERSION} on go build)
    commit  = "none"  // The current version of the program 
                      // (Set with -X main.commit=$(git rev-parse --short HEAD 2>/dev/null || echo \"none\") on 
                      // go build)
    app = NewCommandline("my_app",      // Creates a new root command object
          Short("New app using soil"),  // Short description
          FlagLogFile(),                // Adds a flag to specify the logfile location (--logfile FILE)
          FlagLogLevel("warn"),         // Adds a flag to specify the log level (--loglevel warn)
          Run(execute),                 // Defines function to run on handling this command
          Version(version, commit),     // Adds a subcommand for showing the version and commit info 
                                        // of the current build
          Completion(),                 // Add a subcommand for completion on bash, fish and zsh
    ).GenerateCobra()
)

func init() {
    EnvironmentConfig("MY_APP")
    l.ConfigureDefaultLogging()
}

func main() {
    if err := app.Execute(); err != nil {
        panic(err)
    }
}

func execute(cmd *cobra.Command, args []string) {
    l.L().Info().Msg("My App starting")
    // Your code
}

Commands

The general Syntax for commands is *Command(name, ...options). All options are implemented as functions following the same interface and will be applied to the command at the end of the surrounding function call. Options are stateless and safe to apply multiple times, in case you have an option or flag common to multiple commands/subcommands.

Subcommands

You can add subcommands to any command by simply adding the SubCommand(name, ...options) option to the parent command like this:

NewCommandline("my_app",
    SubCommand("subcommand1",
        SubCommand("nested-subcommand1",
        	options...),
        options...),
    SubCommand("subcommand2",
        options...),
)

Command Options

Alias(...aliases)
Adds the given strings as aliases to this command.
Short(description)
Sets the short description of this command.
Long(description)
Sets the long description of this command.
ValidArgs(...args)
Adds the given string arguments as valid one's.
Hidden()
Marks the command as hidden.
Deprecated(message)
Marks the command as deprecated.
Args(positionalArgs)
Set cobra positional args on the command.
Run(function)
Set the function to run.

Common Commands

Soil provides shortcuts for common commands:

Version(version, commit)
Provides a version command and a --version flag, that prints out the current version and commit hash.
Completion()
Provides a completion command which provides convenient shell completion for bash, zsh, fish and powershell.

Flags

Adding flags to a command works the same way as options and sub commands. Use the Flag(name, type, ...options) command option like this:

NewCommandLine("my_app",
    Flag("some-flag", Str("default value"),
        Persistent(),
        Description("Description of some-flag"),
        Abbr("s"),
        Env(),
    )
)

Flag Types

Soil already provides several types of values for flags:

Str(default)
A string value with a default.
Int(default)
An integer value with a default.
Bool()
A bool value. Defaults to false.
Float(default)
A float value with a default.
Duration(default)
A duration value with a default.

Flag Options

Options can be used to further specify the behavior of a flag:

Persistent()
Add the flag to the persistent `FlagSet` (default is non-persistent).
Description(description)
Set the description of the flag.
Abbr(character)
Define the one-character abbreviation of the flag (like in `--help` and `-h`).
Env()
Enable setting this flag from the environment (only works with Viper's `AutomaticEnv` feature, if you call `EnvironmentConfig(prefix)` as in the example above, this is taken care of).
EnvName(name)
Same as `Env()`, but let's you customize the name of the environment variable.
Mandatory()
Mark the flag as mandatory.
Filename(...extensions)
Mark the flag as filename with the specified extensions. If the argument list is empty, any extension is considered valid. This affects shell completion.
Dirname()
Mark the flag as dirname. This affects shell completion.

Common Flags