aboutsummaryrefslogtreecommitdiff
path: root/cmd/flag.go
blob: 8a9d41239cfd4ac349fd61694c77521089dd4495 (plain)
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
/*
 * flag.go - Definitions for flags and associated formatting functions.
 *
 * Copyright 2017 Google Inc.
 * Author: Joe Richey (joerichey@google.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package cmd

import (
	"flag"
	"fmt"
	"strconv"
	"time"
)

// Useful flags that can be used with a variety of commands.
var (
	HelpFlag = &BoolFlag{
		Name:      "help",
		ShortName: 'h',
		Usage:     "Prints a help text for any command or sub-command.",
	}
	VerboseFlag = &BoolFlag{
		Name:  "verbose",
		Usage: "Prints additional debug messages.",
	}
	QuietFlag = &BoolFlag{
		Name: "quiet",
		Usage: `Prints nothing except for errors and uses any default
		option instead of prompting the user.`,
	}
	ForceFlag = &BoolFlag{
		Name: "force",
		Usage: `Print no confirmation prompts or warnings and
		automatically proceed with the requested action.`,
	}
)

// Flag represents a flag that can be passed to a command. The Name, ArgName,
// and Usage are used to format and display the flag.
type Flag interface {
	// String formats the flag as either "--name" or "--name=<argName>".
	fmt.Stringer
	// FullUsage is the usage for this flag with an optional default note.
	FullUsage() string
	// Apply sets up this flag on a flag set.
	Apply(*flag.FlagSet)
}

// Formats as "--name" or as "--name=<argName>" if argName is present.
func flagFormatHelper(name, argName string) string {
	if argName != "" {
		return fmt.Sprintf("--%s=<%s>", name, argName)
	}
	return fmt.Sprintf("--%s", name)
}

// Appends (default: <default>) to the usage if defaultString is present.
func flagUsageHelper(usage, defaultString string) string {
	if defaultString != "" {
		usage += fmt.Sprintf(" (default: %s)", defaultString)
	}
	return usage
}

// BoolFlag is a Flag of type bool.
type BoolFlag struct {
	Name      string
	ShortName byte
	Usage     string
	Default   bool
	Value     bool
}

// String always uses the smaller format, as it has no ArgName.
func (f *BoolFlag) String() string {
	name := f.Name
	if f.ShortName != 0 {
		name += ", -" + string(f.ShortName)
	}
	return flagFormatHelper(name, "")
}

// FullUsage shows the default if it's true (flag is implicitly passed).
func (f *BoolFlag) FullUsage() string {
	if !f.Default {
		return flagUsageHelper(f.Usage, "")
	}
	return flagUsageHelper(f.Usage, "true")
}

// Apply uses BoolFlag's value to set a flag.BoolVar on the FlagSet.
func (f *BoolFlag) Apply(s *flag.FlagSet) {
	s.BoolVar(&f.Value, f.Name, f.Default, f.Usage)
	if f.ShortName != 0 {
		s.BoolVar(&f.Value, string(f.ShortName), f.Default, f.Usage)
	}
}

// StringFlag is a Flag of type string.
type StringFlag struct {
	Name    string
	ArgName string
	Usage   string
	Default string
	Value   string
}

func (f *StringFlag) String() string { return flagFormatHelper(f.Name, f.ArgName) }

// FullUsage shows the deafult if the string is non-empty.
func (f *StringFlag) FullUsage() string {
	if f.Default == "" {
		return flagUsageHelper(f.Usage, "")
	}
	return flagUsageHelper(f.Usage, strconv.Quote(f.Default))
}

// Apply uses StringFlag's value to set a flag.StringVar on the FlagSet.
func (f *StringFlag) Apply(s *flag.FlagSet) { s.StringVar(&f.Value, f.Name, f.Default, f.Usage) }

// DurationFlag is a Flag of type time.Duration.
type DurationFlag struct {
	Name    string
	ArgName string
	Usage   string
	Default time.Duration
	Value   time.Duration
}

func (f *DurationFlag) String() string { return flagFormatHelper(f.Name, f.ArgName) }

// FullUsage shows the default if the duration is non-zero.
func (f *DurationFlag) FullUsage() string {
	if f.Default == 0 {
		return flagUsageHelper(f.Usage, "")
	}
	return flagUsageHelper(f.Usage, f.Default.String())
}

// Apply uses DurationFlag's value to set a flag.DurationVar on the FlagSet.
func (f *DurationFlag) Apply(s *flag.FlagSet) { s.DurationVar(&f.Value, f.Name, f.Default, f.Usage) }