File: labels.go

package info (click to toggle)
hcloud-cli 1.39.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,628 kB
  • sloc: sh: 36; makefile: 7
file content (159 lines) | stat: -rw-r--r-- 4,847 bytes parent folder | download | duplicates (2)
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
package base

import (
	"context"
	"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(ctx context.Context, client hcapi2.Client, idOrName string) (map[string]string, int64, error)
	SetLabels              func(ctx context.Context, client hcapi2.Client, id int64, labels map[string]string) error
}

// AddCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) AddCobraCommand(
	ctx context.Context, client hcapi2.Client, tokenEnsurer state.TokenEnsurer,
) *cobra.Command {
	cmd := &cobra.Command{
		Use:                   fmt.Sprintf("add-label [FLAGS] %s LABEL", strings.ToUpper(lc.ResourceNameSingular)),
		Short:                 lc.ShortDescriptionAdd,
		Args:                  cobra.ExactArgs(2),
		ValidArgsFunction:     cmpl.SuggestArgs(cmpl.SuggestCandidatesF(lc.NameSuggestions(client))),
		TraverseChildren:      true,
		DisableFlagsInUseLine: true,
		PreRunE:               util.ChainRunE(validateAddLabel, tokenEnsurer.EnsureToken),
		RunE: func(cmd *cobra.Command, args []string) error {
			return lc.RunAdd(ctx, client, 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(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, args []string) error {
	overwrite, _ := cmd.Flags().GetBool("overwrite")
	idOrName := args[0]

	labels, id, err := lc.FetchLabels(ctx, client, idOrName)
	if err != nil {
		return err
	}

	if labels == nil {
		labels = map[string]string{}
	}

	key, val := util.SplitLabelVars(args[1])

	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(ctx, client, id, labels); err != nil {
		return err
	}

	fmt.Printf("Label %s added to %s %d\n", key, lc.ResourceNameSingular, id)
	return nil
}

func validateAddLabel(cmd *cobra.Command, args []string) error {
	label := util.SplitLabel(args[1])
	if len(label) != 2 {
		return fmt.Errorf("invalid label: %s", args[1])
	}

	return nil
}

// RemoveCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) RemoveCobraCommand(
	ctx context.Context, client hcapi2.Client, tokenEnsurer state.TokenEnsurer,
) *cobra.Command {
	cmd := &cobra.Command{
		Use:   fmt.Sprintf("remove-label [FLAGS] %s LABEL", strings.ToUpper(lc.ResourceNameSingular)),
		Short: lc.ShortDescriptionRemove,
		Args:  cobra.RangeArgs(1, 2),
		ValidArgsFunction: cmpl.SuggestArgs(
			cmpl.SuggestCandidatesF(lc.NameSuggestions(client)),
			cmpl.SuggestCandidatesCtx(func(_ *cobra.Command, args []string) []string {
				if len(args) != 1 {
					return nil
				}
				return lc.LabelKeySuggestions(client)(args[0])
			}),
		),
		TraverseChildren:      true,
		DisableFlagsInUseLine: true,
		PreRunE:               util.ChainRunE(validateRemoveLabel, tokenEnsurer.EnsureToken),
		RunE: func(cmd *cobra.Command, args []string) error {
			return lc.RunRemove(ctx, client, cmd, args)
		},
	}
	cmd.Flags().BoolP("all", "a", false, "Remove all labels")
	return cmd
}

// RunRemove executes a remove label command
func (lc *LabelCmds) RunRemove(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, args []string) error {
	all, _ := cmd.Flags().GetBool("all")
	idOrName := args[0]

	labels, id, err := lc.FetchLabels(ctx, client, idOrName)
	if err != nil {
		return err
	}

	if all {
		labels = make(map[string]string)
	} else {
		key := 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(ctx, client, id, labels); err != nil {
		return err
	}

	if all {
		fmt.Printf("All labels removed from %s %d\n", lc.ResourceNameSingular, id)
	} else {
		fmt.Printf("Label %s removed from %s %d\n", args[1], lc.ResourceNameSingular, id)
	}

	return nil
}

func validateRemoveLabel(cmd *cobra.Command, args []string) error {
	all, _ := cmd.Flags().GetBool("all")

	if all && len(args) == 2 {
		return errors.New("must not specify a label key when using --all/-a")
	}
	if !all && len(args) != 2 {
		return errors.New("must specify a label key when not using --all/-a")
	}

	return nil
}