mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-04 13:17:43 -06:00
0a596d2a12
Along with all of the other information we previously reported in the "terraform version" output, we'll now include the name of the current platform as our provider mechanisms represent it. This is addressing a long-standing minor annoyance where we often can't tell from an incomplete bug report which platform Terraform was running on, and incomplete bug reporters do tend to at least include the "terraform version" output even if they don't also include the requested full trace log. However, what motivated doing it _now_ is that anyone building a provider registry or mirror needs to have some awareness of these platform identifiers which have been, until v0.13, mostly an implementation detail. This additional information is a small thing we can do to help registry builders find out what the platform identifier ought to be for each of the platforms they aim to support, even if some of them are platforms which the Go compiler allows but which HashiCorp doesn't officially support. The new information is on a line of its own in the output as a pragmatic way to avoid breaking anyone who might be using something like $(terraform version | head -n1) to print a brief Terraform version identifier into some logs. That's not an interface we officially support for machine consumption, but it's easy to avoid breaking it here and so we won't do so.
180 lines
5.2 KiB
Go
180 lines
5.2 KiB
Go
package command
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/internal/depsfile"
|
|
"github.com/hashicorp/terraform/internal/getproviders"
|
|
)
|
|
|
|
// VersionCommand is a Command implementation prints the version.
|
|
type VersionCommand struct {
|
|
Meta
|
|
|
|
Revision string
|
|
Version string
|
|
VersionPrerelease string
|
|
CheckFunc VersionCheckFunc
|
|
Platform getproviders.Platform
|
|
}
|
|
|
|
type VersionOutput struct {
|
|
Version string `json:"terraform_version"`
|
|
Revision string `json:"terraform_revision"`
|
|
Platform string `json:"platform"`
|
|
ProviderSelections map[string]string `json:"provider_selections"`
|
|
Outdated bool `json:"terraform_outdated"`
|
|
}
|
|
|
|
// VersionCheckFunc is the callback called by the Version command to
|
|
// check if there is a new version of Terraform.
|
|
type VersionCheckFunc func() (VersionCheckInfo, error)
|
|
|
|
// VersionCheckInfo is the return value for the VersionCheckFunc callback
|
|
// and tells the Version command information about the latest version
|
|
// of Terraform.
|
|
type VersionCheckInfo struct {
|
|
Outdated bool
|
|
Latest string
|
|
Alerts []string
|
|
}
|
|
|
|
func (c *VersionCommand) Help() string {
|
|
helpText := `
|
|
Usage: terraform version [options]
|
|
|
|
Displays the version of Terraform and all installed plugins
|
|
|
|
Options:
|
|
|
|
-json Output the version information as a JSON object.
|
|
`
|
|
return strings.TrimSpace(helpText)
|
|
}
|
|
|
|
func (c *VersionCommand) Run(args []string) int {
|
|
var outdated bool
|
|
var latest string
|
|
var versionString bytes.Buffer
|
|
args = c.Meta.process(args)
|
|
var jsonOutput bool
|
|
cmdFlags := c.Meta.defaultFlagSet("version")
|
|
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
|
|
// Enable but ignore the global version flags. In main.go, if any of the
|
|
// arguments are -v, -version, or --version, this command will be called
|
|
// with the rest of the arguments, so we need to be able to cope with
|
|
// those.
|
|
cmdFlags.Bool("v", true, "version")
|
|
cmdFlags.Bool("version", true, "version")
|
|
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
|
|
}
|
|
|
|
fmt.Fprintf(&versionString, "Terraform v%s", c.Version)
|
|
if c.VersionPrerelease != "" {
|
|
fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
|
|
|
|
if c.Revision != "" {
|
|
fmt.Fprintf(&versionString, " (%s)", c.Revision)
|
|
}
|
|
}
|
|
|
|
// We'll also attempt to print out the selected plugin versions. We do
|
|
// this based on the dependency lock file, and so the result might be
|
|
// empty or incomplete if the user hasn't successfully run "terraform init"
|
|
// since the most recent change to dependencies.
|
|
//
|
|
// Generally-speaking this is a best-effort thing that will give us a good
|
|
// result in the usual case where the user successfully ran "terraform init"
|
|
// and then hit a problem running _another_ command.
|
|
var providerVersions []string
|
|
var providerLocks map[addrs.Provider]*depsfile.ProviderLock
|
|
if locks, err := c.lockedDependencies(); err == nil {
|
|
providerLocks = locks.AllProviders()
|
|
for providerAddr, lock := range providerLocks {
|
|
version := lock.Version().String()
|
|
if version == "0.0.0" {
|
|
providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s (unversioned)", providerAddr))
|
|
} else {
|
|
providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s v%s", providerAddr, version))
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we have a version check function, then let's check for
|
|
// the latest version as well.
|
|
if c.CheckFunc != nil {
|
|
// Check the latest version
|
|
info, err := c.CheckFunc()
|
|
if err != nil && !jsonOutput {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"\nError checking latest version: %s", err))
|
|
}
|
|
if info.Outdated {
|
|
outdated = true
|
|
latest = info.Latest
|
|
}
|
|
}
|
|
|
|
if jsonOutput {
|
|
selectionsOutput := make(map[string]string)
|
|
for providerAddr, lock := range providerLocks {
|
|
version := lock.Version().String()
|
|
selectionsOutput[providerAddr.String()] = version
|
|
}
|
|
|
|
var versionOutput string
|
|
if c.VersionPrerelease != "" {
|
|
versionOutput = c.Version + "-" + c.VersionPrerelease
|
|
} else {
|
|
versionOutput = c.Version
|
|
}
|
|
|
|
output := VersionOutput{
|
|
Version: versionOutput,
|
|
Revision: c.Revision,
|
|
Platform: c.Platform.String(),
|
|
ProviderSelections: selectionsOutput,
|
|
Outdated: outdated,
|
|
}
|
|
|
|
jsonOutput, err := json.MarshalIndent(output, "", " ")
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf("\nError marshalling JSON: %s", err))
|
|
return 1
|
|
}
|
|
c.Ui.Output(string(jsonOutput))
|
|
return 0
|
|
} else {
|
|
c.Ui.Output(versionString.String())
|
|
c.Ui.Output(fmt.Sprintf("on %s", c.Platform))
|
|
|
|
if len(providerVersions) != 0 {
|
|
sort.Strings(providerVersions)
|
|
for _, str := range providerVersions {
|
|
c.Ui.Output(str)
|
|
}
|
|
}
|
|
if outdated {
|
|
c.Ui.Output(fmt.Sprintf(
|
|
"\nYour version of Terraform is out of date! The latest version\n"+
|
|
"is %s. You can update by downloading from https://www.terraform.io/downloads.html",
|
|
latest))
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func (c *VersionCommand) Synopsis() string {
|
|
return "Show the current Terraform version"
|
|
}
|