From dc0954f90361a044b1d976a5a43fb833c01b59da Mon Sep 17 00:00:00 2001 From: "Christian G. Warden" Date: Mon, 16 Dec 2024 09:11:45 -0600 Subject: [PATCH] Run Formatters Concurrently When formatting multiple files, use multiple goroutines to speed up formatting. --- cmd/root.go | 102 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 9a5b86d..23f850a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,6 +3,8 @@ package cmd import ( "fmt" "os" + "runtime" + "sync" "github.com/octoberswimmer/apexfmt/formatter" log "github.com/sirupsen/logrus" @@ -41,10 +43,12 @@ var RootCmd = &cobra.Command{ if verbose { log.SetLevel(log.DebugLevel) } + formatters := []*formatter.Formatter{} for _, filename := range args { formatters = append(formatters, formatter.NewFormatter(filename, nil)) } + if len(args) == 0 { if write { return fmt.Errorf("One or more files required for --write option") @@ -54,43 +58,77 @@ var RootCmd = &cobra.Command{ } formatters = append(formatters, formatter.NewFormatter("", os.Stdin)) } + + var wg sync.WaitGroup + errors := make(chan error, len(formatters)) + outputs := make(chan string, len(formatters)) + + semSize := runtime.GOMAXPROCS(0) + if !write && !list { + semSize = 1 + } + + sem := make(chan struct{}, semSize) + for _, f := range formatters { - err := f.Format() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to format file %s: %s\n", f.SourceName(), err.Error()) - os.Exit(1) - } + wg.Add(1) + go func(f *formatter.Formatter) { + defer wg.Done() - if list { - changed, err := f.Changed() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to check file for changes %s: %s\n", f.SourceName(), err.Error()) - os.Exit(1) - } - if changed { - fmt.Println(f.SourceName()) - } - } else if !write { - out, err := f.Formatted() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to get formatted source %s: %s\n", f.SourceName(), err.Error()) - os.Exit(1) + sem <- struct{}{} + defer func() { <-sem }() + + if err := f.Format(); err != nil { + errors <- fmt.Errorf("Failed to format file %s: %s", f.SourceName(), err) + return } - fmt.Println(out) - } - changed, err := f.Changed() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to check file for changes %s: %s\n", f.SourceName(), err.Error()) - os.Exit(1) - } - if write && changed { - err = f.Write() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to write file %s: %s\n", f.SourceName(), err.Error()) - os.Exit(1) + + if list { + changed, err := f.Changed() + if err != nil { + errors <- fmt.Errorf("Failed to check file for changes %s: %s", f.SourceName(), err) + return + } + if changed { + outputs <- f.SourceName() + } + } else if !write { + out, err := f.Formatted() + if err != nil { + errors <- fmt.Errorf("Failed to get formatted source %s: %s", f.SourceName(), err) + return + } + outputs <- out + } else { + changed, err := f.Changed() + if err != nil { + errors <- fmt.Errorf("Failed to check file for changes %s: %s", f.SourceName(), err) + return + } + if changed { + if err = f.Write(); err != nil { + errors <- fmt.Errorf("Failed to write file %s: %s", f.SourceName(), err) + } + } } - } + }(f) } + + go func() { + wg.Wait() + close(errors) + close(outputs) + }() + + for output := range outputs { + fmt.Println(output) + } + + for err := range errors { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + return nil }, DisableFlagsInUseLine: true,