@@ -11,7 +11,6 @@ import (
11
11
"cmd/go/internal/get"
12
12
"cmd/go/internal/imports"
13
13
"cmd/go/internal/load"
14
- "cmd/go/internal/modfetch"
15
14
"cmd/go/internal/modload"
16
15
"cmd/go/internal/module"
17
16
"cmd/go/internal/mvs"
@@ -60,11 +59,12 @@ dependency should be removed entirely, downgrading or removing modules
60
59
depending on it as needed.
61
60
62
61
The version suffix @latest explicitly requests the latest minor release of the
63
- given path.
64
-
65
- The suffix @patch requests the latest patch release: if the path is already in
66
- the build list, the selected version will have the same minor version.
67
- If the path is not already in the build list, @patch is equivalent to @latest.
62
+ given path. The suffix @patch requests the latest patch release: if the path
63
+ is already in the build list, the selected version will have the same minor
64
+ version. If the path is not already in the build list, @patch is equivalent
65
+ to @latest. Neither @latest nor @patch will cause 'go get' to downgrade a module
66
+ in the build list if it is required at a newer pre-release version that is
67
+ newer than the latest released version.
68
68
69
69
Although get defaults to using the latest version of the module containing
70
70
a named package, it does not use the latest version of that module's
@@ -219,10 +219,13 @@ type querySpec struct {
219
219
vers string
220
220
221
221
// forceModulePath is true if path should be interpreted as a module path.
222
+ // If forceModulePath is true, prevM must be set.
222
223
forceModulePath bool
223
224
224
225
// prevM is the previous version of the module. prevM is needed
225
- // if vers is "patch", and the module was previously in the build list.
226
+ // to determine the minor version number if vers is "patch". It's also
227
+ // used to avoid downgrades from prerelease versions newer than
228
+ // "latest" and "patch". If prevM is set, forceModulePath must be true.
226
229
prevM module.Version
227
230
}
228
231
@@ -266,7 +269,12 @@ func runGet(cmd *base.Command, args []string) {
266
269
base .Fatalf ("go get: disabled by -mod=%s" , cfg .BuildMod )
267
270
}
268
271
269
- modload .LoadBuildList ()
272
+ buildList := modload .LoadBuildList ()
273
+ buildList = buildList [:len (buildList ):len (buildList )] // copy on append
274
+ versionByPath := make (map [string ]string )
275
+ for _ , m := range buildList {
276
+ versionByPath [m .Path ] = m .Version
277
+ }
270
278
271
279
// Do not allow any updating of go.mod until we've applied
272
280
// all the requested changes and checked that the result matches
@@ -356,33 +364,66 @@ func runGet(cmd *base.Command, args []string) {
356
364
continue
357
365
}
358
366
359
- if vers == "patch" {
360
- // We need to know the previous version of the module to find
361
- // the new version, but we don't know what module provides this
362
- // package yet. Wait until we load packages later.
363
- // TODO(golang.org/issue/30634): @latest should also depend on
364
- // the current version to prevent downgrading from newer pseudoversions.
365
- } else {
366
- // The requested version of path doesn't depend on the existing version,
367
- // so query the module before loading the package. This may let us
368
- // load the package only once at the correct version.
369
- queries = append (queries , & query {querySpec : querySpec {path : path , vers : vers }, arg : arg })
367
+ first := path
368
+ if i := strings .IndexByte (first , '/' ); i >= 0 {
369
+ first = path
370
+ }
371
+ if ! strings .Contains (first , "." ) {
372
+ // The path doesn't have a dot in the first component and cannot be
373
+ // queried as a module. It may be a package in the standard library,
374
+ // which is fine, so don't report an error unless we encounter
375
+ // a problem loading packages below.
376
+ continue
377
+ }
378
+
379
+ // If we're querying "latest" or "patch", we need to know the current
380
+ // version of the module. For "latest", we want to avoid accidentally
381
+ // downgrading from a newer prerelease. For "patch", we need to query
382
+ // the correct minor version.
383
+ // Here, we check if "path" is the name of a module in the build list
384
+ // (other than the main module) and set prevM if so. If "path" isn't
385
+ // a module in the build list, the current version doesn't matter
386
+ // since it's either an unknown module or a package within a module
387
+ // that we'll discover later.
388
+ q := & query {querySpec : querySpec {path : path , vers : vers }, arg : arg }
389
+ if v , ok := versionByPath [path ]; ok && path != modload .Target .Path {
390
+ q .prevM = module.Version {Path : path , Version : v }
391
+ q .forceModulePath = true
370
392
}
393
+ queries = append (queries , q )
371
394
}
372
395
}
373
396
base .ExitIfErrors ()
374
397
375
- // Query modules referenced by command line arguments at requested versions,
376
- // and add them to the build list. We need to do this before loading packages
377
- // since patterns that refer to packages in unknown modules can't be
378
- // expanded. This also avoids looking up new modules while loading packages,
379
- // only to downgrade later.
398
+ // Query modules referenced by command line arguments at requested versions.
399
+ // We need to do this before loading packages since patterns that refer to
400
+ // packages in unknown modules can't be expanded. This also avoids looking
401
+ // up new modules while loading packages, only to downgrade later.
380
402
queryCache := make (map [querySpec ]* query )
381
403
byPath := runQueries (queryCache , queries , nil )
382
404
383
- // Add queried modules to the build list. This prevents some additional
384
- // lookups for modules at "latest" when we load packages later.
385
- buildList , err := mvs .UpgradeAll (modload .Target , newUpgrader (byPath , nil ))
405
+ // Add missing modules to the build list.
406
+ // We call SetBuildList here and elsewhere, since newUpgrader,
407
+ // ImportPathsQuiet, and other functions read the global build list.
408
+ for _ , q := range queries {
409
+ if _ , ok := versionByPath [q .m .Path ]; ! ok && q .m .Version != "none" {
410
+ buildList = append (buildList , q .m )
411
+ }
412
+ }
413
+ versionByPath = nil // out of date now; rebuilt later when needed
414
+ modload .SetBuildList (buildList )
415
+
416
+ // Upgrade modules specifically named on the command line. This is our only
417
+ // chance to upgrade modules without root packages (modOnly below).
418
+ // This also skips loading packages at an old version, only to upgrade
419
+ // and reload at a new version.
420
+ upgrade := make (map [string ]* query )
421
+ for path , q := range byPath {
422
+ if q .path == q .m .Path && q .m .Version != "none" {
423
+ upgrade [path ] = q
424
+ }
425
+ }
426
+ buildList , err := mvs .UpgradeAll (modload .Target , newUpgrader (upgrade , nil ))
386
427
if err != nil {
387
428
base .Fatalf ("go get: %v" , err )
388
429
}
@@ -478,6 +519,10 @@ func runGet(cmd *base.Command, args []string) {
478
519
continue
479
520
}
480
521
allStd = false
522
+ if m .Path == modload .Target .Path {
523
+ // pkg is in the main module.
524
+ continue
525
+ }
481
526
addQuery (& query {querySpec : querySpec {path : m .Path , vers : arg .vers , forceModulePath : true , prevM : m }, arg : arg .raw })
482
527
}
483
528
if allStd && arg .path != arg .raw {
@@ -538,7 +583,6 @@ func runGet(cmd *base.Command, args []string) {
538
583
539
584
// Scan for any upgrades lost by the downgrades.
540
585
var lostUpgrades []* query
541
- var versionByPath map [string ]string
542
586
if len (down ) > 0 {
543
587
versionByPath = make (map [string ]string )
544
588
for _ , m := range modload .BuildList () {
@@ -680,15 +724,21 @@ func runQueries(cache map[querySpec]*query, queries []*query, modOnly map[string
680
724
// If forceModulePath is set, getQuery must interpret path
681
725
// as a module path.
682
726
func getQuery (path , vers string , prevM module.Version , forceModulePath bool ) (module.Version , error ) {
683
- switch vers {
684
- case "" :
727
+ if (prevM .Version != "" ) != forceModulePath {
728
+ // We resolve package patterns by calling QueryPattern, which does not
729
+ // accept a previous version and therefore cannot take it into account for
730
+ // the "latest" or "patch" queries.
731
+ // If we are resolving a package path or pattern, the caller has already
732
+ // resolved any existing packages to their containing module(s), and
733
+ // will set both prevM.Version and forceModulePath for those modules.
734
+ // The only remaining package patterns are those that are not already
735
+ // provided by the build list, which are indicated by
736
+ // an empty prevM.Version.
737
+ base .Fatalf ("go get: internal error: prevM may be set if and only if forceModulePath is set" )
738
+ }
739
+
740
+ if vers == "" || vers == "patch" && prevM .Version == "" {
685
741
vers = "latest"
686
- case "patch" :
687
- if prevM .Version == "" {
688
- vers = "latest"
689
- } else {
690
- vers = semver .MajorMinor (prevM .Version )
691
- }
692
742
}
693
743
694
744
if forceModulePath || ! strings .Contains (path , "..." ) {
@@ -699,7 +749,7 @@ func getQuery(path, vers string, prevM module.Version, forceModulePath bool) (mo
699
749
}
700
750
701
751
// If the path doesn't contain a wildcard, try interpreting it as a module path.
702
- info , err := modload .Query (path , vers , modload .Allowed )
752
+ info , err := modload .Query (path , vers , prevM . Version , modload .Allowed )
703
753
if err == nil {
704
754
return module.Version {Path : path , Version : info .Version }, nil
705
755
}
@@ -840,18 +890,14 @@ func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
840
890
}
841
891
842
892
// Run query required by upgrade semantics.
843
- // Note that query "latest" is not the same as
844
- // using repo.Latest.
845
- // The query only falls back to untagged versions
846
- // if nothing is tagged. The Latest method
847
- // only ever returns untagged versions,
848
- // which is not what we want.
849
- query := "latest"
850
- if getU == "patch" {
851
- // For patch upgrade, query "v1.2".
852
- query = semver .MajorMinor (m .Version )
853
- }
854
- info , err := modload .Query (m .Path , query , modload .Allowed )
893
+ // Note that Query "latest" is not the same as using repo.Latest,
894
+ // which may return a pseudoversion for the latest commit.
895
+ // Query "latest" returns the newest tagged version or the newest
896
+ // prerelease version if there are no non-prereleases, or repo.Latest
897
+ // if there aren't any tagged versions. Since we're providing the previous
898
+ // version, Query will confirm the latest version is actually newer
899
+ // and will return the current version if not.
900
+ info , err := modload .Query (m .Path , string (getU ), m .Version , modload .Allowed )
855
901
if err != nil {
856
902
// Report error but return m, to let version selection continue.
857
903
// (Reporting the error will fail the command at the next base.ExitIfErrors.)
@@ -866,18 +912,6 @@ func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
866
912
return m , nil
867
913
}
868
914
869
- // If we're on a later prerelease, keep using it,
870
- // even though normally an Upgrade will ignore prereleases.
871
- if semver .Compare (info .Version , m .Version ) < 0 {
872
- return m , nil
873
- }
874
-
875
- // If we're on a pseudo-version chronologically after the latest tagged version, keep using it.
876
- // This avoids some accidental downgrades.
877
- if mTime , err := modfetch .PseudoVersionTime (m .Version ); err == nil && info .Time .Before (mTime ) {
878
- return m , nil
879
- }
880
-
881
915
return module.Version {Path : m .Path , Version : info .Version }, nil
882
916
}
883
917
0 commit comments