github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/cmd/list.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"
     7  
     8  	"github.com/spf13/cobra"
     9  	"github.com/turbot/steampipe/pkg/cmdconfig"
    10  	"github.com/turbot/steampipe/pkg/display"
    11  	"github.com/turbot/steampipe/pkg/error_helpers"
    12  	"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
    13  	"github.com/turbot/steampipe/pkg/workspace"
    14  )
    15  
    16  type listSubCmdOptions struct {
    17  	parentCmd *cobra.Command
    18  }
    19  
    20  func getListSubCmd(opts listSubCmdOptions) *cobra.Command {
    21  	cmd := &cobra.Command{
    22  		Use:              "list",
    23  		TraverseChildren: true,
    24  		Args:             cobra.NoArgs,
    25  		Run:              getRunListSubCmd(opts),
    26  		Short:            fmt.Sprintf("List all resources that can be executed with the '%s' command", opts.parentCmd.Name()),
    27  		Long:             fmt.Sprintf("List all resources that can be executed with the '%s' command", opts.parentCmd.Name()),
    28  	}
    29  
    30  	cmdconfig.
    31  		OnCmd(cmd)
    32  
    33  	return cmd
    34  }
    35  
    36  // getRunListSubCmd generates a command handler based on the parent command
    37  func getRunListSubCmd(opts listSubCmdOptions) func(cmd *cobra.Command, args []string) {
    38  	if opts.parentCmd == nil {
    39  		// this should never happen
    40  		panic("parent is required")
    41  	}
    42  
    43  	return func(cmd *cobra.Command, _ []string) {
    44  		ctx := cmd.Context()
    45  
    46  		w, inputVariables, errAndWarnings := workspace.LoadWorkspaceVars(ctx)
    47  		error_helpers.FailOnError(errAndWarnings.GetError())
    48  		errAndWarnings = w.LoadWorkspaceMod(ctx, inputVariables)
    49  		error_helpers.FailOnError(errAndWarnings.GetError())
    50  
    51  		modResources, depResources, err := listResourcesInMod(ctx, w.Mod, cmd)
    52  		error_helpers.FailOnErrorWithMessage(err, "could not list resources")
    53  		if len(modResources)+len(depResources) == 0 {
    54  			fmt.Println("No resources available to execute.")
    55  		}
    56  
    57  		sortResources(modResources)
    58  		sortResources(depResources)
    59  		headers, rows := getOutputDataTable(modResources, depResources)
    60  
    61  		display.ShowWrappedTable(headers, rows, &display.ShowWrappedTableOptions{
    62  			AutoMerge:        false,
    63  			HideEmptyColumns: true,
    64  			Truncate:         true,
    65  		})
    66  	}
    67  }
    68  
    69  func listResourcesInMod(ctx context.Context, mod *modconfig.Mod, cmd *cobra.Command) (modResources, depResources []modconfig.ModTreeItem, err error) {
    70  	resourceTypesToDisplay := getResourceTypesToDisplay(cmd)
    71  
    72  	err = mod.WalkResources(func(item modconfig.HclResource) (bool, error) {
    73  		if ctx.Err() != nil {
    74  			return false, ctx.Err()
    75  		}
    76  
    77  		// if we are not showing this resource type, return
    78  		if !resourceTypesToDisplay[item.BlockType()] {
    79  			return true, nil
    80  		}
    81  
    82  		m := item.(modconfig.ModTreeItem)
    83  
    84  		itemMod := m.GetMod()
    85  		if m.GetParents()[0] == itemMod {
    86  
    87  			// add to the appropriate array
    88  			if itemMod.Name() == mod.Name() {
    89  				modResources = append(modResources, m)
    90  			} else {
    91  				depResources = append(depResources, m)
    92  			}
    93  		}
    94  		return true, nil
    95  	})
    96  	return modResources, depResources, err
    97  }
    98  
    99  func sortResources(items []modconfig.ModTreeItem) {
   100  	sort.SliceStable(items, func(i, j int) bool {
   101  		return items[i].Name() < items[j].Name()
   102  	})
   103  }
   104  
   105  func getOutputDataTable(modResources, depResources []modconfig.ModTreeItem) ([]string, [][]string) {
   106  	rows := make([][]string, len(modResources)+len(depResources))
   107  	for i, modItem := range modResources {
   108  		rows[i] = []string{modItem.GetUnqualifiedName(), modItem.GetTitle()}
   109  	}
   110  	offset := len(modResources)
   111  	for i, modItem := range depResources {
   112  		// use fully qualified name for dependency resources
   113  		rows[i+offset] = []string{modItem.Name(), modItem.GetTitle()}
   114  	}
   115  	return []string{"Name", "Title"}, rows
   116  }
   117  
   118  func getResourceTypesToDisplay(cmd *cobra.Command) map[string]bool {
   119  	parent := cmd.Parent().Name()
   120  	cmdToTypeMapping := map[string][]string{
   121  		"check":     {"benchmark", "control"},
   122  		"dashboard": {"dashboard", "benchmark"},
   123  		"query":     {"query"},
   124  	}
   125  	resourceTypesToDisplay, found := cmdToTypeMapping[parent]
   126  	if !found {
   127  		panic(fmt.Sprintf("could not find resource type lookup list for '%s'", parent))
   128  	}
   129  	// add resource types to a map for cheap lookup
   130  	res := map[string]bool{}
   131  	for _, t := range resourceTypesToDisplay {
   132  		res[t] = true
   133  	}
   134  	return res
   135  }