File: flag_bool_with_inverse.go

package info (click to toggle)
golang-github-urfave-cli-v3 3.3.8-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,676 kB
  • sloc: sh: 26; makefile: 16
file content (240 lines) | stat: -rw-r--r-- 7,682 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
package cli

import (
	"context"
	"fmt"
	"slices"
	"strings"
)

var DefaultInverseBoolPrefix = "no-"

type BoolWithInverseFlag struct {
	Name             string                                      `json:"name"`             // name of the flag
	Category         string                                      `json:"category"`         // category of the flag, if any
	DefaultText      string                                      `json:"defaultText"`      // default text of the flag for usage purposes
	HideDefault      bool                                        `json:"hideDefault"`      // whether to hide the default value in output
	Usage            string                                      `json:"usage"`            // usage string for help output
	Sources          ValueSourceChain                            `json:"-"`                // sources to load flag value from
	Required         bool                                        `json:"required"`         // whether the flag is required or not
	Hidden           bool                                        `json:"hidden"`           // whether to hide the flag in help output
	Local            bool                                        `json:"local"`            // whether the flag needs to be applied to subcommands as well
	Value            bool                                        `json:"defaultValue"`     // default value for this flag if not set by from any source
	Destination      *bool                                       `json:"-"`                // destination pointer for value when set
	Aliases          []string                                    `json:"aliases"`          // Aliases that are allowed for this flag
	TakesFile        bool                                        `json:"takesFileArg"`     // whether this flag takes a file argument, mainly for shell completion purposes
	Action           func(context.Context, *Command, bool) error `json:"-"`                // Action callback to be called when flag is set
	OnlyOnce         bool                                        `json:"onlyOnce"`         // whether this flag can be duplicated on the command line
	Validator        func(bool) error                            `json:"-"`                // custom function to validate this flag value
	ValidateDefaults bool                                        `json:"validateDefaults"` // whether to validate defaults or not
	Config           BoolConfig                                  `json:"config"`           // Additional/Custom configuration associated with this flag type
	InversePrefix    string                                      `json:"invPrefix"`        // The prefix used to indicate a negative value. Default: `env` becomes `no-env`

	// unexported fields for internal use
	count      int   // number of times the flag has been set
	hasBeenSet bool  // whether the flag has been set from env or file
	applied    bool  // whether the flag has been applied to a flag set already
	value      Value // value representing this flag's value
	pset       bool
	nset       bool
}

func (bif *BoolWithInverseFlag) IsSet() bool {
	return bif.hasBeenSet
}

func (bif *BoolWithInverseFlag) Get() any {
	return bif.value.Get()
}

func (bif *BoolWithInverseFlag) RunAction(ctx context.Context, cmd *Command) error {
	if bif.Action != nil {
		return bif.Action(ctx, cmd, bif.Get().(bool))
	}

	return nil
}

func (bif *BoolWithInverseFlag) IsLocal() bool {
	return bif.Local
}

func (bif *BoolWithInverseFlag) inversePrefix() string {
	if bif.InversePrefix == "" {
		bif.InversePrefix = DefaultInverseBoolPrefix
	}

	return bif.InversePrefix
}

func (bif *BoolWithInverseFlag) PreParse() error {
	count := bif.Config.Count
	if count == nil {
		count = &bif.count
	}
	dest := bif.Destination
	if dest == nil {
		dest = new(bool)
	}
	*dest = bif.Value
	bif.value = &boolValue{
		destination: dest,
		count:       count,
	}

	// Validate the given default or values set from external sources as well
	if bif.Validator != nil && bif.ValidateDefaults {
		if err := bif.Validator(bif.value.Get().(bool)); err != nil {
			return err
		}
	}
	bif.applied = true
	return nil
}

