Skip to content

Commit 328cf2e

Browse files
Bryan C. Millstoothrot
Bryan C. Mills
authored andcommitted
[release-branch.go1.17] cmd/go/internal/modload: scan dependencies of root paths when raising version limits in editRequirements
Updates #47979 Fixes #48156 Change-Id: I1d9d854cda1378e20c70e6c6789b77e42e467ca7 Reviewed-on: https://go-review.googlesource.com/c/go/+/347290 Trust: Bryan C. Mills <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]> (cherry picked from commit 409434d) Reviewed-on: https://go-review.googlesource.com/c/go/+/348411
1 parent fcce86c commit 328cf2e

File tree

2 files changed

+192
-12
lines changed

2 files changed

+192
-12
lines changed

src/cmd/go/internal/modload/edit.go

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
190190

191191
// raiseLimitsForUpgrades increases the module versions in maxVersions to the
192192
// versions that would be needed to allow each of the modules in tryUpgrade
193-
// (individually) and all of the modules in mustSelect (simultaneously) to be
194-
// added as roots.
193+
// (individually or in any combination) and all of the modules in mustSelect
194+
// (simultaneously) to be added as roots.
195195
//
196196
// Versions not present in maxVersion are unrestricted, and it is assumed that
197197
// they will not be promoted to root requirements (and thus will not contribute
@@ -213,18 +213,42 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
213213
}
214214
}
215215

216-
var eagerUpgrades []module.Version
216+
var (
217+
eagerUpgrades []module.Version
218+
isLazyRootPath map[string]bool
219+
)
217220
if depth == eager {
218221
eagerUpgrades = tryUpgrade
219222
} else {
223+
isLazyRootPath = make(map[string]bool, len(maxVersion))
224+
for p := range maxVersion {
225+
isLazyRootPath[p] = true
226+
}
220227
for _, m := range tryUpgrade {
228+
isLazyRootPath[m.Path] = true
229+
}
230+
for _, m := range mustSelect {
231+
isLazyRootPath[m.Path] = true
232+
}
233+
234+
allowedRoot := map[module.Version]bool{}
235+
236+
var allowRoot func(m module.Version) error
237+
allowRoot = func(m module.Version) error {
238+
if allowedRoot[m] {
239+
return nil
240+
}
241+
allowedRoot[m] = true
242+
221243
if m.Path == Target.Path {
222244
// Target is already considered to be higher than any possible m, so we
223245
// won't be upgrading to it anyway and there is no point scanning its
224246
// dependencies.
225-
continue
247+
return nil
226248
}
227249

250+
allow(m)
251+
228252
summary, err := goModSummary(m)
229253
if err != nil {
230254
return err
@@ -234,13 +258,27 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
234258
// graph, rather than loading the (potentially-overlapping) subgraph for
235259
// each upgrade individually.
236260
eagerUpgrades = append(eagerUpgrades, m)
237-
continue
261+
return nil
238262
}
239-
240-
allow(m)
241263
for _, r := range summary.require {
242-
allow(r)
264+
if isLazyRootPath[r.Path] {
265+
// r could become a root as the result of an upgrade or downgrade,
266+
// in which case its dependencies will not be pruned out.
267+
// We need to allow those dependencies to be upgraded too.
268+
if err := allowRoot(r); err != nil {
269+
return err
270+
}
271+
} else {
272+
// r will not become a root, so its dependencies don't matter.
273+
// Allow only r itself.
274+
allow(r)
275+
}
243276
}
277+
return nil
278+
}
279+
280+
for _, m := range tryUpgrade {
281+
allowRoot(m)
244282
}
245283
}
246284

@@ -269,16 +307,41 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
269307
}
270308
}
271309

