@@ -192,8 +192,8 @@ func limiterForEdit(ctx context.Context, rs *Requirements, tryUpgrade, mustSelec
192
192
193
193
// raiseLimitsForUpgrades increases the module versions in maxVersions to the
194
194
// versions that would be needed to allow each of the modules in tryUpgrade
195
- // (individually) and all of the modules in mustSelect (simultaneously) to be
196
- // added as roots.
195
+ // (individually or in any combination ) and all of the modules in mustSelect
196
+ // (simultaneously) to be added as roots.
197
197
//
198
198
// Versions not present in maxVersion are unrestricted, and it is assumed that
199
199
// they will not be promoted to root requirements (and thus will not contribute
@@ -215,18 +215,42 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, p
215
215
}
216
216
}
217
217
218
- var unprunedUpgrades []module.Version
218
+ var (
219
+ unprunedUpgrades []module.Version
220
+ isPrunedRootPath map [string ]bool
221
+ )
219
222
if pruning == unpruned {
220
223
unprunedUpgrades = tryUpgrade
221
224
} else {
225
+ isPrunedRootPath = make (map [string ]bool , len (maxVersion ))
226
+ for p := range maxVersion {
227
+ isPrunedRootPath [p ] = true
228
+ }
222
229
for _ , m := range tryUpgrade {
230
+ isPrunedRootPath [m .Path ] = true
231
+ }
232
+ for _ , m := range mustSelect {
233
+ isPrunedRootPath [m .Path ] = true
234
+ }
235
+
236
+ allowedRoot := map [module.Version ]bool {}
237
+
238
+ var allowRoot func (m module.Version ) error
239
+ allowRoot = func (m module.Version ) error {
240
+ if allowedRoot [m ] {
241
+ return nil
242
+ }
243
+ allowedRoot [m ] = true
244
+
223
245
if MainModules .Contains (m .Path ) {
224
- // The main module versions are already considered to be higher than any possible m, so we
225
- // won't be upgrading to it anyway and there is no point scanning its
226
- // dependencies.
227
- continue
246
+ // The main module versions are already considered to be higher than any
247
+ // possible m, so m cannot be selected as a root and there is no point
248
+ // scanning its dependencies.
249
+ return nil
228
250
}
229
251
252
+ allow (m )
253
+
230
254
summary , err := goModSummary (m )
231
255
if err != nil {
232
256
return err
@@ -236,13 +260,27 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, p
236
260
// graph, rather than loading the (potentially-overlapping) subgraph for
237
261
// each upgrade individually.
238
262
unprunedUpgrades = append (unprunedUpgrades , m )
239
- continue
263
+ return nil
240
264
}
241
-
242
- allow (m )
243
265
for _ , r := range summary .require {
244
- allow (r )
266
+ if isPrunedRootPath [r .Path ] {
267
+ // r could become a root as the result of an upgrade or downgrade,
268
+ // in which case its dependencies will not be pruned out.
269
+ // We need to allow those dependencies to be upgraded too.
270
+ if err := allowRoot (r ); err != nil {
271
+ return err
272
+ }
273
+ } else {
274
+ // r will not become a root, so its dependencies don't matter.
275
+ // Allow only r itself.
276
+ allow (r )
277
+ }
245
278
}
279
+ return nil
280
+ }
281
+
282
+ for _ , m := range tryUpgrade {
283
+ allowRoot (m )
246
284
}
247
285
}
248
286
@@ -269,16 +307,41 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, p
269
307
}
270
308
}
271
309
272
- if len (mustSelect ) > 0 {
273
- mustGraph , err := readModGraph (ctx , pruning , 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 (pruning , nextRoots , nil )
315
+ nextRoots = nil
316
+
317
+ rs , mustGraph , err := expandGraph (ctx , rs )
274
318
if err != nil {
275
319
return err
276
320
}
277
321
278
322
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).
281
326
allow (r )
327
+
328
+ if isPrunedRootPath [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
+ }
282
345
}
283
346
}
284
347
0 commit comments