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.
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
}
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.
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...),
)
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.
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.
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(),
)
)
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.
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.