diff --git a/cmd/root.go b/cmd/root.go index 9b22914..f147e0e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -43,8 +43,14 @@ func TerramaidCmd() *cobra.Command { return fmt.Errorf("Terraform directory \"%s\" does not exist", options.TFDir) } - if options.TFDir != "" && !utils.TerraformFilesExist(options.TFDir) { - return fmt.Errorf("Terraform files do not exist in directory \"%s\"", options.TFDir) + if options.TFDir != "" { + exists, err := utils.TerraformFilesExist(options.TFDir) + if err != nil { + return fmt.Errorf("error checking Terraform files in directory \"%s\": %v", options.TFDir, err) + } + if !exists { + return fmt.Errorf("Terraform files do not exist in directory \"%s\"", options.TFDir) + } } if options.WorkingDir != "" && !utils.DirExists(options.WorkingDir) { @@ -68,6 +74,8 @@ func TerramaidCmd() *cobra.Command { }, RunE: func(cmd *cobra.Command, args []string) error { + sp := utils.NewSpinner("Generating Terramaid Diagrams") + sp.Start() graph, err := internal.ParseTerraform(options.WorkingDir, options.TFBinary, options.TFPlan) if err != nil { return fmt.Errorf("error parsing Terraform: %w", err) @@ -91,6 +99,7 @@ func TerramaidCmd() *cobra.Command { return fmt.Errorf("error writing to file: %w", err) } + sp.Stop() fmt.Printf("Mermaid diagram successfully written to %s\n", options.Output) return nil diff --git a/go.mod b/go.mod index 5e02cb1..e0fa717 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,11 @@ go 1.23 require ( github.com/awalterschulze/gographviz v2.0.3+incompatible + github.com/briandowns/spinner v1.23.1 github.com/caarlos0/env/v11 v11.2.2 github.com/fatih/color v1.17.0 github.com/hashicorp/terraform-exec v0.21.0 + github.com/mattn/go-colorable v0.1.13 github.com/spf13/cobra v1.8.1 golang.org/x/text v0.19.0 ) @@ -17,11 +19,11 @@ require ( github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/terraform-json v0.22.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/zclconf/go-cty v1.14.4 // indirect golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.1.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8affef9..03fbac0 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E= github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= +github.com/briandowns/spinner v1.23.1 h1:t5fDPmScwUjozhDj4FA46p5acZWIPXYE30qW2Ptu650= +github.com/briandowns/spinner v1.23.1/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg= github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= @@ -81,6 +83,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 1b3bae5..5b1827e 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,24 +1,39 @@ package utils import ( + "fmt" "os" "path/filepath" + "time" + + "github.com/briandowns/spinner" + "github.com/mattn/go-colorable" +) + +const ( + ColorReset = "\033[0m" + ColorGreen = "\033[32m" + ColorYellow = "\033[33m" + ColorRed = "\033[31m" + ColorBold = "\033[1m" + ColorUnderline = "\033[4m" ) +type Spinner struct { + s *spinner.Spinner +} + // Check if a directory exists func DirExists(dir string) bool { - if _, err := os.Stat(dir); os.IsNotExist(err) { - return false - } - - return true + _, err := os.Stat(dir) + return !os.IsNotExist(err) } // Check if Terraform files exist in a directory -func TerraformFilesExist(dir string) bool { +func TerraformFilesExist(dir string) (bool, error) { validExtensions := []string{".tf", ".tf.json", ".tftest.hcl", ".tftest.json", "terraform.tfvars", "terraform.tfvars.json"} - found := false + var found bool err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -32,8 +47,28 @@ func TerraformFilesExist(dir string) bool { return nil }) if err != nil { - return false + return false, err } - return found + return found, nil +} + +// Initialize a new spinner +func NewSpinner(text string) *Spinner { + s := spinner.New(spinner.CharSets[14], 100*time.Millisecond) + s.Color("blue") + s.Writer = colorable.NewColorableStdout() // Ensure colors are supported on Windows + s.Suffix = " " + text + return &Spinner{s: s} +} + +// Start the spinner +func (sp *Spinner) Start() { + fmt.Printf("%s%s%s ", ColorBold+ColorGreen, sp.s.Suffix, ColorReset) + sp.s.Start() +} + +// Stop the spinner +func (sp *Spinner) Stop() { + sp.s.Stop() }