github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/control/controldisplay/format_resolver.go (about) 1 package controldisplay 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/turbot/go-kit/files" 8 "github.com/turbot/steampipe/pkg/constants" 9 "github.com/turbot/steampipe/pkg/export" 10 "github.com/turbot/steampipe/pkg/filepaths" 11 ) 12 13 type FormatResolver struct { 14 formatterByName map[string]Formatter 15 // array of unique formatters used for export 16 exportFormatters []Formatter 17 } 18 19 func NewFormatResolver(ctx context.Context) (*FormatResolver, error) { 20 templates, err := loadAvailableTemplates(ctx) 21 if err != nil { 22 return nil, err 23 } 24 25 formatters := []Formatter{ 26 &NullFormatter{}, 27 &TextFormatter{}, 28 &SnapshotFormatter{}, 29 } 30 31 res := &FormatResolver{ 32 formatterByName: make(map[string]Formatter), 33 } 34 35 for _, f := range formatters { 36 if err := res.registerFormatter(f); err != nil { 37 return nil, err 38 } 39 } 40 for _, t := range templates { 41 f, err := NewTemplateFormatter(t) 42 if err != nil { 43 return nil, err 44 } 45 46 if err := res.registerFormatter(f); err != nil { 47 return nil, err 48 } 49 } 50 51 return res, nil 52 } 53 54 func (r *FormatResolver) GetFormatter(arg string) (Formatter, error) { 55 if formatter, found := r.formatterByName[arg]; found { 56 return formatter, nil 57 } 58 59 return nil, fmt.Errorf(" invalid output format: '%s'", arg) 60 } 61 62 func (r *FormatResolver) registerFormatter(f Formatter) error { 63 name := f.Name() 64 65 if _, ok := r.formatterByName[name]; ok { 66 return fmt.Errorf("failed to register output formatter - duplicate format name %s", name) 67 } 68 r.formatterByName[name] = f 69 // if the formatter has an alias, also register by alias 70 if alias := f.Alias(); alias != "" { 71 if _, ok := r.formatterByName[alias]; ok { 72 return fmt.Errorf("failed to register output formatter - duplicate format name %s", alias) 73 } 74 r.formatterByName[alias] = f 75 } 76 // add to exportFormatters list (exclude 'None') 77 if f.Name() != constants.OutputFormatNone { 78 r.exportFormatters = append(r.exportFormatters, f) 79 } 80 return nil 81 } 82 83 func (r *FormatResolver) controlExporters() []export.Exporter { 84 res := make([]export.Exporter, len(r.exportFormatters)) 85 for i, formatter := range r.exportFormatters { 86 res[i] = NewControlExporter(formatter) 87 88 } 89 return res 90 } 91 92 func loadAvailableTemplates(ctx context.Context) ([]*OutputTemplate, error) { 93 templateDirectories, err := files.ListFilesWithContext(ctx, filepaths.EnsureTemplateDir(), &files.ListOptions{ 94 Flags: files.DirectoriesFlat | files.NotEmpty, 95 Exclude: []string{"./.*"}, 96 }) 97 if err != nil { 98 return nil, err 99 } 100 101 templates := []*OutputTemplate{} 102 for _, templateDirectory := range templateDirectories { 103 templates = append(templates, NewOutputTemplate(templateDirectory)) 104 } 105 return templates, nil 106 }