-
Notifications
You must be signed in to change notification settings - Fork 75
/
labels.go
160 lines (135 loc) · 4.61 KB
/
labels.go
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
package base
import (
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/cli/internal/state"
)
// LabelCmds allows defining commands for adding labels to resources.
type LabelCmds struct {
ResourceNameSingular string
ShortDescriptionAdd string
ShortDescriptionRemove string
NameSuggestions func(client hcapi2.Client) func() []string
LabelKeySuggestions func(client hcapi2.Client) func(idOrName string) []string
FetchLabels func(s state.State, idOrName string) (map[string]string, int64, error)
SetLabels func(s state.State, id int64, labels map[string]string) error
}
// AddCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) AddCobraCommand(s state.State) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("add-label [--overwrite] <%s> <label>...", util.ToKebabCase(lc.ResourceNameSingular)),
Short: lc.ShortDescriptionAdd,
Args: util.Validate,
ValidArgsFunction: cmpl.SuggestArgs(cmpl.SuggestCandidatesF(lc.NameSuggestions(s.Client()))),
TraverseChildren: true,
DisableFlagsInUseLine: true,
PreRunE: util.ChainRunE(validateAddLabel, s.EnsureToken),
RunE: func(cmd *cobra.Command, args []string) error {
return lc.RunAdd(s, cmd, args)
},
}
cmd.Flags().BoolP("overwrite", "o", false, "Overwrite label if it exists already")
return cmd
}
// RunAdd executes an add label command
func (lc *LabelCmds) RunAdd(s state.State, cmd *cobra.Command, args []string) error {
overwrite, _ := cmd.Flags().GetBool("overwrite")
idOrName := args[0]
labels, id, err := lc.FetchLabels(s, idOrName)
if err != nil {
return err
}
if labels == nil {
labels = map[string]string{}
}
var keys []string
for _, label := range args[1:] {
key, val := util.SplitLabelVars(label)
keys = append(keys, key)
if _, ok := labels[key]; ok && !overwrite {
return fmt.Errorf("label %s on %s %d already exists", key, lc.ResourceNameSingular, id)
}
labels[key] = val
}
if err := lc.SetLabels(s, id, labels); err != nil {
return err
}
cmd.Printf("Label(s) %s added to %s %d\n", strings.Join(keys, ", "), lc.ResourceNameSingular, id)
return nil
}
func validateAddLabel(_ *cobra.Command, args []string) error {
for _, label := range args[1:] {
if len(util.SplitLabel(label)) != 2 {
return fmt.Errorf("invalid label: %s", label)
}
}
return nil
}
// RemoveCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) RemoveCobraCommand(s state.State) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("remove-label <%s> (--all | <label>...)", util.ToKebabCase(lc.ResourceNameSingular)),
Short: lc.ShortDescriptionRemove,
Args: util.ValidateLenient,
ValidArgsFunction: cmpl.SuggestArgs(
cmpl.SuggestCandidatesF(lc.NameSuggestions(s.Client())),
cmpl.SuggestCandidatesCtx(func(_ *cobra.Command, args []string) []string {
if len(args) != 1 {
return nil
}
return lc.LabelKeySuggestions(s.Client())(args[0])
}),
),
TraverseChildren: true,
DisableFlagsInUseLine: true,
PreRunE: util.ChainRunE(validateRemoveLabel, s.EnsureToken),
RunE: func(cmd *cobra.Command, args []string) error {
return lc.RunRemove(s, cmd, args)
},
}
cmd.Flags().BoolP("all", "a", false, "Remove all labels")
return cmd
}
// RunRemove executes a remove label command
func (lc *LabelCmds) RunRemove(s state.State, cmd *cobra.Command, args []string) error {
all, _ := cmd.Flags().GetBool("all")
idOrName := args[0]
labels, id, err := lc.FetchLabels(s, idOrName)
if err != nil {
return err
}
if all {
labels = make(map[string]string)
} else {
for _, key := range args[1:] {
if _, ok := labels[key]; !ok {
return fmt.Errorf("label %s on %s %d does not exist", key, lc.ResourceNameSingular, id)
}
delete(labels, key)
}
}
if err := lc.SetLabels(s, id, labels); err != nil {
return err
}
if all {
cmd.Printf("All labels removed from %s %d\n", lc.ResourceNameSingular, id)
} else {
cmd.Printf("Label(s) %s removed from %s %d\n", strings.Join(args[1:], ", "), lc.ResourceNameSingular, id)
}
return nil
}
func validateRemoveLabel(cmd *cobra.Command, args []string) error {
all, _ := cmd.Flags().GetBool("all")
if all && len(args) > 1 {
return errors.New("must not specify a label key when using --all/-a")
}
if !all && len(args) <= 1 {
return errors.New("must specify a label key when not using --all/-a")
}
return nil
}