| package tfexec |
| |
| import ( |
| "context" |
| "fmt" |
| "io" |
| "os/exec" |
| "path/filepath" |
| "strings" |
| ) |
| |
| type formatConfig struct { |
| recursive bool |
| dir string |
| } |
| |
| var defaultFormatConfig = formatConfig{ |
| recursive: false, |
| } |
| |
| type FormatOption interface { |
| configureFormat(*formatConfig) |
| } |
| |
| func (opt *RecursiveOption) configureFormat(conf *formatConfig) { |
| conf.recursive = opt.recursive |
| } |
| |
| func (opt *DirOption) configureFormat(conf *formatConfig) { |
| conf.dir = opt.path |
| } |
| |
| // FormatString formats a passed string, given a path to Terraform. |
| func FormatString(ctx context.Context, execPath string, content string) (string, error) { |
| tf, err := NewTerraform(filepath.Dir(execPath), execPath) |
| if err != nil { |
| return "", err |
| } |
| |
| return tf.FormatString(ctx, content) |
| } |
| |
| // FormatString formats a passed string. |
| func (tf *Terraform) FormatString(ctx context.Context, content string) (string, error) { |
| in := strings.NewReader(content) |
| var outBuf strings.Builder |
| err := tf.Format(ctx, in, &outBuf) |
| if err != nil { |
| return "", err |
| } |
| return outBuf.String(), nil |
| } |
| |
| // Format performs formatting on the unformatted io.Reader (as stdin to the CLI) and returns |
| // the formatted result on the formatted io.Writer. |
| func (tf *Terraform) Format(ctx context.Context, unformatted io.Reader, formatted io.Writer) error { |
| cmd, err := tf.formatCmd(ctx, nil, Dir("-")) |
| if err != nil { |
| return err |
| } |
| |
| cmd.Stdin = unformatted |
| cmd.Stdout = mergeWriters(cmd.Stdout, formatted) |
| |
| return tf.runTerraformCmd(ctx, cmd) |
| } |
| |
| // FormatWrite attempts to format and modify all config files in the working or selected (via DirOption) directory. |
| func (tf *Terraform) FormatWrite(ctx context.Context, opts ...FormatOption) error { |
| for _, o := range opts { |
| switch o := o.(type) { |
| case *DirOption: |
| if o.path == "-" { |
| return fmt.Errorf("a path of \"-\" is not supported for this method, please use FormatString") |
| } |
| } |
| } |
| |
| cmd, err := tf.formatCmd(ctx, []string{"-write=true", "-list=false", "-diff=false"}, opts...) |
| if err != nil { |
| return err |
| } |
| |
| return tf.runTerraformCmd(ctx, cmd) |
| } |
| |
| // FormatCheck returns true if the config files in the working or selected (via DirOption) directory are already formatted. |
| func (tf *Terraform) FormatCheck(ctx context.Context, opts ...FormatOption) (bool, []string, error) { |
| for _, o := range opts { |
| switch o := o.(type) { |
| case *DirOption: |
| if o.path == "-" { |
| return false, nil, fmt.Errorf("a path of \"-\" is not supported for this method, please use FormatString") |
| } |
| } |
| } |
| |
| cmd, err := tf.formatCmd(ctx, []string{"-write=false", "-list=true", "-diff=false", "-check=true"}, opts...) |
| if err != nil { |
| return false, nil, err |
| } |
| |
| var outBuf strings.Builder |
| cmd.Stdout = mergeWriters(cmd.Stdout, &outBuf) |
| |
| err = tf.runTerraformCmd(ctx, cmd) |
| if err == nil { |
| return true, nil, nil |
| } |
| if cmd.ProcessState.ExitCode() == 3 { |
| // unformatted, parse the file list |
| |
| files := []string{} |
| lines := strings.Split(strings.Replace(outBuf.String(), "\r\n", "\n", -1), "\n") |
| for _, l := range lines { |
| l = strings.TrimSpace(l) |
| if l == "" { |
| continue |
| } |
| files = append(files, l) |
| } |
| |
| return false, files, nil |
| } |
| return false, nil, err |
| } |
| |
| func (tf *Terraform) formatCmd(ctx context.Context, args []string, opts ...FormatOption) (*exec.Cmd, error) { |
| err := tf.compatible(ctx, tf0_7_7, nil) |
| if err != nil { |
| return nil, fmt.Errorf("fmt was first introduced in Terraform 0.7.7: %w", err) |
| } |
| |
| c := defaultFormatConfig |
| |
| for _, o := range opts { |
| switch o.(type) { |
| case *RecursiveOption: |
| err := tf.compatible(ctx, tf0_12_0, nil) |
| if err != nil { |
| return nil, fmt.Errorf("-recursive was added to fmt in Terraform 0.12: %w", err) |
| } |
| } |
| |
| o.configureFormat(&c) |
| } |
| |
| args = append([]string{"fmt", "-no-color"}, args...) |
| |
| if c.recursive { |
| args = append(args, "-recursive") |
| } |
| |
| if c.dir != "" { |
| args = append(args, c.dir) |
| } |
| |
| return tf.buildTerraformCmd(ctx, nil, args...), nil |
| } |