|  | package tfexec | 
|  |  | 
|  | import ( | 
|  | "context" | 
|  | "fmt" | 
|  | "os/exec" | 
|  | "strings" | 
|  |  | 
|  | tfjson "github.com/hashicorp/terraform-json" | 
|  | ) | 
|  |  | 
|  | type showConfig struct { | 
|  | reattachInfo ReattachInfo | 
|  | } | 
|  |  | 
|  | var defaultShowOptions = showConfig{} | 
|  |  | 
|  | type ShowOption interface { | 
|  | configureShow(*showConfig) | 
|  | } | 
|  |  | 
|  | func (opt *ReattachOption) configureShow(conf *showConfig) { | 
|  | conf.reattachInfo = opt.info | 
|  | } | 
|  |  | 
|  | // Show reads the default state path and outputs the state. | 
|  | // To read a state or plan file, ShowState or ShowPlan must be used instead. | 
|  | func (tf *Terraform) Show(ctx context.Context, opts ...ShowOption) (*tfjson.State, error) { | 
|  | err := tf.compatible(ctx, tf0_12_0, nil) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err) | 
|  | } | 
|  |  | 
|  | c := defaultShowOptions | 
|  |  | 
|  | for _, o := range opts { | 
|  | o.configureShow(&c) | 
|  | } | 
|  |  | 
|  | mergeEnv := map[string]string{} | 
|  | if c.reattachInfo != nil { | 
|  | reattachStr, err := c.reattachInfo.marshalString() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | mergeEnv[reattachEnvVar] = reattachStr | 
|  | } | 
|  |  | 
|  | showCmd := tf.showCmd(ctx, true, mergeEnv) | 
|  |  | 
|  | var ret tfjson.State | 
|  | ret.UseJSONNumber(true) | 
|  | err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | err = ret.Validate() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return &ret, nil | 
|  | } | 
|  |  | 
|  | // ShowStateFile reads a given state file and outputs the state. | 
|  | func (tf *Terraform) ShowStateFile(ctx context.Context, statePath string, opts ...ShowOption) (*tfjson.State, error) { | 
|  | err := tf.compatible(ctx, tf0_12_0, nil) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err) | 
|  | } | 
|  |  | 
|  | if statePath == "" { | 
|  | return nil, fmt.Errorf("statePath cannot be blank: use Show() if not passing statePath") | 
|  | } | 
|  |  | 
|  | c := defaultShowOptions | 
|  |  | 
|  | for _, o := range opts { | 
|  | o.configureShow(&c) | 
|  | } | 
|  |  | 
|  | mergeEnv := map[string]string{} | 
|  | if c.reattachInfo != nil { | 
|  | reattachStr, err := c.reattachInfo.marshalString() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | mergeEnv[reattachEnvVar] = reattachStr | 
|  | } | 
|  |  | 
|  | showCmd := tf.showCmd(ctx, true, mergeEnv, statePath) | 
|  |  | 
|  | var ret tfjson.State | 
|  | ret.UseJSONNumber(true) | 
|  | err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | err = ret.Validate() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return &ret, nil | 
|  | } | 
|  |  | 
|  | // ShowPlanFile reads a given plan file and outputs the plan. | 
|  | func (tf *Terraform) ShowPlanFile(ctx context.Context, planPath string, opts ...ShowOption) (*tfjson.Plan, error) { | 
|  | err := tf.compatible(ctx, tf0_12_0, nil) | 
|  | if err != nil { | 
|  | return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err) | 
|  | } | 
|  |  | 
|  | if planPath == "" { | 
|  | return nil, fmt.Errorf("planPath cannot be blank: use Show() if not passing planPath") | 
|  | } | 
|  |  | 
|  | c := defaultShowOptions | 
|  |  | 
|  | for _, o := range opts { | 
|  | o.configureShow(&c) | 
|  | } | 
|  |  | 
|  | mergeEnv := map[string]string{} | 
|  | if c.reattachInfo != nil { | 
|  | reattachStr, err := c.reattachInfo.marshalString() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | mergeEnv[reattachEnvVar] = reattachStr | 
|  | } | 
|  |  | 
|  | showCmd := tf.showCmd(ctx, true, mergeEnv, planPath) | 
|  |  | 
|  | var ret tfjson.Plan | 
|  | err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | err = ret.Validate() | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return &ret, nil | 
|  |  | 
|  | } | 
|  |  | 
|  | // ShowPlanFileRaw reads a given plan file and outputs the plan in a | 
|  | // human-friendly, opaque format. | 
|  | func (tf *Terraform) ShowPlanFileRaw(ctx context.Context, planPath string, opts ...ShowOption) (string, error) { | 
|  | if planPath == "" { | 
|  | return "", fmt.Errorf("planPath cannot be blank: use Show() if not passing planPath") | 
|  | } | 
|  |  | 
|  | c := defaultShowOptions | 
|  |  | 
|  | for _, o := range opts { | 
|  | o.configureShow(&c) | 
|  | } | 
|  |  | 
|  | mergeEnv := map[string]string{} | 
|  | if c.reattachInfo != nil { | 
|  | reattachStr, err := c.reattachInfo.marshalString() | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  | mergeEnv[reattachEnvVar] = reattachStr | 
|  | } | 
|  |  | 
|  | showCmd := tf.showCmd(ctx, false, mergeEnv, planPath) | 
|  |  | 
|  | var outBuf strings.Builder | 
|  | showCmd.Stdout = &outBuf | 
|  | err := tf.runTerraformCmd(ctx, showCmd) | 
|  | if err != nil { | 
|  | return "", err | 
|  | } | 
|  |  | 
|  | return outBuf.String(), nil | 
|  |  | 
|  | } | 
|  |  | 
|  | func (tf *Terraform) showCmd(ctx context.Context, jsonOutput bool, mergeEnv map[string]string, args ...string) *exec.Cmd { | 
|  | allArgs := []string{"show"} | 
|  | if jsonOutput { | 
|  | allArgs = append(allArgs, "-json") | 
|  | } | 
|  | allArgs = append(allArgs, "-no-color") | 
|  | allArgs = append(allArgs, args...) | 
|  |  | 
|  | return tf.buildTerraformCmd(ctx, mergeEnv, allArgs...) | 
|  | } |