github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/workcmd/sync.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // go work sync 6 7 package workcmd 8 9 import ( 10 "context" 11 12 "github.com/go-asm/go/cmd/go/base" 13 "github.com/go-asm/go/cmd/go/gover" 14 "github.com/go-asm/go/cmd/go/imports" 15 "github.com/go-asm/go/cmd/go/modload" 16 "github.com/go-asm/go/cmd/go/toolchain" 17 18 "golang.org/x/mod/module" 19 ) 20 21 var cmdSync = &base.Command{ 22 UsageLine: "go work sync", 23 Short: "sync workspace build list to modules", 24 Long: `Sync syncs the workspace's build list back to the 25 workspace's modules 26 27 The workspace's build list is the set of versions of all the 28 (transitive) dependency modules used to do builds in the workspace. go 29 work sync generates that build list using the Minimal Version Selection 30 algorithm, and then syncs those versions back to each of modules 31 specified in the workspace (with use directives). 32 33 The syncing is done by sequentially upgrading each of the dependency 34 modules specified in a workspace module to the version in the build list 35 if the dependency module's version is not already the same as the build 36 list's version. Note that Minimal Version Selection guarantees that the 37 build list's version of each module is always the same or higher than 38 that in each workspace module. 39 40 See the workspaces reference at https://go.dev/ref/mod#workspaces 41 for more information. 42 `, 43 Run: runSync, 44 } 45 46 func init() { 47 base.AddChdirFlag(&cmdSync.Flag) 48 base.AddModCommonFlags(&cmdSync.Flag) 49 } 50 51 func runSync(ctx context.Context, cmd *base.Command, args []string) { 52 modload.ForceUseModules = true 53 modload.InitWorkfile() 54 if modload.WorkFilePath() == "" { 55 base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)") 56 } 57 58 _, err := modload.LoadModGraph(ctx, "") 59 if err != nil { 60 toolchain.SwitchOrFatal(ctx, err) 61 } 62 mustSelectFor := map[module.Version][]module.Version{} 63 64 mms := modload.MainModules 65 66 opts := modload.PackageOpts{ 67 Tags: imports.AnyTags(), 68 VendorModulesInGOROOTSrc: true, 69 ResolveMissingImports: false, 70 LoadTests: true, 71 AllowErrors: true, 72 SilencePackageErrors: true, 73 SilenceUnmatchedWarnings: true, 74 } 75 for _, m := range mms.Versions() { 76 opts.MainModule = m 77 _, pkgs := modload.LoadPackages(ctx, opts, "all") 78 opts.MainModule = module.Version{} // reset 79 80 var ( 81 mustSelect []module.Version 82 inMustSelect = map[module.Version]bool{} 83 ) 84 for _, pkg := range pkgs { 85 if r := modload.PackageModule(pkg); r.Version != "" && !inMustSelect[r] { 86 // r has a known version, so force that version. 87 mustSelect = append(mustSelect, r) 88 inMustSelect[r] = true 89 } 90 } 91 gover.ModSort(mustSelect) // ensure determinism 92 mustSelectFor[m] = mustSelect 93 } 94 95 workFilePath := modload.WorkFilePath() // save go.work path because EnterModule clobbers it. 96 97 var goV string 98 for _, m := range mms.Versions() { 99 if mms.ModRoot(m) == "" && m.Path == "command-line-arguments" { 100 // This is not a real module. 101 // TODO(#49228): Remove this special case once the special 102 // command-line-arguments module is gone. 103 continue 104 } 105 106 // Use EnterModule to reset the global state in modload to be in 107 // single-module mode using the modroot of m. 108 modload.EnterModule(ctx, mms.ModRoot(m)) 109 110 // Edit the build list in the same way that 'go get' would if we 111 // requested the relevant module versions explicitly. 112 // TODO(#57001): Do we need a toolchain.SwitchOrFatal here, 113 // and do we need to pass a toolchain.Switcher in LoadPackages? 114 // If so, think about saving the WriteGoMods for after the loop, 115 // so we don't write some go.mods with the "before" toolchain 116 // and others with the "after" toolchain. If nothing else, that 117 // discrepancy could show up in auto-recorded toolchain lines. 118 changed, err := modload.EditBuildList(ctx, nil, mustSelectFor[m]) 119 if err != nil { 120 continue 121 } 122 if changed { 123 modload.LoadPackages(ctx, modload.PackageOpts{ 124 Tags: imports.AnyTags(), 125 Tidy: true, 126 VendorModulesInGOROOTSrc: true, 127 ResolveMissingImports: false, 128 LoadTests: true, 129 AllowErrors: true, 130 SilenceMissingStdImports: true, 131 SilencePackageErrors: true, 132 }, "all") 133 modload.WriteGoMod(ctx, modload.WriteOpts{}) 134 } 135 goV = gover.Max(goV, modload.MainModules.GoVersion()) 136 } 137 138 wf, err := modload.ReadWorkFile(workFilePath) 139 if err != nil { 140 base.Fatal(err) 141 } 142 modload.UpdateWorkGoVersion(wf, goV) 143 modload.UpdateWorkFile(wf) 144 if err := modload.WriteWorkFile(workFilePath, wf); err != nil { 145 base.Fatal(err) 146 } 147 }