forked from knative/func
-
Notifications
You must be signed in to change notification settings - Fork 0
/
list.go
172 lines (139 loc) · 4.6 KB
/
list.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
161
162
163
164
165
166
167
168
169
170
171
172
package cmd
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"os"
"text/tabwriter"
"github.com/ory/viper"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"knative.dev/func/pkg/config"
fn "knative.dev/func/pkg/functions"
)
func NewListCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List deployed functions",
Long: `List deployed functions
Lists all deployed functions in a given namespace.
`,
Example: `
# List all functions in the current namespace with human readable output
{{rootCmdUse}} list
# List all functions in the 'test' namespace with yaml output
{{rootCmdUse}} list --namespace test --output yaml
# List all functions in all namespaces with JSON output
{{rootCmdUse}} list --all-namespaces --output json
`,
SuggestFor: []string{"ls", "lsit"},
PreRunE: bindEnv("all-namespaces", "output", "namespace", "verbose"),
RunE: func(cmd *cobra.Command, args []string) error {
return runList(cmd, args, newClient)
},
}
cfg, err := config.NewDefault()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
}
// Namespace Config
// Differing from other commands, the default namespace for the list
// command is always the currently active namespace as returned by
// config.DefaultNamespace(). The -A flag clears this value indicating
// the lister implementation should not filter by namespace and instead
// list from all namespaces. This logic is sligtly inverse to the other
// namespace-sensitive commands which default to the currently active
// function if available, and delegate to the implementation to use
// the config default otherwise.
// Flags
cmd.Flags().BoolP("all-namespaces", "A", false, "List functions in all namespaces. If set, the --namespace flag is ignored.")
cmd.Flags().StringP("namespace", "n", config.DefaultNamespace(), "The namespace for which to list functions. ($FUNC_NAMESPACE)")
cmd.Flags().StringP("output", "o", "human", "Output format (human|plain|json|xml|yaml) ($FUNC_OUTPUT)")
addVerboseFlag(cmd, cfg.Verbose)
if err := cmd.RegisterFlagCompletionFunc("output", CompleteOutputFormatList); err != nil {
fmt.Println("internal: error while calling RegisterFlagCompletionFunc: ", err)
}
return cmd
}
func runList(cmd *cobra.Command, _ []string, newClient ClientFactory) (err error) {
cfg := newListConfig()
if err := cfg.Validate(cmd); err != nil {
return err
}
client, done := newClient(ClientConfig{Namespace: cfg.Namespace, Verbose: cfg.Verbose})
defer done()
items, err := client.List(cmd.Context())
if err != nil {
return
}
if len(items) == 0 {
if cfg.Namespace != "" {
fmt.Printf("no functions found in namespace '%v'\n", cfg.Namespace)
} else {
fmt.Println("no functions found")
}
return
}
write(os.Stdout, listItems(items), cfg.Output)
return
}
// CLI Configuration (parameters)
// ------------------------------
type listConfig struct {
Namespace string
Output string
Verbose bool
}
func newListConfig() listConfig {
c := listConfig{
Namespace: viper.GetString("namespace"),
Output: viper.GetString("output"),
Verbose: viper.GetBool("verbose"),
}
// Lister instantiated by newClient explicitly expects "" namespace to
// inidicate it should list from all namespaces, so remove default "default"
// when -A.
if viper.GetBool("all-namespaces") {
c.Namespace = ""
}
return c
}
func (c listConfig) Validate(cmd *cobra.Command) error {
if cmd.Flags().Changed("namespace") && viper.GetBool("all-namespaces") {
return errors.New("Both --namespace and --all-namespaces specified.")
}
return nil
}
// Output Formatting (serializers)
// -------------------------------
type listItems []fn.ListItem
func (items listItems) Human(w io.Writer) error {
return items.Plain(w)
}
func (items listItems) Plain(w io.Writer) error {
// minwidth, tabwidth, padding, padchar, flags
tabWriter := tabwriter.NewWriter(w, 0, 8, 2, ' ', 0)
defer tabWriter.Flush()
fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%s\t%s\n", "NAME", "NAMESPACE", "RUNTIME", "URL", "READY")
for _, item := range items {
fmt.Fprintf(tabWriter, "%s\t%s\t%s\t%s\t%s\n", item.Name, item.Namespace, item.Runtime, item.URL, item.Ready)
}
return nil
}
func (items listItems) JSON(w io.Writer) error {
return json.NewEncoder(w).Encode(items)
}
func (items listItems) XML(w io.Writer) error {
return xml.NewEncoder(w).Encode(items)
}
func (items listItems) YAML(w io.Writer) error {
return yaml.NewEncoder(w).Encode(items)
}
func (items listItems) URL(w io.Writer) error {
for _, item := range items {
fmt.Fprintf(w, "%s\n", item.URL)
}
return nil
}