Skip to content

Commit 9d89b37

Browse files
committed
fmterrorfix: tooling to automatically rewrite fmt.Errorf to errors.New if needed
Implements a CLI tool that'll traverse a directory, find all patterns matching fmt.Errorf without format specifiers and replace in-place such with errors.New. For example for the Go standard library ```shell go run main.go $GOPATH/src/go.googlesource.com ``` Updates golang/go#52696
1 parent c38a69a commit 9d89b37

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

fmterrorffix/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/orijtech/otils/fmterrorffix
2+
3+
go 1.19

fmterrorffix/main.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"io/fs"
6+
"os"
7+
"path/filepath"
8+
"regexp"
9+
"strings"
10+
)
11+
12+
var reBadFmtErrorf = regexp.MustCompile("fmt.Errorf\\((?P<args>\"[^%]*\"|`[^%]*`)\\)")
13+
14+
func main() {
15+
dirPath := "."
16+
if len(os.Args) > 1 {
17+
dirPath = os.Args[1]
18+
}
19+
20+
targetsCh := make(chan string, 10)
21+
go func() {
22+
defer close(targetsCh)
23+
24+
filepath.WalkDir(dirPath, func(path string, d fs.DirEntry, err error) error {
25+
if err != nil {
26+
return err
27+
}
28+
if d.IsDir() {
29+
return nil
30+
}
31+
if !strings.HasSuffix(d.Name(), ".go") {
32+
return nil
33+
}
34+
if strings.Contains(path, "vendor") {
35+
return nil
36+
}
37+
38+
targetsCh <- path
39+
return nil
40+
})
41+
}()
42+
43+
for path := range targetsCh {
44+
searchAndReplace(path)
45+
}
46+
}
47+
48+
func searchAndReplace(fullPath string) error {
49+
f, err := os.Open(fullPath)
50+
if err != nil {
51+
return err
52+
}
53+
defer f.Close()
54+
55+
blob, err := io.ReadAll(f)
56+
if err != nil {
57+
println(err.Error())
58+
return err
59+
}
60+
61+
if !reBadFmtErrorf.Match(blob) {
62+
// println("No matches for ", path)
63+
return nil
64+
}
65+
66+
// Preserve the prior permissions.
67+
fi, err := f.Stat()
68+
f.Close()
69+
if err != nil {
70+
return nil
71+
}
72+
wf, err := os.OpenFile(fullPath, os.O_WRONLY, fi.Mode())
73+
if err != nil {
74+
return err
75+
}
76+
defer wf.Close()
77+
78+
ml := reBadFmtErrorf.ReplaceAll(blob, []byte("errors.New(${args})"))
79+
if _, err := wf.Write(ml); err != nil {
80+
panic(err)
81+
}
82+
return nil
83+
}

0 commit comments

Comments
 (0)