297 lines
5.5 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package flags
import "fmt"
type GroupModifier func(g *Group)
// Don't display the group name of the flags
func HideGroupName() GroupModifier {
return func(g *Group) {
g.showGroupName = false
}
}
// Don't display this group of flags
func HideGroup() GroupModifier {
return func(g *Group) {
g.hidden = true
}
}
type Group struct {
flags []*Flag // flags attached to group
hidden bool // group should not be displayed
name string // name of the group
set *Set // Set group is attached to
showGroupName bool // group name should be included in display
}
func newGroup(s *Set, n string, modifiers ...GroupModifier) *Group {
if s == nil {
panic("group must be attached to set")
}
g := &Group{
set: s,
name: n,
flags: []*Flag{},
showGroupName: true,
}
for _, fn := range modifiers {
fn(g)
}
s.groups = append(s.groups, g)
return g
}
// Add a flag to the group. This is used to relocate
// a flag from one group to another.
func (g *Group) Add(f *Flag) (err error) {
if f.group == g {
return nil
}
if f.group != nil {
idx := -1
for i, flg := range f.group.flags {
if flg.longName == f.longName {
idx = i
break
}
}
if idx >= 0 {
f.group.flags = append(f.group.flags[0:idx], f.group.flags[idx+1:]...)
}
}
f.group = g
g.flags = append(g.flags, f)
return err
}
// Name of the group
func (g *Group) Name() string {
return g.name
}
// Flags contained by this group
func (g *Group) Flags() []*Flag {
f := make([]*Flag, len(g.flags))
copy(f, g.flags)
return f
}
// Add a new BooleanType flag
func (g *Group) Bool(
name string,
modifiers ...FlagModifier,
) *Flag {
return newFlag(name, BooleanType, g, modifiers...)
}
// Add a new BooleanType flag using variable
func (g *Group) BoolVar(
name string,
ptr *bool,
modifiers ...FlagModifier,
) *Flag {
f := g.Bool(name, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new StringType flag
func (g *Group) String(
name string,
modifiers ...FlagModifier,
) *Flag {
return newFlag(name, StringType, g, modifiers...)
}
// Add a new StringType flag using variable
func (g *Group) StringVar(
name string,
ptr *string,
modifiers ...FlagModifier,
) *Flag {
f := g.String(name, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new ArrayType flag
func (g *Group) Array(
name string,
subtype Type,
modifiers ...FlagModifier,
) *Flag {
modifiers = append(modifiers, SetSubtype(subtype))
return newFlag(name, ArrayType, g, modifiers...)
}
// Add a new ArrayType flag using variable
func (g *Group) ArrayVar(
name string,
subtype Type,
ptr interface{},
modifiers ...FlagModifier,
) *Flag {
f := g.Array(name, subtype, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new FloatType flag
func (g *Group) Float(
name string,
modifiers ...FlagModifier,
) *Flag {
return newFlag(name, FloatType, g, modifiers...)
}
// Add a new FloatType flag using variable
func (g *Group) FloatVar(
name string,
ptr *float64,
modifiers ...FlagModifier,
) *Flag {
f := g.Float(name, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new Integer flag
func (g *Group) Integer(
name string,
modifiers ...FlagModifier,
) *Flag {
return newFlag(name, IntegerType, g, modifiers...)
}
// Add a new Integer flag using variable
func (g *Group) IntegerVar(
name string,
ptr *int64,
modifiers ...FlagModifier,
) *Flag {
f := g.Integer(name, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new IncrementType flag
func (g *Group) Increment(
name string,
modifiers ...FlagModifier,
) *Flag {
modifiers = append(modifiers, SetSubtype(IntegerType))
return newFlag(name, IncrementType, g, modifiers...)
}
// Add a new IncrementType flag using variable
func (g *Group) IncrementVar(
name string,
ptr *int64,
modifiers ...FlagModifier,
) *Flag {
f := g.Increment(name, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Add a new MapType flag
func (g *Group) Map(
name string,
subtype Type,
modifiers ...FlagModifier,
) *Flag {
modifiers = append(modifiers, SetSubtype(subtype))
return newFlag(name, MapType, g, modifiers...)
}
// Add a new MaptType flag using variable
func (g *Group) MapVar(
name string,
subtype Type,
ptr interface{},
modifiers ...FlagModifier,
) *Flag {
f := g.Map(name, subtype, modifiers...)
f.ptr = true
f.value = ptr
return f
}
// Generate printable output of flag group
func (g *Group) Display(
indent int, // Number of spaces to indent
) string {
if g.hidden {
return ""
}
var pad int
opts := []string{}
desc := []string{}
for i, f := range g.flags {
if f.hidden {
continue
}
if f.shortName != 0 {
opts = append(opts, fmt.Sprintf("-%c,", f.shortName))
} else {
opts = append(opts, " ")
}
switch f.kind {
case BooleanType:
opts[i] = fmt.Sprintf("%s --[no-]%s", opts[i], f.longName)
case IncrementType:
opts[i] = fmt.Sprintf("%s --%s", opts[i], f.longName)
default:
opts[i] = fmt.Sprintf("%s --%s VALUE", opts[i], f.longName)
}
desc = append(desc, f.description)
if len(opts[i]) > pad {
pad = len(opts[i])
}
}
// If there were no flags to display (empty flag collection or all hidden)
// then just return an empty string
if len(opts) == 0 {
return ""
}
pad += indent
var d string
if g.showGroupName {
d = fmt.Sprintf("%s:\n", g.name)
}
for i := 0; i < len(opts); i++ {
d = fmt.Sprintf("%s%4s%-*s%s\n", d, "", pad, opts[i], desc[i])
}
return d
}