From 526a7a0670cce4a090da17cb274c5ac5bae7be0e Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Tue, 4 Apr 2023 11:25:25 +0100 Subject: [PATCH] Bump recommended templates to the top of the file * Introduces concept of sorting by recommended templates * Adds filtering options to only view recommended or official templates Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- commands/template_store_list.go | 105 ++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/commands/template_store_list.go b/commands/template_store_list.go index 9b6f98b07..f1851d28d 100644 --- a/commands/template_store_list.go +++ b/commands/template_store_list.go @@ -8,9 +8,11 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" + "net/http" "os" + "sort" "strings" "text/tabwriter" "time" @@ -27,12 +29,16 @@ const ( var ( templateStoreURL string inputPlatform string + recommended bool + official bool ) func init() { templateStoreListCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Shows additional language and platform") templateStoreListCmd.PersistentFlags().StringVarP(&templateStoreURL, "url", "u", DefaultTemplatesStore, "Use as alternative store for templates") templateStoreListCmd.Flags().StringVarP(&inputPlatform, "platform", "p", mainPlatform, "Shows the platform if the output is verbose") + templateStoreListCmd.Flags().BoolVarP(&recommended, "recommended", "r", false, "Shows only recommended templates") + templateStoreListCmd.Flags().BoolVarP(&official, "official", "o", false, "Shows only official templates") templateStoreCmd.AddCommand(templateStoreListCmd) } @@ -42,12 +48,28 @@ var templateStoreListCmd = &cobra.Command{ Use: `list`, Short: `List templates from OpenFaaS organizations`, Aliases: []string{"ls"}, - Long: `List templates from official store or from custom URL or set the environmental variable OPENFAAS_TEMPLATE_STORE_URL to be the default store location`, + Long: `List templates from a template store manifest file, by default the +official list maintained by the OpenFaaS community is used. You can override this.`, Example: ` faas-cli template store list - faas-cli template store ls - faas-cli template store ls --url=https://raw.githubusercontent.com/openfaas/store/master/templates.json + # List only recommended templates + faas-cli template store list --recommended + + # List only official templates + faas-cli template store list --official + + # Override the store via a flag + faas-cli template store ls \ + --url=https://raw.githubusercontent.com/openfaas/store/master/templates.json + + # Specify an alternative store via environment variable + export OPENFAAS_TEMPLATE_STORE_URL=https://example.com/templates.json + + # See additional language and platform faas-cli template store ls --verbose=true - faas-cli template store list --platform arm64`, + + # Filter by platform for arm64 only + faas-cli template store list --platform arm64 +`, RunE: runTemplateStoreList, } @@ -55,12 +77,29 @@ func runTemplateStoreList(cmd *cobra.Command, args []string) error { envTemplateRepoStore := os.Getenv(templateStoreURLEnvironment) storeURL := getTemplateStoreURL(templateStoreURL, envTemplateRepoStore, DefaultTemplatesStore) - templatesInfo, templatesErr := getTemplateInfo(storeURL) - if templatesErr != nil { - return fmt.Errorf("error while getting templates info: %s", templatesErr) + templatesInfo, err := getTemplateInfo(storeURL) + if err != nil { + return fmt.Errorf("error while getting templates info: %s", err) } + list := []TemplateInfo{} - formattedOutput := formatTemplatesOutput(templatesInfo, verbose, inputPlatform) + if recommended { + for i := 0; i < len(templatesInfo); i++ { + if templatesInfo[i].Recommended { + list = append(list, templatesInfo[i]) + } + } + } else if official { + for i := 0; i < len(templatesInfo); i++ { + if templatesInfo[i].Official == "true" { + list = append(list, templatesInfo[i]) + } + } + } else { + list = templatesInfo + } + + formattedOutput := formatTemplatesOutput(list, verbose, inputPlatform) fmt.Fprintf(cmd.OutOrStdout(), "%s", formattedOutput) @@ -78,9 +117,9 @@ func getTemplateInfo(repository string) ([]TemplateInfo, error) { req = req.WithContext(reqContext) client := http.DefaultClient - res, clientErr := client.Do(req) - if clientErr != nil { - return nil, fmt.Errorf("error while requesting template list: %s", clientErr.Error()) + res, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("error while requesting template list: %s", err.Error()) } if res.Body == nil { @@ -92,19 +131,37 @@ func getTemplateInfo(repository string) ([]TemplateInfo, error) { return nil, fmt.Errorf("unexpected status code wanted: %d got: %d", http.StatusOK, res.StatusCode) } - body, bodyErr := ioutil.ReadAll(res.Body) - if bodyErr != nil { - return nil, fmt.Errorf("error while reading data from templates body: %s", bodyErr.Error()) + body, err := io.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf("error while reading response: %s", err.Error()) } templatesInfo := []TemplateInfo{} - unmarshallErr := json.Unmarshal(body, &templatesInfo) - if unmarshallErr != nil { - return nil, fmt.Errorf("error while unmarshalling into templates struct: %s", unmarshallErr.Error()) + if err := json.Unmarshal(body, &templatesInfo); err != nil { + return nil, fmt.Errorf("can't unmarshal text: %s", err.Error()) } + + sortTemplates(templatesInfo) + return templatesInfo, nil } +func sortTemplates(templatesInfo []TemplateInfo) { + sort.Slice(templatesInfo, func(i, j int) bool { + if templatesInfo[i].Recommended == templatesInfo[j].Recommended { + if templatesInfo[i].Official == templatesInfo[j].Official { + return strings.ToLower(templatesInfo[i].TemplateName) < strings.ToLower(templatesInfo[j].TemplateName) + } else { + return templatesInfo[i].Official < templatesInfo[j].Official + } + } else if templatesInfo[i].Recommended { + return true + } else { + return false + } + }) +} + func formatTemplatesOutput(templates []TemplateInfo, verbose bool, platform string) string { if platform != mainPlatform { @@ -135,10 +192,17 @@ func formatTemplatesOutput(templates []TemplateInfo, verbose bool, platform stri func formatBasicOutput(lineWriter *tabwriter.Writer, templates []TemplateInfo) { - fmt.Fprintf(lineWriter, "NAME\tSOURCE\tDESCRIPTION\n") + fmt.Fprintf(lineWriter, "NAME\tRECOMMENDED\tDESCRIPTION\tSOURCE\n") for _, template := range templates { - fmt.Fprintf(lineWriter, "%s\t%s\t%s\n", + + recommended := "[ ]" + if template.Recommended { + recommended = "[x]" + } + + fmt.Fprintf(lineWriter, "%s\t%s\t%s\t%s\n", template.TemplateName, + recommended, template.Source, template.Description) } @@ -166,6 +230,7 @@ type TemplateInfo struct { Description string `json:"description"` Repository string `json:"repo"` Official string `json:"official"` + Recommended bool `json:"recommended"` } func filterTemplate(templates []TemplateInfo, platform string) []TemplateInfo {