272-
if len(mustSelect) > 0 {
273-
mustGraph, err := readModGraph(ctx, depth, mustSelect)
310+
// Explicitly allow any (transitive) upgrades implied by mustSelect.
311+
nextRoots := append([]module.Version(nil), mustSelect...)
312+
for nextRoots != nil {
313+
module.Sort(nextRoots)
314+
rs := newRequirements(depth, nextRoots, nil)
315+
nextRoots = nil
316+
317+
rs, mustGraph, err := expandGraph(ctx, rs)
274318
if err != nil {
275319
return err
276320
}
277321

278322
for _, r := range mustGraph.BuildList() {
279-
// Some module in mustSelect requires r, so we must allow at least r.Version
280-
// unless it conflicts with an entry in mustSelect.
323+
// Some module in mustSelect requires r, so we must allow at least
324+
// r.Version (unless it conflicts with another entry in mustSelect, in
325+
// which case we will error out either way).
281326
allow(r)
327+
328+
if isLazyRootPath[r.Path] {
329+
if v, ok := rs.rootSelected(r.Path); ok && r.Version == v {
330+
// r is already a root, so its requirements are already included in
331+
// the build list.
332+
continue
333+
}
334+
335+
// The dependencies in mustSelect may upgrade (or downgrade) an existing
336+
// root to match r, which will remain as a root. However, since r is not
337+
// a root of rs, its dependencies have been pruned out of this build
338+
// list. We need to add it back explicitly so that we allow any
339+
// transitive upgrades that r will pull in.
340+
if nextRoots == nil {
341+
nextRoots = rs.rootModules // already capped
342+
}
343+
nextRoots = append(nextRoots, r)
344+
}
282345
}
283346
}
284347

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Regression test for https://golang.org/issue/47979:
2+
#
3+
# An argument to 'go get' that results in an upgrade to a different existing
4+
# root should be allowed, and should not panic the 'go' command.
5+
6+
cp go.mod go.mod.orig
7+
8+
9+
# Transitive upgrades from upgraded roots should not prevent
10+
# 'go get -u' from performing upgrades.
11+
12+
cp go.mod.orig go.mod
13+
go get -u -d .
14+
cmp go.mod go.mod.want
15+
16+
17+
# 'go get' of a specific version should allow upgrades of
18+
# every dependency (transitively) required by that version,
19+
# including dependencies that are pulled into the module
20+
# graph by upgrading other root requirements
21+
# (in this case, example.net/indirect).
22+
23+
cp go.mod.orig go.mod
24+
go get -d example.net/[email protected]
25+
cmp go.mod go.mod.want
26+
27+
28+
-- go.mod --
29+
module golang.org/issue47979
30+
31+
go 1.17
32+
33+
replace (
34+
example.net/a v0.1.0 => ./a1
35+
example.net/a v0.2.0 => ./a2
36+
example.net/indirect v0.1.0 => ./indirect1
37+
example.net/indirect v0.2.0 => ./indirect2
38+
example.net/other v0.1.0 => ./other
39+
example.net/other v0.2.0 => ./other
40+
)
41+
42+
require (
43+
example.net/a v0.1.0
44+
example.net/other v0.1.0
45+
)
46+
47+
require example.net/indirect v0.1.0 // indirect
48+
-- go.mod.want --
49+
module golang.org/issue47979
50+
51+
go 1.17
52+
53+
replace (
54+
example.net/a v0.1.0 => ./a1
55+
example.net/a v0.2.0 => ./a2
56+
example.net/indirect v0.1.0 => ./indirect1
57+
example.net/indirect v0.2.0 => ./indirect2
58+
example.net/other v0.1.0 => ./other
59+
example.net/other v0.2.0 => ./other
60+
)
61+
62+
require (
63+
example.net/a v0.2.0
64+
example.net/other v0.2.0
65+
)
66+
67+
require example.net/indirect v0.2.0 // indirect
68+
-- issue.go --
69+
package issue
70+
71+
import _ "example.net/a"
72+
-- useother/useother.go --
73+
package useother
74+
75+
import _ "example.net/other"
76+
-- a1/go.mod --
77+
module example.net/a
78+
79+
go 1.17
80+
81+
require example.net/indirect v0.1.0
82+
-- a1/a.go --
83+
package a
84+
-- a2/go.mod --
85+
module example.net/a
86+
87+
go 1.17
88+
89+
require example.net/indirect v0.2.0
90+
-- a2/a.go --
91+
package a
92+
93+
import "example.net/indirect"
94+
-- indirect1/go.mod --
95+
module example.net/indirect
96+
97+
go 1.17
98+
99+
require example.net/other v0.1.0
100+
-- indirect1/indirect.go --
101+
package indirect
102+
-- indirect2/go.mod --
103+
module example.net/indirect
104+
105+
go 1.17
106+
107+
require example.net/other v0.2.0
108+
-- indirect2/indirect.go --
109+
package indirect
110+
111+
import "example.net/other"
112+
-- other/go.mod --
113+
module example.net/other
114+
115+
go 1.17
116+
-- other/other.go --
117+
package other

0 commit comments

Comments
 (0)