Skip to content

Commit

Permalink
feat: improve error handling in format Run method
Browse files Browse the repository at this point in the history
When reviewing #511, I noticed there was some shadowing of variables and edge cases which were not being handled gracefully.

Signed-off-by: Brian McGee <[email protected]>
  • Loading branch information
brianmcgee committed Jan 23, 2025
1 parent 45881a4 commit 30e1ecd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 21 deletions.
63 changes: 44 additions & 19 deletions cmd/format/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,45 +167,70 @@ func Run(v *viper.Viper, statz *stats.Stats, cmd *cobra.Command, paths []string)
// start traversing
files := make([]*walk.File, BatchSize)

var (
n int
readErr, formatErr error
)

for {
// read the next batch
readCtx, cancel := context.WithTimeout(ctx, 1*time.Second)
n, err := walker.Read(readCtx, files)
readCtx, cancelRead := context.WithTimeout(ctx, 1*time.Second)

n, readErr = walker.Read(readCtx, files)
log.Debugf("read %d files", n)

// ensure context is cancelled to release resources
cancel()
cancelRead()

// format
if err := formatter.Apply(ctx, files[:n]); err != nil {
return fmt.Errorf("formatting failure: %w", err)
// format any files that were read before processing the read error
if formatErr = formatter.Apply(ctx, files[:n]); formatErr != nil {
break
}

if errors.Is(err, io.EOF) {
// we have finished traversing
// stop reading files if there was a read error
if readErr != nil {
break
} else if err != nil {
// something went wrong
return fmt.Errorf("failed to read files: %w", err)
}
}

// finalize formatting
formatErr := formatter.Close(ctx)
// finalize formatting (there could be formatting tasks in-flight)
formatCloseErr := formatter.Close(ctx)

// close the walker, ensuring any pending file release hooks finish
if err = walker.Close(); err != nil {
return fmt.Errorf("failed to close walker: %w", err)
}
walkerCloseErr := walker.Close()

// print stats to stderr
if !cfg.Quiet {
statz.PrintToStderr()
}

// process errors

//nolint:gocritic
if errors.Is(readErr, io.EOF) {
// nothing more to read, reset the error and break out of the read loop
log.Debugf("no more files to read")
} else if errors.Is(readErr, context.DeadlineExceeded) {
// the read timed-out
return errors.New("timeout reading files")
} else if readErr != nil {
// something unexpected happened
return fmt.Errorf("failed to read files: %w", readErr)
}

if formatErr != nil {
// return an error if any formatting failures were detected
return formatErr //nolint:wrapcheck
} else if cfg.FailOnChange && statz.Value(stats.Changed) != 0 {
return fmt.Errorf("failed to format files: %w", formatErr)
}

if formatCloseErr != nil {
return fmt.Errorf("failed to finalise formatting: %w", formatCloseErr)
}

if walkerCloseErr != nil {
return fmt.Errorf("failed to close walker: %w", walkerCloseErr)
}

if cfg.FailOnChange && statz.Value(stats.Changed) != 0 {
// if fail on change has been enabled, check that no files were actually changed, throwing an error if so
return ErrFailOnChange
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1433,12 +1433,12 @@ func TestGit(t *testing.T) {
}),
)

// try with a path not in the git index, e.g. it is skipped
// try with a path not in the git index
_, err := os.Create(filepath.Join(tempDir, "foo.txt"))
as.NoError(err)

treefmt(t,
withArgs("haskell", "foo.txt"),
withArgs("haskell", "foo.txt", "-vv"),
withConfig(configPath, cfg),
withNoError(t),
withStats(t, map[stats.Type]int{
Expand Down

0 comments on commit 30e1ecd

Please sign in to comment.