Skip to content

Commit 4c7a8d6

Browse files
zx2c4Bryan C. Mills
authored andcommitted
cmd/go/internal/modfile: remove preceding empty lines when setting require
When rewriting a go.mod file, we currently sort all of the require lines in a block. The way the parser works is that it considers preceding blank lines to be empty comment lines, and preceding empty comment lines are "owned" by their adjoining line. So when we go to sort them, the empty lines follow around each sorted entry, which doesn't make a whole lot of sense, since usually vertical space is inserted to show sections, and if things get moved around by sorting, those sections are no longer meaningful. This all results in one especially troublesome edge case: blank lines between a block opening ("require (") and the first block line ("golang.org/x/sys ...") are not treated the same way and are rewritten out of existence. Here's an example of the behavior this fixes. Starting input file: require ( golang.zx2c4.com/wireguard master golang.org/x/crypto latest golang.org/x/net latest golang.org/x/sys latest golang.org/x/text latest github.com/lxn/walk latest github.com/lxn/win latest ) Now we run this through `GOPROXY=direct go get -d`: require ( github.com/lxn/walk v0.0.0-20190619151032-86d8802c197a github.com/lxn/win v0.0.0-20190716185335-d1d36f0e4f48 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a golang.org/x/text v0.3.2 golang.zx2c4.com/wireguard v0.0.20190806-0.20190822065259-3cedc22d7b49 ) Notice how the blank lines before lxn/walk and x/crypto were preserved. Finally, we have this be rewritten yet again with a call to `go build`: require ( github.com/lxn/walk v0.0.0-20190619151032-86d8802c197a github.com/lxn/win v0.0.0-20190716185335-d1d36f0e4f48 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a golang.org/x/text v0.3.2 golang.zx2c4.com/wireguard v0.0.20190806-0.20190822065259-3cedc22d7b49 ) In this final resting point, the first blank line has been removed. The discrepancy between those two last stages are especially bothersome, because it makes for lots of dirty git commits and file contents bouncing back and forth. This commit fixes the problem as mentioned above, getting rid of those preceding blank lines. The output in all cases looks as it should, like this: require ( github.com/lxn/walk v0.0.0-20190619151032-86d8802c197a github.com/lxn/win v0.0.0-20190716185335-d1d36f0e4f48 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a golang.org/x/text v0.3.2 golang.zx2c4.com/wireguard v0.0.20190806-0.20190822065259-3cedc22d7b49 ) Fixes #33779 Change-Id: I11c894440bd35f343ee62db3e06a50fa871f2599 Reviewed-on: https://go-review.googlesource.com/c/go/+/199917 Run-TryBot: Jason A. Donenfeld <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 829fae3 commit 4c7a8d6

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/cmd/go/internal/modfile/rule.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,9 @@ func (f *File) SetRequire(req []*Require) {
566566
var newLines []*Line
567567
for _, line := range stmt.Line {
568568
if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" {
569+
if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 {
570+
line.Comments.Before = line.Comments.Before[:0]
571+
}
569572
line.Token[1] = need[p]
570573
delete(need, p)
571574
setIndirect(line, indirect[p])

src/cmd/go/internal/modfile/rule_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"bytes"
99
"fmt"
1010
"testing"
11+
12+
"cmd/go/internal/module"
1113
)
1214

1315
var addRequireTests = []struct {
@@ -59,6 +61,40 @@ var addRequireTests = []struct {
5961
},
6062
}
6163

64+
var setRequireTests = []struct {
65+
in string
66+
mods []struct {
67+
path string
68+
vers string
69+
}
70+
out string
71+
}{
72+
{
73+
`module m
74+
require (
75+
x.y/b v1.2.3
76+
77+
x.y/a v1.2.3
78+
)
79+
`,
80+
[]struct {
81+
path string
82+
vers string
83+
}{
84+
{"x.y/a", "v1.2.3"},
85+
{"x.y/b", "v1.2.3"},
86+
{"x.y/c", "v1.2.3"},
87+
},
88+
`module m
89+
require (
90+
x.y/a v1.2.3
91+
x.y/b v1.2.3
92+
x.y/c v1.2.3
93+
)
94+
`,
95+
},
96+
}
97+
6298
func TestAddRequire(t *testing.T) {
6399
for i, tt := range addRequireTests {
64100
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
@@ -88,3 +124,40 @@ func TestAddRequire(t *testing.T) {
88124
})
89125
}
90126
}
127+
128+
func TestSetRequire(t *testing.T) {
129+
for i, tt := range setRequireTests {
130+
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
131+
f, err := Parse("in", []byte(tt.in), nil)
132+
if err != nil {
133+
t.Fatal(err)
134+
}
135+
g, err := Parse("out", []byte(tt.out), nil)
136+
if err != nil {
137+
t.Fatal(err)
138+
}
139+
golden, err := g.Format()
140+
if err != nil {
141+
t.Fatal(err)
142+
}
143+
var mods []*Require
144+
for _, mod := range tt.mods {
145+
mods = append(mods, &Require{
146+
Mod: module.Version{
147+
Path: mod.path,
148+
Version: mod.vers,
149+
},
150+
})
151+
}
152+
153+
f.SetRequire(mods)
154+
out, err := f.Format()
155+
if err != nil {
156+
t.Fatal(err)
157+
}
158+
if !bytes.Equal(out, golden) {
159+
t.Errorf("have:\n%s\nwant:\n%s", out, golden)
160+
}
161+
})
162+
}
163+
}

0 commit comments

Comments
 (0)