Skip to content

Commit

Permalink
[Ch4364] terradoc fmt (#31)
Browse files Browse the repository at this point in the history
* [ch4364] feat: add `terradoc fmt`

* on main_test, build binary in tmp dir
  • Loading branch information
Nathan Thiesen authored Jan 28, 2022
1 parent aefce0d commit ca83ee0
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 168 deletions.
6 changes: 6 additions & 0 deletions cmd/terradoc/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package cli

var Cli struct {
Generate GenerateCmd `cmd:"" help:"Generate a markdown file from .tfdoc.hcl input."`
Format FormatCmd `name:"fmt" cmd:"" help:"Format .tfdoc.hcl file."`
}
35 changes: 35 additions & 0 deletions cmd/terradoc/cli/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cli

import (
"fmt"
"io/ioutil"
"os"

"github.com/hashicorp/hcl/v2/hclwrite"
)

type FormatCmd struct {
InputFile string `arg:"" help:"Input file." type:"existingfile"`
Write bool `name:"write" short:"w" help:"Overwrite file with formatted version."`
}

func (f FormatCmd) Run() error {
inSrc, err := ioutil.ReadFile(f.InputFile)
if err != nil {
return fmt.Errorf("reading input: %s", err)
}

outSrc := hclwrite.Format(inSrc)

if f.Write {
err = ioutil.WriteFile(f.InputFile, outSrc, 0644)
} else {
_, err = os.Stdout.Write(outSrc)
}

if err != nil {
return fmt.Errorf("writing result: %s", err)
}

return nil
}
81 changes: 81 additions & 0 deletions cmd/terradoc/cli/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cli

import (
"fmt"
"io"
"os"

"github.com/mineiros-io/terradoc/internal/parser/hclparser"
"github.com/mineiros-io/terradoc/internal/renderers/markdown"
)

type GenerateCmd struct {
InputFile string `arg:"" required:"" help:"Input file." type:"existingfile"`
OutputFile string `name:"output" short:"o" optional:"" default:"-" help:"Output file to write resulting markdown to" type:"path"`
}

func (g GenerateCmd) Run() error {
r, rCloser, err := openInput(g.InputFile)
if err != nil {
return fmt.Errorf("opening input: %s\n", err)
}
defer rCloser()

w, wCloser, err := getOutputWriter(g.OutputFile)
if err != nil {
return fmt.Errorf("creating writer: %s\n", err)
}
defer wCloser()

def, err := hclparser.Parse(r, r.Name())
if err != nil {
return fmt.Errorf("parsing input: %v", err)
}

err = markdown.Render(w, def)
if err != nil {
return fmt.Errorf("rendering document: %v", err)
}

return nil
}

func openInput(path string) (*os.File, func(), error) {
if path == "-" {
return os.Stdin, noopClose, nil
}

f, err := os.Open(path)
if err != nil {
return nil, nil, err
}

closer := func() {
if err := f.Close(); err != nil {
fmt.Fprintf(os.Stderr, "closing input stream: %v", err)
}
}

return f, closer, nil
}

func getOutputWriter(filename string) (io.Writer, func(), error) {
if filename == "-" {
return os.Stdout, noopClose, nil
}

f, err := os.Create(filename)
if err != nil {
return nil, nil, err
}

closer := func() {
if err := f.Close(); err != nil {
fmt.Fprintf(os.Stderr, "closing output stream: %v", err)
}
}

return f, closer, nil
}

func noopClose() {}
88 changes: 5 additions & 83 deletions cmd/terradoc/main.go
Original file line number Diff line number Diff line change
@@ -1,90 +1,12 @@
package main

import (
"flag"
"fmt"
"io"
"os"

"github.com/mineiros-io/terradoc/internal/parser/hclparser"
"github.com/mineiros-io/terradoc/internal/renderers/markdown"
"github.com/alecthomas/kong"
"github.com/mineiros-io/terradoc/cmd/terradoc/cli"
)

func main() {
outputFile := flag.String("o", "", "Output file name")

flag.Parse()

r, rCloser, err := openInput(flag.Args()...)
if err != nil {
fmt.Fprintf(os.Stderr, "reading input: %s\n", err)

os.Exit(1)
}
defer rCloser()

def, err := hclparser.Parse(r, r.Name())
if err != nil {
fmt.Fprintf(os.Stderr, "parsing document: %v", err)

os.Exit(1)
}

w, wCloser, err := getOutputWriter(*outputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "creating writer: %s\n", err)

os.Exit(1)
}
defer wCloser()

err = markdown.Render(w, def)
if err != nil {
fmt.Fprintf(os.Stderr, "rendering document: %v", err)

os.Exit(1)
}
ctx := kong.Parse(&cli.Cli)
err := ctx.Run()
ctx.FatalIfErrorf(err)
}

func getOutputWriter(filename string) (io.Writer, func(), error) {
if filename == "" {
return os.Stdout, noopClose, nil
}

f, err := os.Create(filename)
if err != nil {
return nil, nil, err
}

closer := func() {
if err := f.Close(); err != nil {
fmt.Fprintf(os.Stderr, "closing output stream: %v", err)
}
}

return f, closer, nil
}

func openInput(args ...string) (*os.File, func(), error) {
switch len(args) {
case 0:
return os.Stdin, noopClose, nil
case 1:
f, err := os.Open(args[0])
if err != nil {
return nil, nil, err
}

closer := func() {
if err := f.Close(); err != nil {
fmt.Fprintf(os.Stderr, "closing input stream: %v", err)
}
}

return f, closer, nil
default:
return nil, nil, fmt.Errorf("expects none or one input file but given %d", len(args))
}
}

