2014-05-24 21:04:43 +02:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-06-15 19:54:49 +02:00
|
|
|
"encoding/json"
|
2014-05-24 21:04:43 +02:00
|
|
|
"fmt"
|
2017-10-24 21:27:38 +02:00
|
|
|
"sort"
|
2020-06-17 21:24:15 +02:00
|
|
|
"strings"
|
2020-10-03 01:41:56 +02:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
|
|
"github.com/hashicorp/terraform/internal/depsfile"
|
2014-05-24 21:04:43 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// VersionCommand is a Command implementation prints the version.
|
|
|
|
type VersionCommand struct {
|
2014-07-13 19:42:18 +02:00
|
|
|
Meta
|
|
|
|
|
2014-05-24 21:04:43 +02:00
|
|
|
Revision string
|
|
|
|
Version string
|
|
|
|
VersionPrerelease string
|
2014-10-13 23:05:29 +02:00
|
|
|
CheckFunc VersionCheckFunc
|
|
|
|
}
|
|
|
|
|
2020-06-15 19:54:49 +02:00
|
|
|
type VersionOutput struct {
|
|
|
|
Version string `json:"terraform_version"`
|
|
|
|
Revision string `json:"terraform_revision"`
|
|
|
|
ProviderSelections map[string]string `json:"provider_selections"`
|
|
|
|
Outdated bool `json:"terraform_outdated"`
|
|
|
|
}
|
|
|
|
|
2014-10-13 23:05:29 +02:00
|
|
|
// 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
|
2014-05-24 21:04:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VersionCommand) Help() string {
|
2020-06-17 21:24:15 +02:00
|
|
|
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)
|
2014-05-24 21:04:43 +02:00
|
|
|
}
|
|
|
|
|
2014-07-13 19:42:18 +02:00
|
|
|
func (c *VersionCommand) Run(args []string) int {
|
2020-06-15 19:54:49 +02:00
|
|
|
var outdated bool
|
2020-08-12 00:18:26 +02:00
|
|
|
var latest string
|
2014-05-24 21:04:43 +02:00
|
|
|
var versionString bytes.Buffer
|
2020-04-01 21:01:08 +02:00
|
|
|
args = c.Meta.process(args)
|
2020-06-15 19:54:49 +02:00
|
|
|
var jsonOutput bool
|
|
|
|
cmdFlags := c.Meta.defaultFlagSet("version")
|
|
|
|
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
|
2020-06-17 21:24:15 +02:00
|
|
|
// 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()) }
|
2020-06-15 19:54:49 +02:00
|
|
|
if err := cmdFlags.Parse(args); err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2014-05-24 21:04:43 +02:00
|
|
|
fmt.Fprintf(&versionString, "Terraform v%s", c.Version)
|
|
|
|
if c.VersionPrerelease != "" {
|
2015-02-07 16:55:59 +01:00
|
|
|
fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
|
2014-05-24 21:04:43 +02:00
|
|
|
|
|
|
|
if c.Revision != "" {
|
|
|
|
fmt.Fprintf(&versionString, " (%s)", c.Revision)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-03 01:41:56 +02:00
|
|
|
// 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.
|
2017-10-24 21:27:38 +02:00
|
|
|
//
|
|
|
|
// 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.
|
2020-10-03 01:41:56 +02:00
|
|
|
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))
|
|
|
|
}
|
2017-10-24 21:27:38 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-03 01:41:56 +02:00
|
|
|
|
2014-10-13 23:05:29 +02:00
|
|
|
// 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()
|
2020-06-15 19:54:49 +02:00
|
|
|
if err != nil && !jsonOutput {
|
2014-10-13 23:05:29 +02:00
|
|
|
c.Ui.Error(fmt.Sprintf(
|
2019-07-06 15:18:13 +02:00
|
|
|
"\nError checking latest version: %s", err))
|
2014-10-13 23:05:29 +02:00
|
|
|
}
|
|
|
|
if info.Outdated {
|
2020-06-15 19:54:49 +02:00
|
|
|
outdated = true
|
2020-08-12 00:18:26 +02:00
|
|
|
latest = info.Latest
|
2020-06-15 19:54:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if jsonOutput {
|
|
|
|
selectionsOutput := make(map[string]string)
|
2020-10-03 01:41:56 +02:00
|
|
|
for providerAddr, lock := range providerLocks {
|
|
|
|
version := lock.Version().String()
|
2020-06-15 19:54:49 +02:00
|
|
|
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,
|
|
|
|
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())
|
2020-10-03 01:41:56 +02:00
|
|
|
if len(providerVersions) != 0 {
|
|
|
|
sort.Strings(providerVersions)
|
|
|
|
for _, str := range providerVersions {
|
2020-06-15 19:54:49 +02:00
|
|
|
c.Ui.Output(str)
|
|
|
|
}
|
2014-10-13 23:05:29 +02:00
|
|
|
}
|
2020-08-12 00:18:26 +02:00
|
|
|
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))
|
|
|
|
}
|
2020-06-15 19:54:49 +02:00
|
|
|
|
2014-10-13 23:05:29 +02:00
|
|
|
}
|
|
|
|
|
2014-05-24 21:04:43 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VersionCommand) Synopsis() string {
|
|
|
|
return "Prints the Terraform version"
|
|
|
|
}
|