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  }