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 }