// roots — but in a lazy module it may pull in previously-irrelevant
// transitive dependencies.
- newRS, rsErr := updateRoots(ctx, rs.direct, rs)
+ newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil)
if rsErr != nil {
// Failed to update roots, perhaps because of an error in a transitive
// dependency needed for the update. Return the original Requirements
// (if it is not "none").
// 2. Each root is the selected version of its path. (We say that such a root
// set is “consistent”.)
-// 3. Every version selected in the graph of rs remains selected.
-func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements) (*Requirements, error) {
+// 3. Every version selected in the graph of rs remains selected unless upgraded
+// by a dependency in add.
+// 4. Every version in add is selected at its given version unless upgraded by
+// an existing root or another module in add.
+func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
mg, err := rs.Graph(ctx)
if err != nil {
// We can't ignore errors in the module graph even if the user passed the -e
return rs, errGoModDirty
}
}
+ for _, m := range add {
+ if m.Version != mg.Selected(m.Path) {
+ return rs, errGoModDirty
+ }
+ }
for mPath := range direct {
if _, ok := rs.rootSelected(mPath); !ok {
// Module m is supposed to be listed explicitly, but isn't.
if go117LazyTODO {
// Update the above comment to reflect lazy loading once implemented.
}
- keep := mg.BuildList()[1:]
+ keep := append(mg.BuildList()[1:], add...)
for _, m := range keep {
if direct[m.Path] && !inRootPaths[m.Path] {
rootPaths = append(rootPaths, m.Path)
for _, n := range mPathCount {
if n > 1 {
var err error
- rs, err = updateRoots(ctx, rs.direct, rs)
+ rs, err = updateRoots(ctx, rs.direct, rs, nil)
if err != nil {
base.Fatalf("go: %v", err)
}
}
module.Sort(toAdd) // to make errors deterministic
- rs, changed, err := editRequirements(ctx, ld.requirements, toAdd, nil)
- if err != nil {
+ prevRS := ld.requirements
+ if err := ld.updateRequirements(ctx, toAdd); err != nil {
// If an error was found in a newly added module, report the package
// import stack instead of the module requirement stack. Packages
// are more descriptive.
}
base.Fatalf("go: %v", err)
}
- ld.requirements = rs
-
- if !changed {
- break
+ if reflect.DeepEqual(prevRS.rootModules, ld.requirements.rootModules) {
+ // Something is deeply wrong. resolveMissingImports gave us a non-empty
+ // set of modules to add, but adding those modules to the graph had no
+ // effect.
+ panic(fmt.Sprintf("internal error: adding %v to module graph had no effect on root requirements (%v)", toAdd, prevRS.rootModules))
}
}
base.ExitIfErrors() // TODO(bcmills): Is this actually needed?
- if err := ld.updateRequirements(ctx); err != nil {
+ if err := ld.updateRequirements(ctx, nil); err != nil {
base.Fatalf("go: %v", err)
}
return ld
}
-// updateRequirements ensures that ld.requirements is consistent with
-// the information gained from ld.pkgs.
+// updateRequirements ensures that ld.requirements is consistent with the
+// information gained from ld.pkgs and includes the modules in add as roots at
+// at least the given versions.
//
// In particular:
//
// not provide any directly-imported package are then marked as indirect.
//
// - Root dependencies are updated to their selected versions.
-func (ld *loader) updateRequirements(ctx context.Context) error {
+func (ld *loader) updateRequirements(ctx context.Context, add []module.Version) error {
rs := ld.requirements
// Compute directly referenced dependency modules.
}
}
- rs, err := updateRoots(ctx, direct, rs)
+ rs, err := updateRoots(ctx, direct, rs, add)
if err == nil {
ld.requirements = rs
}