github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/command/version.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/cycloidio/terraform/addrs"
    11  	"github.com/cycloidio/terraform/depsfile"
    12  	"github.com/cycloidio/terraform/getproviders"
    13  )
    14  
    15  // VersionCommand is a Command implementation prints the version.
    16  type VersionCommand struct {
    17  	Meta
    18  
    19  	Version           string
    20  	VersionPrerelease string
    21  	CheckFunc         VersionCheckFunc
    22  	Platform          getproviders.Platform
    23  }
    24  
    25  type VersionOutput struct {
    26  	Version            string            `json:"terraform_version"`
    27  	Platform           string            `json:"platform"`
    28  	ProviderSelections map[string]string `json:"provider_selections"`
    29  	Outdated           bool              `json:"terraform_outdated"`
    30  }
    31  
    32  // VersionCheckFunc is the callback called by the Version command to
    33  // check if there is a new version of Terraform.
    34  type VersionCheckFunc func() (VersionCheckInfo, error)
    35  
    36  // VersionCheckInfo is the return value for the VersionCheckFunc callback
    37  // and tells the Version command information about the latest version
    38  // of Terraform.
    39  type VersionCheckInfo struct {
    40  	Outdated bool
    41  	Latest   string
    42  	Alerts   []string
    43  }
    44  
    45  func (c *VersionCommand) Help() string {
    46  	helpText := `
    47  Usage: terraform [global options] version [options]
    48  
    49    Displays the version of Terraform and all installed plugins
    50  
    51  Options:
    52  
    53    -json       Output the version information as a JSON object.
    54  `
    55  	return strings.TrimSpace(helpText)
    56  }
    57  
    58  func (c *VersionCommand) Run(args []string) int {
    59  	var outdated bool
    60  	var latest string
    61  	var versionString bytes.Buffer
    62  	args = c.Meta.process(args)
    63  	var jsonOutput bool
    64  	cmdFlags := c.Meta.defaultFlagSet("version")
    65  	cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
    66  	// Enable but ignore the global version flags. In main.go, if any of the
    67  	// arguments are -v, -version, or --version, this command will be called
    68  	// with the rest of the arguments, so we need to be able to cope with
    69  	// those.
    70  	cmdFlags.Bool("v", true, "version")
    71  	cmdFlags.Bool("version", true, "version")
    72  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    73  	if err := cmdFlags.Parse(args); err != nil {
    74  		c.Ui.Error(fmt.Sprintf("Error parsing command-line flags: %s\n", err.Error()))
    75  		return 1
    76  	}
    77  
    78  	fmt.Fprintf(&versionString, "Terraform v%s", c.Version)
    79  	if c.VersionPrerelease != "" {
    80  		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
    81  	}
    82  
    83  	// We'll also attempt to print out the selected plugin versions. We do
    84  	// this based on the dependency lock file, and so the result might be
    85  	// empty or incomplete if the user hasn't successfully run "terraform init"
    86  	// since the most recent change to dependencies.
    87  	//
    88  	// Generally-speaking this is a best-effort thing that will give us a good
    89  	// result in the usual case where the user successfully ran "terraform init"
    90  	// and then hit a problem running _another_ command.
    91  	var providerVersions []string
    92  	var providerLocks map[addrs.Provider]*depsfile.ProviderLock
    93  	if locks, err := c.lockedDependencies(); err == nil {
    94  		providerLocks = locks.AllProviders()
    95  		for providerAddr, lock := range providerLocks {
    96  			version := lock.Version().String()
    97  			if version == "0.0.0" {
    98  				providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s (unversioned)", providerAddr))
    99  			} else {
   100  				providerVersions = append(providerVersions, fmt.Sprintf("+ provider %s v%s", providerAddr, version))
   101  			}
   102  		}
   103  	}
   104  
   105  	// If we have a version check function, then let's check for
   106  	// the latest version as well.
   107  	if c.CheckFunc != nil {
   108  		// Check the latest version
   109  		info, err := c.CheckFunc()
   110  		if err != nil && !jsonOutput {
   111  			c.Ui.Error(fmt.Sprintf(
   112  				"\nError checking latest version: %s", err))
   113  		}
   114  		if info.Outdated {
   115  			outdated = true
   116  			latest = info.Latest
   117  		}
   118  	}
   119  
   120  	if jsonOutput {
   121  		selectionsOutput := make(map[string]string)
   122  		for providerAddr, lock := range providerLocks {
   123  			version := lock.Version().String()
   124  			selectionsOutput[providerAddr.String()] = version
   125  		}
   126  
   127  		var versionOutput string
   128  		if c.VersionPrerelease != "" {
   129  			versionOutput = c.Version + "-" + c.VersionPrerelease
   130  		} else {
   131  			versionOutput = c.Version
   132  		}
   133  
   134  		output := VersionOutput{
   135  			Version:            versionOutput,
   136  			Platform:           c.Platform.String(),
   137  			ProviderSelections: selectionsOutput,
   138  			Outdated:           outdated,
   139  		}
   140  
   141  		jsonOutput, err := json.MarshalIndent(output, "", "  ")
   142  		if err != nil {
   143  			c.Ui.Error(fmt.Sprintf("\nError marshalling JSON: %s", err))
   144  			return 1
   145  		}
   146  		c.Ui.Output(string(jsonOutput))
   147  		return 0
   148  	} else {
   149  		c.Ui.Output(versionString.String())
   150  		c.Ui.Output(fmt.Sprintf("on %s", c.Platform))
   151  
   152  		if len(providerVersions) != 0 {
   153  			sort.Strings(providerVersions)
   154  			for _, str := range providerVersions {
   155  				c.Ui.Output(str)
   156  			}
   157  		}
   158  		if outdated {
   159  			c.Ui.Output(fmt.Sprintf(
   160  				"\nYour version of Terraform is out of date! The latest version\n"+
   161  					"is %s. You can update by downloading from https://www.terraform.io/downloads.html",
   162  				latest))
   163  		}
   164  
   165  	}
   166  
   167  	return 0
   168  }
   169  
   170  func (c *VersionCommand) Synopsis() string {
   171  	return "Show the current Terraform version"
   172  }