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