--- Begin Message ---
- To: submit@bugs.debian.org
- Subject: ITP: golang-github-audriusbutkevicius-recli -- Reflection based CLI (command line interface) generator for Golang
- From: "Quentin Hibon" <qh.public@yahoo.com>
- Date: Fri, 20 Mar 2020 18:40:00 +0100
Package: wnpp
Severity: wishlist
Owner: hiq <hiq@hiq-lptp-deb.home>
* Package name : golang-github-audriusbutkevicius-recli
Version : 0.0.5-1
Upstream Author : Audrius Butkevicius
* URL : https://github.com/AudriusButkevicius/recli
* License : MPL-2.0
Programming Lang: Go
Description : Reflection based CLI (command line interface) generator for Golang
recli - Reflection based CLI (command line interface) generator for
Golang GoDoc (https://godoc.org/github.com/AudriusButkevicius/recli)
.
For a given struct, builds a set of urfave/cli
(https://github.com/urfave/cli) commands which allows you to modify it
from the command line.
.
Useful for generating command line clients for your application
configuration that is stored in a Go struct. Features•
Nested struct support• Enum/Custom complex type support via
MarshalText/UnmarshalText• Slice support, including complex types•
Slice indexing by struct field• Map support• Default primitive value
support when adding items to slicesKnown limitations• Adding new
struct to a slice only allows setting primitive fields (use add-json
as a work-around)• Only primitive types supported for map keys and
values• No defaults for mapsExamples Example config
.
``go type Config struct {
Address stringusage:"Address on which to listen"`
// Description printed in -help AuthMode AuthMode
// Enum support ThreadingOptions ThreadingOptions
// Nested struct support Backends []Backend
// Slice support EnvVars map[string]string
// Map support
}
.
type Backend struct {
Hostname string recli:"id" // Constructs commands
for indexing into the array based on the value of this field Port
int default:"2019" // Default support BackoffIntervals []int
default:"10,20" // Slice default support IPAddressCached net.IP
recli:"-" json:"-" // Skips the field
}
.
type ThreadingOptions struct {
MaxThreads int
} ```
.
Sample input data json {
"Address":"http://website.com", "AuthMode":"static",
"ThreadingOptions":{
"MaxThreads":10
}, "Backends":[
{
"Hostname":"backend1.com", "Port":1010
}, {
"Hostname":"backend2.com", "Port":2020
}
], "EnvVars":{
"CC":"/usr/bin/gcc"
}
}
.
.
.
Full example code
.
```go package main
.
import (
"encoding/json" "fmt" "net" "os"
"github.com/AudriusButkevicius/recli" "github.com/urfave/cli"
.
)
.
type Config struct {
Address string usage:"Address on which to listen"
// Description printed in -help AuthMode AuthMode
// Enum support ThreadingOptions ThreadingOptions
// Nested struct support Backends []Backend
// Slice support EnvVars map[string]string
// Map support
}
.
type Backend struct {
Hostname string recli:"id" // Constructs commands
for indexing into the array based on the value of this field Port
int default:"2019" // Default support BackoffIntervals []int
default:"10,20" // Slice default support IPAddressCached net.IP
recli:"-" json:"-" // Skips the field
}
.
type ThreadingOptions struct {
MaxThreads int
}
.
type AuthMode int
.
const (
AuthModeStatic AuthMode = iota // default is static AuthModeLDAP
)
.
func (t AuthMode) MarshalText() ([]byte, error) {
switch t { case AuthModeStatic:
return []byte("static"), nil
case AuthModeLDAP:
return []byte("ldap"), nil
} return nil, fmt.Errorf("unknown value: %s", t)
}
.
func (t *AuthMode) UnmarshalText(bs []byte) error {
switch string(bs) { case "ldap":
*t = AuthModeLDAP
case "static":
*t = AuthModeStatic
default:
return fmt.Errorf("unknown value: %s", string(bs))
} return nil
}
.
const (
sampleData =
{
"Address":"http://website.com", "AuthMode":"static",
"ThreadingOptions":{
"MaxThreads":10
}, "Backends":[
{
"Hostname":"backend1.com", "Port":1010
}, {
"Hostname":"backend2.com", "Port":2020
}
], "EnvVars":{
"CC":"/usr/bin/gcc"
}
} )
.
func main() {
cfg := &Config{}
if err := json.Unmarshal([]byte(sampleData), cfg); err != nil {
panic(err)
}
.
cmds, err := recli.Default.Construct(cfg) if err != nil {
panic(err)
}
.
dump := false
.
app := cli.NewApp() app.Commands = cmds app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "dump", Destination: &dump,
},
}
.
if err := app.Run(os.Args); err != nil {
panic(err)
}
.
if dump {
bs, err := json.MarshalIndent(&cfg, "", " ") if err != nil {
panic(err)
}
.
fmt.Print(string(bs))
}
.
} ```
.
.
.
Get a field
.
bash $ go run main.go address get http://website.com
.
.
.
.
Set a field
.
bash $ go run main.go -dump address set foo {
"Address": "foo", "AuthMode": "static", "ThreadingOptions": {
"MaxThreads": 10
}, "Backends": [
{
"Hostname": "backend1.com", "Port": 1010, "BackoffIntervals":
null
}, {
"Hostname": "backend2.com", "Port": 2020, "BackoffIntervals":
null
}
], "EnvVars": {
"CC": "/usr/bin/gcc"
}
}
.
.
.
.
Set a nested field
.
bash $ go run main.go -dump threading-options max-threads set 9000 {
"Address": "http://website.com", "AuthMode": "static",
"ThreadingOptions": {
"MaxThreads": 9000
}, "Backends": [
{
"Hostname": "backend1.com", "Port": 1010, "BackoffIntervals":
null
}, {
"Hostname": "backend2.com", "Port": 2020, "BackoffIntervals":
null
}
], "EnvVars": {
"CC": "/usr/bin/gcc"
}
}
.
.
.
.
Listing available slice items (with a custom slice index key)
.
```bash $ go run main.go backends NAME:
main.exe backends -
.
USAGE:
main.exe backends command [command options] [arguments...]
.
COMMANDS:
ACTIONS:
add Add a new item to collection add-json Add a new
item to collection deserialised from JSON
.
ITEMS:
backend1.com backend2.com
.
OPTIONS:
--help, -h show help
.
```
.
.
.
Deleting a slice item
.
bash $ go run main.go -dump backends backend1.com delete {
"Address": "http://website.com", "AuthMode": "static",
"ThreadingOptions": {
"MaxThreads": 10
}, "Backends": [
{
"Hostname": "backend2.com", "Port": 2020, "BackoffIntervals":
null
}
], "EnvVars": {
"CC": "/usr/bin/gcc"
}
}
.
.
.
.
Adding a slice item (with defaults)
.
bash $ go run main.go -dump backends add -hostname="testback.end" {
"Address": "http://website.com", "AuthMode": "static",
"ThreadingOptions": {
"MaxThreads": 10
}, "Backends": [
{
"Hostname": "backend1.com", "Port": 1010, "BackoffIntervals":
null
}, {
"Hostname": "backend2.com", "Port": 2020, "BackoffIntervals":
null
}, {
"Hostname": "testback.end", "Port": 2019, "BackoffIntervals":
[
10, 20
]
}
], "EnvVars": {
"CC": "/usr/bin/gcc"
}
}
.
.
.
.
Setting map keys
.
bash $ go run main.go -dump env-vars set GCC /usr/bin/true {
"Address": "http://website.com", "AuthMode": "static",
"ThreadingOptions": {
"MaxThreads": 10
}, "Backends": [
{
"Hostname": "backend1.com", "Port": 1010, "BackoffIntervals":
null
}, {
"Hostname": "backend2.com", "Port": 2020, "BackoffIntervals":
null
}
], "EnvVars": {
"CC": "/usr/bin/gcc", "GCC": "/usr/bin/true"
}
}
Reasoning: Dependency of syncthing
--- End Message ---