forked from knative/func
-
Notifications
You must be signed in to change notification settings - Fork 0
/
templates.go
185 lines (158 loc) · 5 KB
/
templates.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
173
174
175
176
177
178
179
180
181
182
183
184
185
package cmd
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
"text/tabwriter"
"github.com/ory/viper"
"github.com/spf13/cobra"
"knative.dev/func/pkg/config"
fn "knative.dev/func/pkg/functions"
)
// ErrTemplateRepoDoesNotExist is a sentinel error if a template repository responds with 404 status code
var ErrTemplateRepoDoesNotExist = errors.New("template repo does not exist")
func NewTemplatesCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "templates",
Short: "List available function source templates",
Long: `
NAME
{{rootCmdUse}} templates - list available function source templates
SYNOPSIS
{{rootCmdUse}} templates [language] [--json] [-r|--repository]
DESCRIPTION
List all templates available, optionally for a specific language runtime.
To specify a URI of a single, specific repository for which templates
should be displayed, use the --repository flag.
Installed repositories are by default located at ~/.func/repositories
($XDG_CONFIG_HOME/.func/repositories). This can be overridden with
$FUNC_REPOSITORIES_PATH.
To see all available language runtimes, see the 'languages' command.
EXAMPLES
o Show a list of all available templates grouped by language runtime
$ {{rootCmdUse}} templates
o Show a list of all templates for the Go runtime
$ {{rootCmdUse}} templates go
o Return a list of all template runtimes in JSON output format
$ {{rootCmdUse}} templates --json
o Return Go templates in a specific repository
$ {{rootCmdUse}} templates go --repository=https://github.com/boson-project/templates
`,
SuggestFor: []string{"template", "templtaes", "templatse", "remplates",
"gemplates", "yemplates", "tenplates", "tekplates", "tejplates",
"temolates", "temllates", "temppates", "tempmates", "tempkates",
"templstes", "templztes", "templqtes", "templares", "templages", //nolint:misspell
"templayes", "templatee", "templatea", "templated", "templatew"},
PreRunE: bindEnv("json", "repository", "verbose"),
RunE: func(cmd *cobra.Command, args []string) error {
return runTemplates(cmd, args, newClient)
},
}
cfg, err := config.NewDefault()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
}
cmd.Flags().Bool("json", false, "Set output to JSON format. (Env: $FUNC_JSON)")
cmd.Flags().StringP("repository", "r", "", "URI to a specific repository to consider ($FUNC_REPOSITORY)")
addVerboseFlag(cmd, cfg.Verbose)
return cmd
}
func runTemplates(cmd *cobra.Command, args []string, newClient ClientFactory) (err error) {
// Gather config
cfg, err := newTemplatesConfig(newClient)
if err != nil {
return
}
// Simple ping to the repo to avoid subsequent errors from http package if it does not exist
if cfg.Repository != "" {
res, err := http.Get(cfg.Repository)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode == http.StatusNotFound {
return ErrTemplateRepoDoesNotExist
}
}
// Client which will provide data
client, done := newClient(
ClientConfig{Verbose: cfg.Verbose},
fn.WithRepository(cfg.Repository))
defer done()
// For a single language runtime
// -------------------
if len(args) == 1 {
templates, err := client.Templates().List(args[0])
if err != nil {
return err
}
if cfg.JSON {
s, err := json.MarshalIndent(templates, "", " ")
if err != nil {
return err
}
fmt.Fprintln(cmd.OutOrStdout(), string(s))
} else {
for _, template := range templates {
fmt.Fprintln(cmd.OutOrStdout(), template)
}
}
return nil
} else if len(args) > 1 {
return errors.New("unexpected extra arguments")
}
// All language runtimes
// ------------
runtimes, err := client.Runtimes()
if err != nil {
return
}
if cfg.JSON {
// Gather into a single data structure for printing as json
templateMap := make(map[string][]string)
for _, runtime := range runtimes {
templates, err := client.Templates().List(runtime)
if err != nil {
return err
}
templateMap[runtime] = templates
}
s, err := json.MarshalIndent(templateMap, "", " ")
if err != nil {
return err
}
fmt.Fprintln(cmd.OutOrStdout(), string(s))
} else {
// print using a formatted writer (sorted)
builder := strings.Builder{}
writer := tabwriter.NewWriter(&builder, 0, 0, 3, ' ', 0)
fmt.Fprint(writer, "LANGUAGE\tTEMPLATE\n")
for _, runtime := range runtimes {
templates, err := client.Templates().List(runtime)
if err != nil {
return err
}
for _, template := range templates {
fmt.Fprintf(writer, "%v\t%v\n", runtime, template)
}
}
writer.Flush()
fmt.Fprint(cmd.OutOrStdout(), builder.String())
}
return
}
type templatesConfig struct {
Verbose bool
Repository string // Consider only a specific repository (URI)
JSON bool // output as JSON
}
func newTemplatesConfig(newClient ClientFactory) (cfg templatesConfig, err error) {
cfg = templatesConfig{
Verbose: viper.GetBool("verbose"),
Repository: viper.GetString("repository"),
JSON: viper.GetBool("json"),
}
return
}