From 176a5abfd31556eee212b2263ab2776715608aa3 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 17 Jan 2019 10:58:59 -0800 Subject: [PATCH] command: Restore single-file support in "terraform fmt" This possibility was lost in the rewrite to use HCL2, but it's used by a number of external utilities and text editor integrations, so we'll restore it here. Using the stdin/stdout mode is generally preferable for text editor use since it allows formatting of the in-memory buffer rather than directly the file on disk, but for editors that don't have support for that sort of tooling it can be convenient to just launch a single command and directly modify the on-disk file. --- command/fmt.go | 37 +++++++++++++++++++++++++++++++------ command/fmt_test.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/command/fmt.go b/command/fmt.go index a7ce560b9..427f5fbd9 100644 --- a/command/fmt.go +++ b/command/fmt.go @@ -64,14 +64,14 @@ func (c *FmtCommand) Run(args []string) int { return 1 } - var dirs []string + var paths []string if len(args) == 0 { - dirs = []string{"."} + paths = []string{"."} } else if args[0] == stdinArg { c.list = false c.write = false } else { - dirs = []string{args[0]} + paths = []string{args[0]} } var output io.Writer @@ -86,7 +86,7 @@ func (c *FmtCommand) Run(args []string) int { output = &cli.UiWriter{Ui: c.Ui} } - diags := c.fmt(dirs, c.input, output) + diags := c.fmt(paths, c.input, output) c.showDiagnostics(diags) if diags.HasErrors() { return 2 @@ -123,8 +123,33 @@ func (c *FmtCommand) fmt(paths []string, stdin io.Reader, stdout io.Writer) tfdi for _, path := range paths { path = c.normalizePath(path) - dirDiags := c.processDir(path, stdout) - diags = diags.Append(dirDiags) + info, err := os.Stat(path) + if err != nil { + diags = diags.Append(fmt.Errorf("No file or directory at %s", path)) + return diags + } + if info.IsDir() { + dirDiags := c.processDir(path, stdout) + diags = diags.Append(dirDiags) + } else { + switch filepath.Ext(path) { + case ".tf", ".tfvars": + f, err := os.Open(path) + if err != nil { + // Open does not produce error messages that are end-user-appropriate, + // so we'll need to simplify here. + diags = diags.Append(fmt.Errorf("Failed to read file %s", path)) + continue + } + + fileDiags := c.processFile(c.normalizePath(path), f, stdout, false) + diags = diags.Append(fileDiags) + f.Close() + default: + diags = diags.Append(fmt.Errorf("Only .tf and .tfvars files can be processed with terraform fmt")) + continue + } + } } return diags diff --git a/command/fmt_test.go b/command/fmt_test.go index f09994e04..1828c7f62 100644 --- a/command/fmt_test.go +++ b/command/fmt_test.go @@ -29,7 +29,7 @@ func TestFmt_nonexist(t *testing.T) { t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String()) } - expected := "There is no configuration directory at" + expected := "No file or directory at" if actual := ui.ErrorWriter.String(); !strings.Contains(actual, expected) { t.Fatalf("expected:\n%s\n\nto include: %q", actual, expected) } @@ -148,6 +148,33 @@ func TestFmt_directoryArg(t *testing.T) { } } +func TestFmt_fileArg(t *testing.T) { + tempDir := fmtFixtureWriteDir(t) + + ui := new(cli.MockUi) + c := &FmtCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + }, + } + + args := []string{filepath.Join(tempDir, fmtFixture.filename)} + if code := c.Run(args); code != 0 { + t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String()) + } + + got, err := filepath.Abs(strings.TrimSpace(ui.OutputWriter.String())) + if err != nil { + t.Fatal(err) + } + want := filepath.Join(tempDir, fmtFixture.filename) + + if got != want { + t.Fatalf("wrong output\ngot: %s\nwant: %s", got, want) + } +} + func TestFmt_stdinArg(t *testing.T) { input := new(bytes.Buffer) input.Write(fmtFixture.input)