github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/modload/vendor.go (about) 1 // Copyright 2020 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 package modload 6 7 import ( 8 "errors" 9 "fmt" 10 "io/fs" 11 "os" 12 "path/filepath" 13 "strings" 14 "sync" 15 16 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 17 18 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/modfile" 19 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/module" 20 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/semver" 21 ) 22 23 var ( 24 vendorOnce sync.Once 25 vendorList []module.Version // modules that contribute packages to the build, in order of appearance 26 vendorReplaced []module.Version // all replaced modules; may or may not also contribute packages 27 vendorVersion map[string]string // module path → selected version (if known) 28 vendorPkgModule map[string]module.Version // package → containing module 29 vendorMeta map[module.Version]vendorMetadata 30 ) 31 32 type vendorMetadata struct { 33 Explicit bool 34 Replacement module.Version 35 GoVersion string 36 } 37 38 // readVendorList reads the list of vendored modules from vendor/modules.txt. 39 func readVendorList(mainModule module.Version) { 40 vendorOnce.Do(func() { 41 vendorList = nil 42 vendorPkgModule = make(map[string]module.Version) 43 vendorVersion = make(map[string]string) 44 vendorMeta = make(map[module.Version]vendorMetadata) 45 data, err := os.ReadFile(filepath.Join(MainModules.ModRoot(mainModule), "vendor/modules.txt")) 46 if err != nil { 47 if !errors.Is(err, fs.ErrNotExist) { 48 base.Fatalf("go: %s", err) 49 } 50 return 51 } 52 53 var mod module.Version 54 for _, line := range strings.Split(string(data), "\n") { 55 if strings.HasPrefix(line, "# ") { 56 f := strings.Fields(line) 57 58 if len(f) < 3 { 59 continue 60 } 61 if semver.IsValid(f[2]) { 62 // A module, but we don't yet know whether it is in the build list or 63 // only included to indicate a replacement. 64 mod = module.Version{Path: f[1], Version: f[2]} 65 f = f[3:] 66 } else if f[2] == "=>" { 67 // A wildcard replacement found in the main module's go.mod file. 68 mod = module.Version{Path: f[1]} 69 f = f[2:] 70 } else { 71 // Not a version or a wildcard replacement. 72 // We don't know how to interpret this module line, so ignore it. 73 mod = module.Version{} 74 continue 75 } 76 77 if len(f) >= 2 && f[0] == "=>" { 78 meta := vendorMeta[mod] 79 if len(f) == 2 { 80 // File replacement. 81 meta.Replacement = module.Version{Path: f[1]} 82 vendorReplaced = append(vendorReplaced, mod) 83 } else if len(f) == 3 && semver.IsValid(f[2]) { 84 // Path and version replacement. 85 meta.Replacement = module.Version{Path: f[1], Version: f[2]} 86 vendorReplaced = append(vendorReplaced, mod) 87 } else { 88 // We don't understand this replacement. Ignore it. 89 } 90 vendorMeta[mod] = meta 91 } 92 continue 93 } 94 95 // Not a module line. Must be a package within a module or a metadata 96 // directive, either of which requires a preceding module line. 97 if mod.Path == "" { 98 continue 99 } 100 101 if annonations, ok := strings.CutPrefix(line, "## "); ok { 102 // Metadata. Take the union of annotations across multiple lines, if present. 103 meta := vendorMeta[mod] 104 for _, entry := range strings.Split(annonations, ";") { 105 entry = strings.TrimSpace(entry) 106 if entry == "explicit" { 107 meta.Explicit = true 108 } 109 if goVersion, ok := strings.CutPrefix(entry, "go "); ok { 110 meta.GoVersion = goVersion 111 rawGoVersion.Store(mod, meta.GoVersion) 112 } 113 // All other tokens are reserved for future use. 114 } 115 vendorMeta[mod] = meta 116 continue 117 } 118 119 if f := strings.Fields(line); len(f) == 1 && module.CheckImportPath(f[0]) == nil { 120 // A package within the current module. 121 vendorPkgModule[f[0]] = mod 122 123 // Since this module provides a package for the build, we know that it 124 // is in the build list and is the selected version of its path. 125 // If this information is new, record it. 126 if v, ok := vendorVersion[mod.Path]; !ok || semver.Compare(v, mod.Version) < 0 { 127 vendorList = append(vendorList, mod) 128 vendorVersion[mod.Path] = mod.Version 129 } 130 } 131 } 132 }) 133 } 134 135 // checkVendorConsistency verifies that the vendor/modules.txt file matches (if 136 // go 1.14) or at least does not contradict (go 1.13 or earlier) the 137 // requirements and replacements listed in the main module's go.mod file. 138 func checkVendorConsistency(index *modFileIndex, modFile *modfile.File) { 139 readVendorList(MainModules.mustGetSingleMainModule()) 140 141 pre114 := false 142 if semver.Compare(index.goVersionV, "v1.14") < 0 { 143 // Go versions before 1.14 did not include enough information in 144 // vendor/modules.txt to check for consistency. 145 // If we know that we're on an earlier version, relax the consistency check. 146 pre114 = true 147 } 148 149 vendErrors := new(strings.Builder) 150 vendErrorf := func(mod module.Version, format string, args ...any) { 151 detail := fmt.Sprintf(format, args...) 152 if mod.Version == "" { 153 fmt.Fprintf(vendErrors, "\n\t%s: %s", mod.Path, detail) 154 } else { 155 fmt.Fprintf(vendErrors, "\n\t%s@%s: %s", mod.Path, mod.Version, detail) 156 } 157 } 158 159 // Iterate over the Require directives in their original (not indexed) order 160 // so that the errors match the original file. 161 for _, r := range modFile.Require { 162 if !vendorMeta[r.Mod].Explicit { 163 if pre114 { 164 // Before 1.14, modules.txt did not indicate whether modules were listed 165 // explicitly in the main module's go.mod file. 166 // However, we can at least detect a version mismatch if packages were 167 // vendored from a non-matching version. 168 if vv, ok := vendorVersion[r.Mod.Path]; ok && vv != r.Mod.Version { 169 vendErrorf(r.Mod, fmt.Sprintf("is explicitly required in go.mod, but vendor/modules.txt indicates %s@%s", r.Mod.Path, vv)) 170 } 171 } else { 172 vendErrorf(r.Mod, "is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt") 173 } 174 } 175 } 176 177 describe := func(m module.Version) string { 178 if m.Version == "" { 179 return m.Path 180 } 181 return m.Path + "@" + m.Version 182 } 183 184 // We need to verify *all* replacements that occur in modfile: even if they 185 // don't directly apply to any module in the vendor list, the replacement 186 // go.mod file can affect the selected versions of other (transitive) 187 // dependencies 188 for _, r := range modFile.Replace { 189 vr := vendorMeta[r.Old].Replacement 190 if vr == (module.Version{}) { 191 if pre114 && (r.Old.Version == "" || vendorVersion[r.Old.Path] != r.Old.Version) { 192 // Before 1.14, modules.txt omitted wildcard replacements and 193 // replacements for modules that did not have any packages to vendor. 194 } else { 195 vendErrorf(r.Old, "is replaced in go.mod, but not marked as replaced in vendor/modules.txt") 196 } 197 } else if vr != r.New { 198 vendErrorf(r.Old, "is replaced by %s in go.mod, but marked as replaced by %s in vendor/modules.txt", describe(r.New), describe(vr)) 199 } 200 } 201 202 for _, mod := range vendorList { 203 meta := vendorMeta[mod] 204 if meta.Explicit { 205 if _, inGoMod := index.require[mod]; !inGoMod { 206 vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in go.mod") 207 } 208 } 209 } 210 211 for _, mod := range vendorReplaced { 212 r := Replacement(mod) 213 if r == (module.Version{}) { 214 vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod") 215 continue 216 } 217 if meta := vendorMeta[mod]; r != meta.Replacement { 218 vendErrorf(mod, "is marked as replaced by %s in vendor/modules.txt, but replaced by %s in go.mod", describe(meta.Replacement), describe(r)) 219 } 220 } 221 222 if vendErrors.Len() > 0 { 223 modRoot := MainModules.ModRoot(MainModules.mustGetSingleMainModule()) 224 base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors) 225 } 226 }