func noopClose() {}
103 changes: 76 additions & 27 deletions cmd/terradoc/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,32 @@ import (
)

var (
binName = "terradoc"
inputFixtureName = "golden-input.tfdoc.hcl"
expectedOutputFixtureName = "golden-readme.md"
binName = "terradoc"
generateInput = "golden-input.tfdoc.hcl"
formatInput = "unformatted-input.tfdoc.hcl"
expectedGenerateOutput = "golden-readme.md"
expectedFormatOutput = "formatted-input.tfdoc.hcl"
)

var terradocBinPath string

func TestMain(m *testing.M) {
fmt.Println("Building tool...")

if runtime.GOOS == "windows" {
binName += ".exe"
}

build := exec.Command("go", "build", "-o", binName)
binTmpdir, err := os.MkdirTemp("", "cmd-terradoc-test-")
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot create temp dir: %v", err)
os.Exit(1)
}

terradocBinPath = filepath.Join(binTmpdir, binName)

err := build.Run()
build := exec.Command("go", "build", "-o", terradocBinPath)
err = build.Run()
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot build %q: %v", binName, err)
os.Exit(1)
Expand All @@ -41,44 +52,40 @@ func TestMain(m *testing.M) {
result := m.Run()

fmt.Println("Cleaning up...")

os.Remove(binName)
err = os.RemoveAll(binTmpdir)
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot clean up temp dir %q: %v", binTmpdir, err)
}

os.Exit(result)
}

func TestTerradocCLI(t *testing.T) {
dir, err := os.Getwd()
assert.NoError(t, err)

// set up input file and content - TODO: structure this better
inputContent := test.ReadFixture(t, inputFixtureName)

func TestGenerate(t *testing.T) {
inputContent := test.ReadFixture(t, generateInput)
// create tempfile
inputFile, err := ioutil.TempFile("", "terradoc-input-")
assert.NoError(t, err)

defer inputFile.Close()

// write content to tempfile
_, err = inputFile.Write(inputContent)
assert.NoError(t, err)

cmdPath := filepath.Join(dir, binName)
defer inputFile.Close()

expectedOutput := test.ReadFixture(t, expectedOutputFixtureName)
expectedOutput := test.ReadFixture(t, expectedGenerateOutput)

t.Run("ReadFromFile", func(t *testing.T) {
cmd := exec.Command(cmdPath, inputFile.Name())
cmd := exec.Command(terradocBinPath, "generate", inputFile.Name())

output, err := cmd.CombinedOutput()
assert.NoError(t, err)

if diff := cmp.Diff(output, expectedOutput); diff != "" {
if diff := cmp.Diff(expectedOutput, output); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})

t.Run("ReadFromSTDIN", func(t *testing.T) {
cmd := exec.Command(cmdPath)
cmd := exec.Command(terradocBinPath, "generate", "-")

cmdStdIn, err := cmd.StdinPipe()
assert.NoError(t, err)
Expand All @@ -91,18 +98,18 @@ func TestTerradocCLI(t *testing.T) {
output, err := cmd.CombinedOutput()
assert.NoError(t, err)

if diff := cmp.Diff(output, expectedOutput); diff != "" {
if diff := cmp.Diff(expectedOutput, output); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})

t.Run("WriteToStdout", func(t *testing.T) {
cmd := exec.Command(cmdPath, inputFile.Name())
cmd := exec.Command(terradocBinPath, "generate", inputFile.Name())

output, err := cmd.CombinedOutput()
assert.NoError(t, err)

if diff := cmp.Diff(output, expectedOutput); diff != "" {
if diff := cmp.Diff(expectedOutput, output); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})
Expand All @@ -112,15 +119,57 @@ func TestTerradocCLI(t *testing.T) {
assert.NoError(t, err)
defer f.Close()

cmd := exec.Command(cmdPath, "-o", f.Name(), inputFile.Name())
cmd := exec.Command(terradocBinPath, "generate", "-o", f.Name(), inputFile.Name())

err = cmd.Run()
assert.NoError(t, err)

result, err := ioutil.ReadAll(f)
assert.NoError(t, err)

if diff := cmp.Diff(result, expectedOutput); diff != "" {
if diff := cmp.Diff(expectedOutput, result); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})
}

func TestFormat(t *testing.T) {
unformattedInput := test.ReadFixture(t, formatInput)
// create another file with unformattedFile content to test overwrites
inputFile, err := ioutil.TempFile("", "terradoc-fmt-output-")
assert.NoError(t, err)
// write unformatted input to file
_, err = inputFile.Write(unformattedInput)
assert.NoError(t, err)

defer inputFile.Close()

expectedFormattedOutput := test.ReadFixture(t, expectedFormatOutput)

t.Run("WriteToStdout", func(t *testing.T) {
cmd := exec.Command(terradocBinPath, "fmt", inputFile.Name())

output, err := cmd.CombinedOutput()
assert.NoError(t, err)

if diff := cmp.Diff(expectedFormattedOutput, output); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})

t.Run("OverwriteFile", func(t *testing.T) {
cmd := exec.Command(terradocBinPath, "fmt", "-w", inputFile.Name())

_, err := cmd.CombinedOutput()
assert.NoError(t, err)

_, err = inputFile.Seek(0, 0)
assert.NoError(t, err)

persistedResult, err := ioutil.ReadAll(inputFile)
assert.NoError(t, err)

if diff := cmp.Diff(expectedFormattedOutput, persistedResult); diff != "" {
t.Errorf("Result is not expected (-want +got):\n%s", diff)
}
})
Expand Down
Loading

0 comments on commit ca83ee0

Please sign in to comment.