Skip to content

Commit e1479bc

Browse files
committed
playground: format go.mod files; fix paths in formatting errors
Previously, handleFmt applied gofmt/goimports formatting to .go files only. This change makes it apply formatting to go.mod files as well. The cmd/go/internal/modfile package (well, a non-internal copy thereof) is used to perform the go.mod file formatting. Add test cases for error messages, and fix some cases where the paths weren't accurate. Detect when the error was returned by format.Source and needs to be prefixed by using the fixImports variable instead of checking for the presence of the prefix. This makes the code simpler and more readable. Replace old fs.m[f] usage with fs.Data(f) in fmt.go and txtar_test.go. Updates golang/go#32040 Updates golang/go#31944 Change-Id: Iefef7337f962914817558bcf0c622a952160ac44 Reviewed-on: https://go-review.googlesource.com/c/playground/+/177421 Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent a7b4d4c commit e1479bc

File tree

4 files changed

+88
-26
lines changed

4 files changed

+88
-26
lines changed

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ RUN go install cloud.google.com/go/datastore
5151
RUN go install github.com/bradfitz/gomemcache/memcache
5252
RUN go install golang.org/x/tools/godoc/static
5353
RUN go install golang.org/x/tools/imports
54+
RUN go install github.com/rogpeppe/go-internal/modfile
5455
RUN go install github.com/rogpeppe/go-internal/txtar
5556

5657
# Add and compile playground daemon

fmt.go

+39-22
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import (
99
"fmt"
1010
"go/format"
1111
"net/http"
12-
"strings"
12+
"path"
1313

14+
"github.com/rogpeppe/go-internal/modfile"
1415
"golang.org/x/tools/imports"
1516
)
1617

@@ -30,30 +31,46 @@ func handleFmt(w http.ResponseWriter, r *http.Request) {
3031

3132
fixImports := r.FormValue("imports") != ""
3233
for _, f := range fs.files {
33-
if !strings.HasSuffix(f, ".go") {
34-
continue
35-
}
36-
var out []byte
37-
var err error
38-
in := fs.m[f]
39-
if fixImports {
40-
// TODO: pass options to imports.Process so it
41-
// can find symbols in sibling files.
42-
out, err = imports.Process(progName, in, nil)
43-
} else {
44-
out, err = format.Source(in)
45-
}
46-
if err != nil {
47-
errMsg := err.Error()
48-
// Prefix the error returned by format.Source.
49-
if !strings.HasPrefix(errMsg, f) {
50-
errMsg = fmt.Sprintf("%v:%v", f, errMsg)
34+
switch {
35+
case path.Ext(f) == ".go":
36+
var out []byte
37+
var err error
38+
in := fs.Data(f)
39+
if fixImports {
40+
// TODO: pass options to imports.Process so it
41+
// can find symbols in sibling files.
42+
out, err = imports.Process(f, in, nil)
43+
} else {
44+
out, err = format.Source(in)
45+
}
46+
if err != nil {
47+
errMsg := err.Error()
48+
if !fixImports {
49+
// Unlike imports.Process, format.Source does not prefix
50+
// the error with the file path. So, do it ourselves here.
51+
errMsg = fmt.Sprintf("%v:%v", f, errMsg)
52+
}
53+
json.NewEncoder(w).Encode(fmtResponse{Error: errMsg})
54+
return
55+
}
56+
fs.AddFile(f, out)
57+
case path.Base(f) == "go.mod":
58+
out, err := formatGoMod(f, fs.Data(f))
59+
if err != nil {
60+
json.NewEncoder(w).Encode(fmtResponse{Error: err.Error()})
61+
return
5162
}
52-
json.NewEncoder(w).Encode(fmtResponse{Error: errMsg})
53-
return
63+
fs.AddFile(f, out)
5464
}
55-
fs.AddFile(f, out)
5665
}
5766

5867
json.NewEncoder(w).Encode(fmtResponse{Body: string(fs.Format())})
5968
}
69+
70+
func formatGoMod(file string, data []byte) ([]byte, error) {
71+
f, err := modfile.Parse(file, data, nil)
72+
if err != nil {
73+
return nil, err
74+
}
75+
return f.Format()
76+
}

fmt_test.go

+47-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,53 @@ func TestHandleFmt(t *testing.T) {
4747
want: "package main\n-- two.go --\npackage main\n\nvar X = 5\n",
4848
},
4949
{
50-
name: "only_format_go",
51-
body: " package main\n\n\n-- go.mod --\n module foo\n",
52-
want: "package main\n-- go.mod --\n module foo\n",
50+
name: "single_go.mod_with_header",
51+
body: "-- go.mod --\n module \"foo\" ",
52+
want: "-- go.mod --\nmodule foo\n",
53+
},
54+
{
55+
name: "multi_go.mod_with_header",
56+
body: "-- a/go.mod --\n module foo\n\n\n-- b/go.mod --\n module \"bar\"",
57+
want: "-- a/go.mod --\nmodule foo\n-- b/go.mod --\nmodule bar\n",
58+
},
59+
{
60+
name: "only_format_go_and_go.mod",
61+
body: " package main \n\n\n" +
62+
"-- go.mod --\n module foo \n\n\n" +
63+
"-- plain.txt --\n plain text \n\n\n",
64+
want: "package main\n-- go.mod --\nmodule foo\n-- plain.txt --\n plain text \n\n\n",
65+
},
66+
{
67+
name: "error_gofmt",
68+
body: "package 123\n",
69+
wantErr: "prog.go:1:9: expected 'IDENT', found 123",
70+
},
71+
{
72+
name: "error_gofmt_with_header",
73+
body: "-- dir/one.go --\npackage 123\n",
74+
wantErr: "dir/one.go:1:9: expected 'IDENT', found 123",
75+
},
76+
{
77+
name: "error_goimports",
78+
body: "package 123\n",
79+
imports: true,
80+
wantErr: "prog.go:1:9: expected 'IDENT', found 123",
81+
},
82+
{
83+
name: "error_goimports_with_header",
84+
body: "-- dir/one.go --\npackage 123\n",
85+
imports: true,
86+
wantErr: "dir/one.go:1:9: expected 'IDENT', found 123",
87+
},
88+
{
89+
name: "error_go.mod",
90+
body: "-- go.mod --\n123\n",
91+
wantErr: "go.mod:1: unknown directive: 123",
92+
},
93+
{
94+
name: "error_go.mod_with_header",
95+
body: "-- dir/go.mod --\n123\n",
96+
wantErr: "dir/go.mod:1: unknown directive: 123",
5397
},
5498
} {
5599
t.Run(tt.name, func(t *testing.T) {

txtar_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func filesAsString(fs *fileSet) string {
147147
if i == 0 && f == progName && fs.noHeader {
148148
implicit = " (implicit)"
149149
}
150-
fmt.Fprintf(&sb, "[file %q%s]: %q\n", f, implicit, fs.m[f])
150+
fmt.Fprintf(&sb, "[file %q%s]: %q\n", f, implicit, fs.Data(f))
151151
}
152152
return sb.String()
153153
}

0 commit comments

Comments
 (0)