"sync"
"sync/atomic"
- "cmd/go/internal/base"
"cmd/go/internal/module"
"cmd/go/internal/par"
)
return buildList(target, reqs, nil)
}
-func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) module.Version) ([]module.Version, error) {
+func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
// Explore work graph in parallel in case reqs.Required
// does high-latency network operations.
type modGraphNode struct {
min = map[string]string{} // maps module path to minimum required version
haveErr int32
)
+ setErr := func(n *modGraphNode, err error) {
+ n.err = err
+ atomic.StoreInt32(&haveErr, 1)
+ }
var work par.Work
work.Add(target)
required, err := reqs.Required(m)
if err != nil {
- node.err = err
- atomic.StoreInt32(&haveErr, 1)
+ setErr(node, err)
return
}
node.required = required
}
if upgrade != nil {
- u := upgrade(m)
- if u.Path == "" {
- base.Errorf("Upgrade(%v) returned zero module", m)
+ u, err := upgrade(m)
+ if err != nil {
+ setErr(node, err)
return
}
if u != m {
// UpgradeAll returns a build list for the target module
// in which every module is upgraded to its latest version.
func UpgradeAll(target module.Version, reqs Reqs) ([]module.Version, error) {
- return buildList(target, reqs, func(m module.Version) module.Version {
+ return buildList(target, reqs, func(m module.Version) (module.Version, error) {
if m.Path == target.Path {
- return target
+ return target, nil
}
- latest, err := reqs.Upgrade(m)
- if err != nil {
- panic(err) // TODO
- }
- m.Version = latest.Version
- return m
+ return reqs.Upgrade(m)
})
}
func Upgrade(target module.Version, reqs Reqs, upgrade ...module.Version) ([]module.Version, error) {
list, err := reqs.Required(target)
if err != nil {
- panic(err) // TODO
+ return nil, err
}
// TODO: Maybe if an error is given,
// rerun with BuildList(upgrade[0], reqs) etc
func Downgrade(target module.Version, reqs Reqs, downgrade ...module.Version) ([]module.Version, error) {
list, err := reqs.Required(target)
if err != nil {
- panic(err) // TODO
+ return nil, err
}
max := make(map[string]string)
for _, r := range list {
}
list, err := reqs.Required(m)
if err != nil {
- panic(err) // TODO
+ // If we can't load the requirements, we couldn't load the go.mod file.
+ // There are a number of reasons this can happen, but this usually
+ // means an older version of the module had a missing or invalid
+ // go.mod file. For example, if example.com/mod released v2.0.0 before
+ // migrating to modules (v2.0.0+incompatible), then added a valid go.mod
+ // in v2.0.1, downgrading from v2.0.1 would cause this error.
+ //
+ // TODO(golang.org/issue/31730, golang.org/issue/30134): if the error
+ // is transient (we couldn't download go.mod), return the error from
+ // Downgrade. Currently, we can't tell what kind of error it is.
+ exclude(m)
}
for _, r := range list {
add(r)
for excluded[r] {
p, err := reqs.Previous(r)
if err != nil {
- return nil, err // TODO
+ // This is likely a transient error reaching the repository,
+ // rather than a permanent error with the retrieved version.
+ //
+ // TODO(golang.org/issue/31730, golang.org/issue/30134):
+ // decode what to do based on the actual error.
+ return nil, err
}
// If the target version is a pseudo-version, it may not be
// included when iterating over prior versions using reqs.Previous.
[short] skip
# downgrade sampler should downgrade quote
+cp go.mod.orig go.mod
go get rsc.io/sampler@v1.0.0
go list -m all
stdout 'rsc.io/quote v1.4.0'
stdout 'rsc.io/sampler v1.0.0'
! stdout golang.org/x/text
--- go.mod --
+# downgrading away quote should also downgrade away latemigrate/v2,
+# since there are no older versions. v2.0.0 is incompatible.
+cp go.mod.orig go.mod
+go list -m -versions example.com/latemigrate/v2
+stdout v2.0.0 # proxy may serve incompatible versions
+go get rsc.io/quote@none
+go list -m all
+! stdout 'example.com/latemigrate/v2'
+
+-- go.mod.orig --
module x
-require rsc.io/quote v1.5.1
+require (
+ rsc.io/quote v1.5.1
+ example.com/latemigrate/v2 v2.0.1
+)
-- go.mod.empty --
module x
-- x.go --