Files
opentf/internal/command/views/version.go

107 lines
3.7 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package views
import (
"encoding/json"
"fmt"
"maps"
"slices"
"sort"
"github.com/opentofu/opentofu/internal/command/arguments"
"github.com/opentofu/opentofu/internal/tfdiags"
)
type Version interface {
Diagnostics(diags tfdiags.Diagnostics)
// PrintVersion returns true if the printing has been done successfully and false otherwise.
PrintVersion(version string, versionPrerelease string, platform string, fipsEnabled bool, providerVersions map[string]string) bool
}
// NewVersion returns an initialized Version implementation for the given ViewType.
// This view behaves differently from the general approach since the JSON format is not meant to follow
// the general JSON format.
// Instead, the view that is returned will always print diagnostics in human format while
// [Version.PrintVersion] will return different results based on the [arguments.ViewOptions#ViewType].
func NewVersion(args arguments.ViewOptions, view *View) Version {
return &VersionMixed{view: view, json: args.ViewType == arguments.ViewJSON}
}
type VersionMixed struct {
view *View
// In the case of this command, we don't use the [JSONView], but we only marshal the result and print it directly
json bool
}
var _ Version = (*VersionMixed)(nil)
func (v *VersionMixed) Diagnostics(diags tfdiags.Diagnostics) {
v.view.Diagnostics(diags)
}
func (v *VersionMixed) PrintVersion(version string, versionPrerelease string, platform string, fipsEnabled bool, providerVersions map[string]string) bool {
if v.json {
return v.printJsonVersion(version, versionPrerelease, platform, fipsEnabled, providerVersions)
}
return v.printHumanVersion(version, versionPrerelease, platform, fipsEnabled, providerVersions)
}
func (v *VersionMixed) printJsonVersion(version string, versionPrerelease string, platform string, fipsEnabled bool, providerVersions map[string]string) bool {
finalVersion := version
if versionPrerelease != "" {
finalVersion = fmt.Sprintf("%s-%s", finalVersion, versionPrerelease)
}
output := versionOutput{
Version: finalVersion,
Platform: platform,
ProviderSelections: providerVersions,
FIPS140Enabled: fipsEnabled,
}
jsonOutput, err := json.MarshalIndent(output, "", " ")
if err != nil {
_, _ = v.view.streams.Eprintln(fmt.Sprintf("\nError marshalling JSON: %s", err))
return false
}
_, _ = v.view.streams.Println(string(jsonOutput))
return true
}
func (v *VersionMixed) printHumanVersion(version string, versionPrerelease string, platform string, fipsEnabled bool, providerVersions map[string]string) bool {
formattedVersion := fmt.Sprintf("OpenTofu v%s", version)
if versionPrerelease != "" {
formattedVersion = fmt.Sprintf("%s-%s", formattedVersion, versionPrerelease)
}
_, _ = v.view.streams.Println(formattedVersion)
_, _ = v.view.streams.Println(fmt.Sprintf("on %s", platform))
if fipsEnabled {
_, _ = v.view.streams.Println("running in FIPS 140-3 mode (not yet supported)")
}
providerAddrs := slices.Collect(maps.Keys(providerVersions))
sort.Strings(providerAddrs)
for _, provAddr := range providerAddrs {
provVers, ok := providerVersions[provAddr]
if !ok {
continue
}
if provVers == "0.0.0" {
_, _ = v.view.streams.Println(fmt.Sprintf("+ provider %s (unversioned)", provAddr))
} else {
_, _ = v.view.streams.Println(fmt.Sprintf("+ provider %s v%s", provAddr, provVers))
}
}
return true
}
type versionOutput struct {
Version string `json:"terraform_version"`
Platform string `json:"platform"`
FIPS140Enabled bool `json:"fips140,omitempty"`
ProviderSelections map[string]string `json:"provider_selections"`
}