diff --git a/featctl/cmd/list_feature.go b/featctl/cmd/list_feature.go index 343ef4e1f..27e48bd81 100644 --- a/featctl/cmd/list_feature.go +++ b/featctl/cmd/list_feature.go @@ -2,14 +2,19 @@ package cmd import ( "context" + "encoding/csv" "fmt" "log" + "os" + "time" + "github.com/olekukonko/tablewriter" "github.com/oom-ai/oomstore/pkg/oomstore/types" "github.com/spf13/cobra" ) var listFeatureOpt types.ListFeatureOpt +var listFeatureOutput *string var listFeatureCmd = &cobra.Command{ Use: "feature", @@ -21,6 +26,9 @@ var listFeatureCmd = &cobra.Command{ if !cmd.Flags().Changed("group") { listFeatureOpt.GroupName = nil } + if !cmd.Flags().Changed("output") { + listFeatureOutput = stringPtr(ASCIITable) + } }, Run: func(cmd *cobra.Command, args []string) { ctx := context.Background() @@ -32,10 +40,9 @@ var listFeatureCmd = &cobra.Command{ log.Fatalf("failed listing features given option %v, error %v\n", listFeatureOpt, err) } - // print csv to stdout - fmt.Println(types.FeatureCsvHeader()) - for _, feature := range features { - fmt.Println(feature.ToCsvRecord()) + // print features to stdout + if err := printFeatures(features, *listFeatureOutput); err != nil { + log.Fatalf("failed printing features, error %v\n", err) } }, } @@ -47,4 +54,65 @@ func init() { listFeatureOpt.EntityName = flags.StringP("entity", "e", "", "entity") listFeatureOpt.GroupName = flags.StringP("group", "g", "", "feature group") + listFeatureOutput = flags.StringP("output", "o", "", "output format") +} + +func printFeatures(features types.FeatureList, output string) error { + switch output { + case CSV: + return printFeaturesInCSV(features) + case ASCIITable: + return printFeaturesInASCIITable(features) + default: + return fmt.Errorf("unsupported output format %s", output) + } +} + +func printFeaturesInCSV(features types.FeatureList) error { + w := csv.NewWriter(os.Stdout) + if err := w.Write(featureHeader()); err != nil { + return err + } + for _, feature := range features { + if err := w.Write(featureRecord(feature)); err != nil { + return err + } + } + + w.Flush() + return nil +} + +func printFeaturesInASCIITable(features types.FeatureList) error { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader(featureHeader()) + table.SetAutoFormatHeaders(false) + + for _, feature := range features { + table.Append(featureRecord(feature)) + } + table.Render() + return nil +} + +func featureHeader() []string { + return []string{"Name", "Group", "Entity", "Category", "DBValueType", "ValueType", "Description", "OnlineRevision", "OfflineLatestRevision", "OfflineLatestDataTable", "CreateTime", "ModifyTime"} +} + +func featureRecord(f *types.Feature) []string { + onlineRevision := "" + offlineRevision := "" + offlineDataTable := "" + + if f.OnlineRevision != nil { + onlineRevision = fmt.Sprint(*f.OnlineRevision) + } + if f.OfflineRevision != nil { + offlineRevision = fmt.Sprint(*f.OfflineRevision) + } + if f.OfflineDataTable != nil { + offlineDataTable = *f.OfflineDataTable + } + + return []string{f.Name, f.GroupName, f.EntityName, f.Category, f.DBValueType, f.ValueType, f.Description, onlineRevision, offlineRevision, offlineDataTable, f.CreateTime.Format(time.RFC3339), f.ModifyTime.Format(time.RFC3339)} } diff --git a/featctl/test/test_list_feature.sh b/featctl/test/test_list_feature.sh index 256f70cb1..f5f4e2714 100755 --- a/featctl/test/test_list_feature.sh +++ b/featctl/test/test_list_feature.sh @@ -11,6 +11,6 @@ expected='Name,Group,Entity,Category,DBValueType,ValueType,Description,OnlineRev model,phone,device,batch,varchar(32),string,,1634626568,1634626568,phone_1634626568,2021-10-19T06:56:07Z,2021-10-19T06:56:07Z price,phone,device,batch,int,int32,1634626568,1634626568,phone_1634626568,2021-10-19T06:56:07Z,2021-10-19T06:56:07Z ' -actual=$(featctl list feature) +actual=$(featctl list feature -o csv) ignore_time() { cut -d ',' -f 1-6 <<<"$1"; } assert_eq "$case" "$(ignore_time "$expected" | sort)" "$(ignore_time "$actual" | sort)"