opentofu/command/providers.go
Martin Atkins c94a6102df command: Improve consistency of the command short descriptions
The short description of our commands (as shown in the main help output
from "terraform") was previously very inconsistent, using different
tense/mood for different commands. Some of the commands were also using
some terminology choices inconsistent with how we currently talk about
the related ideas in our documentation.

Here I've tried to add some consistency by first rewriting them all in
the imperative mood (except the ones that just are just subcommand
groupings), and tweaking some of the terminology to hopefully gel better
with how we present similar ideas in our recently-updated docs.

While working on this I inevitably spotted some similar inconsistencies
in the longer-form help output of some of the commands. I've not reviewed
all of these for consistency, but I did update some where the wording
was either left inconsstent with the short form changes I'd made or
where the prose stood out to me as particularly inconsistent with our
current usual documentation language style.

All of this is subjective, so I expect we'll continue to tweak these over
time as we continue to develop our documentation writing style based on
user questions and feedback.
2020-10-26 09:55:21 -07:00

158 lines
3.9 KiB
Go

package command
import (
"fmt"
"path/filepath"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/internal/getproviders"
"github.com/hashicorp/terraform/tfdiags"
"github.com/xlab/treeprint"
)
// ProvidersCommand is a Command implementation that prints out information
// about the providers used in the current configuration/state.
type ProvidersCommand struct {
Meta
}
func (c *ProvidersCommand) Help() string {
return providersCommandHelp
}
func (c *ProvidersCommand) Synopsis() string {
return "Show the providers required for this configuration"
}
func (c *ProvidersCommand) Run(args []string) int {
args = c.Meta.process(args)
cmdFlags := c.Meta.defaultFlagSet("providers")
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
if err := cmdFlags.Parse(args); err != nil {
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
return 1
}
configPath, err := ModulePath(cmdFlags.Args())
if err != nil {
c.Ui.Error(err.Error())
return 1
}
var diags tfdiags.Diagnostics
empty, err := configs.IsEmptyDir(configPath)
if err != nil {
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Error validating configuration directory",
fmt.Sprintf("Terraform encountered an unexpected error while verifying that the given configuration directory is valid: %s.", err),
))
c.showDiagnostics(diags)
return 1
}
if empty {
absPath, err := filepath.Abs(configPath)
if err != nil {
absPath = configPath
}
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"No configuration files",
fmt.Sprintf("The directory %s contains no Terraform configuration files.", absPath),
))
c.showDiagnostics(diags)
return 1
}
config, configDiags := c.loadConfig(configPath)
diags = diags.Append(configDiags)
if configDiags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
// Load the backend
b, backendDiags := c.Backend(&BackendOpts{
Config: config.Module.Backend,
})
diags = diags.Append(backendDiags)
if backendDiags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
// Get the state
env, err := c.Workspace()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
return 1
}
s, err := b.StateMgr(env)
if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
return 1
}
if err := s.RefreshState(); err != nil {
c.Ui.Error(fmt.Sprintf("Failed to load state: %s", err))
return 1
}
reqs, reqDiags := config.ProviderRequirementsByModule()
diags = diags.Append(reqDiags)
if diags.HasErrors() {
c.showDiagnostics(diags)
return 1
}
state := s.State()
var stateReqs getproviders.Requirements
if state != nil {
stateReqs = state.ProviderRequirements()
}
printRoot := treeprint.New()
c.populateTreeNode(printRoot, reqs)
c.Ui.Output("\nProviders required by configuration:")
c.Ui.Output(printRoot.String())
if len(stateReqs) > 0 {
c.Ui.Output("Providers required by state:\n")
for fqn := range stateReqs {
c.Ui.Output(fmt.Sprintf(" provider[%s]\n", fqn.String()))
}
}
c.showDiagnostics(diags)
if diags.HasErrors() {
return 1
}
return 0
}
func (c *ProvidersCommand) populateTreeNode(tree treeprint.Tree, node *configs.ModuleRequirements) {
for fqn, dep := range node.Requirements {
versionsStr := getproviders.VersionConstraintsString(dep)
if versionsStr != "" {
versionsStr = " " + versionsStr
}
tree.AddNode(fmt.Sprintf("provider[%s]%s", fqn.String(), versionsStr))
}
for name, childNode := range node.Children {
branch := tree.AddBranch(fmt.Sprintf("module.%s", name))
c.populateTreeNode(branch, childNode)
}
}
const providersCommandHelp = `
Usage: terraform providers [dir]
Prints out a tree of modules in the referenced configuration annotated with
their provider requirements.
This provides an overview of all of the provider requirements across all
referenced modules, as an aid to understanding why particular provider
plugins are needed and why particular versions are selected.
`