Skip to content

Commit 619f3d0

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 619f3d0

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-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: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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("(?P<fmt>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+
err := filepath.WalkDir(dirPath, func(path string, d fs.DirEntry, err error) error {
25+
if err != nil {
26+
panic(err)
27+
return err
28+
}
29+
if d.IsDir() {
30+
return nil
31+
}
32+
if !strings.HasSuffix(d.Name(), ".go") {
33+
return nil
34+
}
35+
if strings.Contains(path, "vendor") {
36+
return nil
37+
}
38+
39+
targetsCh <- path
40+
return nil
41+
})
42+
if err != nil {
43+
panic(err)
44+
}
45+
}()
46+
47+
for path := range targetsCh {
48+
if err := searchAndReplace(path); err != nil {
49+
panic(err)
50+
}
51+
}
52+
}
53+
54+
func searchAndReplace(fullPath string) error {
55+
f, err := os.Open(fullPath)
56+
if err != nil {
57+
return err
58+
}
59+
defer f.Close()
60+
61+
blob, err := io.ReadAll(f)
62+
if err != nil {
63+
return err
64+
}
65+
66+
if !reBadFmtErrorf.Match(blob) {
67+
return nil
68+
}
69+
70+
// Preserve the prior permissions.
71+
fi, err := f.Stat()
72+
f.Close()
73+
if err != nil {
74+
return nil
75+
}
76+
wf, err := os.OpenFile(fullPath, os.O_WRONLY, fi.Mode())
77+
if err != nil {
78+
return err
79+
}
80+
defer wf.Close()
81+
82+
ml := reBadFmtErrorf.ReplaceAll(blob, []byte("errors.New(${args})"))
83+
if _, err := wf.Write(ml); err != nil {
84+
panic(err)
85+
}
86+
return nil
87+
}

0 commit comments

Comments
 (0)