func (bif *BoolWithInverseFlag) PostParse() error {
	tracef("postparse (flag=%[1]q)", bif.Name)

	if !bif.hasBeenSet {
		if val, source, found := bif.Sources.LookupWithSource(); found {
			if val == "" {
				val = "false"
			}
			if err := bif.Set(bif.Name, val); err != nil {
				return fmt.Errorf(
					"could not parse %[1]q as %[2]T value from %[3]s for flag %[4]s: %[5]s",
					val, bif.Value, source, bif.Name, err,
				)
			}

			bif.hasBeenSet = true
		}
	}

	return nil
}

func (bif *BoolWithInverseFlag) Set(name, val string) error {
	if bif.count > 0 && bif.OnlyOnce {
		return fmt.Errorf("cant duplicate this flag")
	}

	bif.hasBeenSet = true

	if slices.Contains(append([]string{bif.Name}, bif.Aliases...), name) {
		if bif.nset {
			return fmt.Errorf("cannot set both flags `--%s` and `--%s`", bif.Name, bif.inversePrefix()+bif.Name)
		}
		if err := bif.value.Set(val); err != nil {
			return err
		}
		bif.pset = true
	} else {
		if bif.pset {
			return fmt.Errorf("cannot set both flags `--%s` and `--%s`", bif.Name, bif.inversePrefix()+bif.Name)
		}
		if err := bif.value.Set("false"); err != nil {
			return err
		}
		bif.nset = true
	}

	if bif.Validator != nil {
		return bif.Validator(bif.value.Get().(bool))
	}
	return nil
}

func (bif *BoolWithInverseFlag) Names() []string {
	names := append([]string{bif.Name}, bif.Aliases...)

	for _, name := range names {
		names = append(names, bif.inversePrefix()+name)
	}

	return names
}

func (bif *BoolWithInverseFlag) IsRequired() bool {
	return bif.Required
}

func (bif *BoolWithInverseFlag) IsVisible() bool {
	return !bif.Hidden
}

// String implements the standard Stringer interface.
//
// Example for BoolFlag{Name: "env"}
// --[no-]env	(default: false)
func (bif *BoolWithInverseFlag) String() string {
	out := FlagStringer(bif)

	i := strings.Index(out, "\t")

	prefix := "--"

	// single character flags are prefixed with `-` instead of `--`
	if len(bif.Name) == 1 {
		prefix = "-"
	}

	return fmt.Sprintf("%s[%s]%s%s", prefix, bif.inversePrefix(), bif.Name, out[i:])
}

// IsBoolFlag returns whether the flag doesnt need to accept args
func (bif *BoolWithInverseFlag) IsBoolFlag() bool {
	return true
}

// Count returns the number of times this flag has been invoked
func (bif *BoolWithInverseFlag) Count() int {
	return bif.count
}

// GetDefaultText returns the default text for this flag
func (bif *BoolWithInverseFlag) GetDefaultText() string {
	if bif.Required {
		return bif.DefaultText
	}
	return boolValue{}.ToString(bif.Value)
}

// GetCategory returns the category of the flag
func (bif *BoolWithInverseFlag) GetCategory() string {
	return bif.Category
}

func (bif *BoolWithInverseFlag) SetCategory(c string) {
	bif.Category = c
}

// GetUsage returns the usage string for the flag
func (bif *BoolWithInverseFlag) GetUsage() string {
	return bif.Usage
}

// GetEnvVars returns the env vars for this flag
func (bif *BoolWithInverseFlag) GetEnvVars() []string {
	return bif.Sources.EnvKeys()
}

// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (bif *BoolWithInverseFlag) GetValue() string {
	return ""
}

func (bif *BoolWithInverseFlag) TakesValue() bool {
	return false
}

// IsDefaultVisible returns true if the flag is not hidden, otherwise false
func (bif *BoolWithInverseFlag) IsDefaultVisible() bool {
	return !bif.HideDefault
}

// TypeName is used for stringify/docs. For bool its a no-op
func (bif *BoolWithInverseFlag) TypeName() string {
	return "bool"
}