mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 09:48:32 -05:00
Previously the Go toolchain had no explicit support for "tools" and so we used the typical Go community workaround of adding "tools.go" files (two, for some reason) that existed only to trick the Go toolchain into considering the tools as dependencies we could track in go.mod. Go 1.24 introduced explicit support for tracking tools as part of go.mod, and the ability to run those using "go tool" instead of "go run", and so this commit switches us over to using that strategy for everything we were previously managing in tools.go. There are some intentional exceptions here: - The protobuf-compile script can't use "go tool" or "go run" because the tools in question are run only indirectly through protoc. However, we do still use the "tool" directive in go.mod to tell the Go toolchain that we depend on those tools, so that it'll track which versions we are currently using as part of go.mod. - Our golangci-lint Makefile target uses "go run" to run a specific version of golangci-lint. We _intentionally_ don't consider that tool to be a direct dependency of OpenTofu because it has a lot of indirect dependencies that would pollute our go.mod file. Therefore that continues to use "go run" after this commit. - Both of our tools.go files previously referred to github.com/nishanths/exhaustive , but nothing actually appears to be using that tool in the current OpenTofu tree, so it's no longer a dependency after this commit. All of the dependencies we have _only_ for tools are now classified as "indirect" in the go.mod file. This is the default behavior of the Go toolchain and appears to be motivated by making it clearer that these modules do not contribute anything to the runtime behavior of OpenTofu. This also corrected a historical oddity in our go.mod where for some reason the "indirect" dependencies had been split across two different "require" directives; they are now all grouped together in a single directive. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
187 lines
5.6 KiB
Go
187 lines
5.6 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 arguments
|
|
|
|
import (
|
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
|
)
|
|
|
|
// Show represents the command-line arguments for the show command.
|
|
type Show struct {
|
|
// TargetType and TargetArg together describe the object that was
|
|
// requested to be shown.
|
|
//
|
|
// The meaning of TargetArg varies depending on TargetType. Refer to
|
|
// the documentation for each [ShowTargetType] constant for details.
|
|
TargetType ShowTargetType
|
|
TargetArg string
|
|
|
|
// ViewType specifies which output format to use: human, JSON, or "raw".
|
|
ViewType ViewType
|
|
|
|
Vars *Vars
|
|
|
|
// ShowSensitive is used to display the value of variables marked as sensitive.
|
|
ShowSensitive bool
|
|
}
|
|
|
|
// ShowTargetType represents the type of object that is requested to be
|
|
// shown by the "tofu show" command.
|
|
type ShowTargetType int
|
|
|
|
//go:generate go tool golang.org/x/tools/cmd/stringer -type=ShowTargetType
|
|
const (
|
|
// ShowUnknownType is the zero value of [ShowTargetType], and represents
|
|
// that the target type is ambiguous and so must be inferred by the
|
|
// caller based on the [Show.TargetArg] value.
|
|
ShowUnknownType ShowTargetType = iota
|
|
|
|
// ShowState represents a request to show the latest state snapshot.
|
|
//
|
|
// This target type does not use [Show.TargetArg].
|
|
ShowState
|
|
|
|
// ShowPlan represents a request to show a plan loaded from a saved
|
|
// plan file.
|
|
//
|
|
// For this target type, [Show.TargetArg] is the plan file to load.
|
|
ShowPlan
|
|
|
|
// ShowConfig represents a request to show the current configuration.
|
|
//
|
|
// This target type does not use [Show.TargetArg].
|
|
ShowConfig
|
|
|
|
// ShowModule represents a request to show just one module in isolation,
|
|
// without requiring any of its dependencies to be installed.
|
|
//
|
|
// For this target type, [Show.TargetArg] is a path to the directory
|
|
// containing the module.
|
|
ShowModule
|
|
)
|
|
|
|
// ParseShow processes CLI arguments, returning a Show value and errors.
|
|
// If errors are encountered, a Show value is still returned representing
|
|
// the best effort interpretation of the arguments.
|
|
func ParseShow(args []string) (*Show, tfdiags.Diagnostics) {
|
|
var diags tfdiags.Diagnostics
|
|
show := &Show{
|
|
Vars: &Vars{},
|
|
}
|
|
|
|
var jsonOutput bool
|
|
var stateTarget bool
|
|
var planTarget string
|
|
var configTarget bool
|
|
var moduleTarget string
|
|
cmdFlags := extendedFlagSet("show", nil, nil, show.Vars)
|
|
cmdFlags.BoolVar(&jsonOutput, "json", false, "json")
|
|
cmdFlags.BoolVar(&show.ShowSensitive, "show-sensitive", false, "displays sensitive values")
|
|
cmdFlags.BoolVar(&stateTarget, "state", false, "show the latest state snapshot")
|
|
cmdFlags.StringVar(&planTarget, "plan", "", "show the plan from a saved plan file")
|
|
cmdFlags.BoolVar(&configTarget, "config", false, "show the current configuration")
|
|
cmdFlags.StringVar(&moduleTarget, "module", "", "show metadata about one module")
|
|
|
|
if err := cmdFlags.Parse(args); err != nil {
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Failed to parse command-line options",
|
|
err.Error(),
|
|
))
|
|
}
|
|
|
|
// If -config or -module=... is selected, -json is required
|
|
if configTarget && !jsonOutput {
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"JSON output required for configuration",
|
|
"The -config option requires -json to be specified.",
|
|
))
|
|
return show, diags
|
|
}
|
|
if moduleTarget != "" && !jsonOutput {
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"JSON output required for module",
|
|
"The -module=DIR option requires -json to be specified.",
|
|
))
|
|
return show, diags
|
|
}
|
|
|
|
switch {
|
|
case jsonOutput:
|
|
show.ViewType = ViewJSON
|
|
default:
|
|
show.ViewType = ViewHuman
|
|
}
|
|
|
|
if planTarget == "" && moduleTarget == "" && !stateTarget && !configTarget {
|
|
// If none of the target type options was provided then we're
|
|
// in the legacy mode where the target type is implied by
|
|
// the number of arguments.
|
|
args = cmdFlags.Args()
|
|
switch len(args) {
|
|
case 0:
|
|
show.TargetType = ShowState
|
|
show.TargetArg = ""
|
|
case 1:
|
|
// This case is ambiguous: the argument could be either
|
|
// a saved plan file or a local state snapshot such as
|
|
// the output from "tofu state pull". The caller will need
|
|
// to probe TargetArg to decide which it is.
|
|
show.TargetType = ShowUnknownType
|
|
show.TargetArg = args[0]
|
|
default:
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Too many command line arguments",
|
|
"Expected at most one positional argument for the legacy positional argument mode.",
|
|
))
|
|
}
|
|
return show, diags
|
|
}
|
|
|
|
// The following handles the modern mode where the target type is
|
|
// chosen based on which target type option was used.
|
|
if len(cmdFlags.Args()) != 0 {
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Unexpected command line arguments",
|
|
"This command does not expect any positional arguments when using a target-selection option.",
|
|
))
|
|
return show, diags
|
|
}
|
|
targetTypes := 0
|
|
if stateTarget {
|
|
targetTypes++
|
|
show.TargetType = ShowState
|
|
show.TargetArg = ""
|
|
}
|
|
if planTarget != "" {
|
|
targetTypes++
|
|
show.TargetType = ShowPlan
|
|
show.TargetArg = planTarget
|
|
}
|
|
if configTarget {
|
|
targetTypes++
|
|
show.TargetType = ShowConfig
|
|
show.TargetArg = ""
|
|
}
|
|
if moduleTarget != "" {
|
|
targetTypes++
|
|
show.TargetType = ShowModule
|
|
show.TargetArg = moduleTarget
|
|
}
|
|
if targetTypes != 1 {
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Conflicting object types to show",
|
|
"The -state, -plan=FILENAME, -config, and -module=DIR options are mutually-exclusive, to specify which kind of object to show.",
|
|
))
|
|
}
|
|
return show, diags
|
|
}
|