// 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 }