github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/providers.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "path/filepath" 6 7 "github.com/xlab/treeprint" 8 9 "github.com/hashicorp/terraform/internal/configs" 10 "github.com/hashicorp/terraform/internal/getproviders" 11 "github.com/hashicorp/terraform/internal/tfdiags" 12 ) 13 14 // ProvidersCommand is a Command implementation that prints out information 15 // about the providers used in the current configuration/state. 16 type ProvidersCommand struct { 17 Meta 18 } 19 20 func (c *ProvidersCommand) Help() string { 21 return providersCommandHelp 22 } 23 24 func (c *ProvidersCommand) Synopsis() string { 25 return "Show the providers required for this configuration" 26 } 27 28 func (c *ProvidersCommand) Run(args []string) int { 29 args = c.Meta.process(args) 30 cmdFlags := c.Meta.defaultFlagSet("providers") 31 cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } 32 if err := cmdFlags.Parse(args); err != nil { 33 c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error())) 34 return 1 35 } 36 37 configPath, err := ModulePath(cmdFlags.Args()) 38 if err != nil { 39 c.Ui.Error(err.Error()) 40 return 1 41 } 42 43 var diags tfdiags.Diagnostics 44 45 empty, err := configs.IsEmptyDir(configPath) 46 if err != nil { 47 diags = diags.Append(tfdiags.Sourceless( 48 tfdiags.Error, 49 "Error validating configuration directory", 50 fmt.Sprintf("Terraform encountered an unexpected error while verifying that the given configuration directory is valid: %s.", err), 51 )) 52 c.showDiagnostics(diags) 53 return 1 54 } 55 if empty { 56 absPath, err := filepath.Abs(configPath) 57 if err != nil { 58 absPath = configPath 59 } 60 diags = diags.Append(tfdiags.Sourceless( 61 tfdiags.Error, 62 "No configuration files", 63 fmt.Sprintf("The directory %s contains no Terraform configuration files.", absPath), 64 )) 65 c.showDiagnostics(diags) 66 return 1 67 } 68 69 config, configDiags := c.loadConfig(configPath) 70 diags = diags.Append(configDiags) 71 if configDiags.HasErrors() { 72 c.showDiagnostics(diags) 73 return 1 74 } 75 76 // Load the backend 77 b, backendDiags := c.Backend(&BackendOpts{ 78 Config: config.Module.Backend, 79 }) 80 diags = diags.Append(backendDiags) 81 if backendDiags.HasErrors() { 82 c.showDiagnostics(diags) 83 return 1 84 } 85 86 // This is a read-only command 87 c.ignoreRemoteVersionConflict(b) 88 89 // Get the state 90 env, err := c.Workspace() 91 if err != nil { 92 c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err)) 93 return 1 94 } 95 s, err := b.StateMgr(env) 96 if err != nil { 97 c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) 98 return 1 99 } 100 if err := s.RefreshState(); err != nil { 101 c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err)) 102 return 1 103 } 104 105 reqs, reqDiags := config.ProviderRequirementsByModule() 106 diags = diags.Append(reqDiags) 107 if diags.HasErrors() { 108 c.showDiagnostics(diags) 109 return 1 110 } 111 112 state := s.State() 113 var stateReqs getproviders.Requirements 114 if state != nil { 115 stateReqs = state.ProviderRequirements() 116 } 117 118 printRoot := treeprint.New() 119 c.populateTreeNode(printRoot, reqs) 120 121 c.Ui.Output("\nProviders required by configuration:") 122 c.Ui.Output(printRoot.String()) 123 124 if len(stateReqs) > 0 { 125 c.Ui.Output("Providers required by state:\n") 126 for fqn := range stateReqs { 127 c.Ui.Output(fmt.Sprintf(" provider[%s]\n", fqn.String())) 128 } 129 } 130 131 c.showDiagnostics(diags) 132 if diags.HasErrors() { 133 return 1 134 } 135 return 0 136 } 137 138 func (c *ProvidersCommand) populateTreeNode(tree treeprint.Tree, node *configs.ModuleRequirements) { 139 for fqn, dep := range node.Requirements { 140 versionsStr := getproviders.VersionConstraintsString(dep) 141 if versionsStr != "" { 142 versionsStr = " " + versionsStr 143 } 144 tree.AddNode(fmt.Sprintf("provider[%s]%s", fqn.String(), versionsStr)) 145 } 146 for name, childNode := range node.Children { 147 branch := tree.AddBranch(fmt.Sprintf("module.%s", name)) 148 c.populateTreeNode(branch, childNode) 149 } 150 } 151 152 const providersCommandHelp = ` 153 Usage: terraform [global options] providers [DIR] 154 155 Prints out a tree of modules in the referenced configuration annotated with 156 their provider requirements. 157 158 This provides an overview of all of the provider requirements across all 159 referenced modules, as an aid to understanding why particular provider 160 plugins are needed and why particular versions are selected. 161 `