github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/go/internal/modload/build.go (about) 1 // Copyright 2018 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 "bytes" 9 "cmd/go/internal/base" 10 "cmd/go/internal/cfg" 11 "cmd/go/internal/modfetch" 12 "cmd/go/internal/modinfo" 13 "cmd/go/internal/module" 14 "cmd/go/internal/search" 15 "encoding/hex" 16 "fmt" 17 "internal/goroot" 18 "os" 19 "path/filepath" 20 "strings" 21 ) 22 23 var ( 24 infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6") 25 infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2") 26 ) 27 28 func isStandardImportPath(path string) bool { 29 return findStandardImportPath(path) != "" 30 } 31 32 func findStandardImportPath(path string) string { 33 if path == "" { 34 panic("findStandardImportPath called with empty path") 35 } 36 if search.IsStandardImportPath(path) { 37 if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) { 38 return filepath.Join(cfg.GOROOT, "src", path) 39 } 40 if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, "vendor/"+path) { 41 return filepath.Join(cfg.GOROOT, "src/vendor", path) 42 } 43 } 44 return "" 45 } 46 47 func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic { 48 if isStandardImportPath(pkgpath) || !Enabled() { 49 return nil 50 } 51 return moduleInfo(findModule(pkgpath, pkgpath), true) 52 } 53 54 func ModuleInfo(path string) *modinfo.ModulePublic { 55 if !Enabled() { 56 return nil 57 } 58 59 if i := strings.Index(path, "@"); i >= 0 { 60 return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false) 61 } 62 63 for _, m := range BuildList() { 64 if m.Path == path { 65 return moduleInfo(m, true) 66 } 67 } 68 69 return &modinfo.ModulePublic{ 70 Path: path, 71 Error: &modinfo.ModuleError{ 72 Err: "module not in current build", 73 }, 74 } 75 } 76 77 // addUpdate fills in m.Update if an updated version is available. 78 func addUpdate(m *modinfo.ModulePublic) { 79 if m.Version != "" { 80 if info, err := Query(m.Path, "latest", Allowed); err == nil && info.Version != m.Version { 81 m.Update = &modinfo.ModulePublic{ 82 Path: m.Path, 83 Version: info.Version, 84 Time: &info.Time, 85 } 86 } 87 } 88 } 89 90 // addVersions fills in m.Versions with the list of known versions. 91 func addVersions(m *modinfo.ModulePublic) { 92 m.Versions, _ = versions(m.Path) 93 } 94 95 func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic { 96 if m == Target { 97 info := &modinfo.ModulePublic{ 98 Path: m.Path, 99 Version: m.Version, 100 Main: true, 101 Dir: ModRoot, 102 GoMod: filepath.Join(ModRoot, "go.mod"), 103 } 104 if modFile.Go != nil { 105 info.GoVersion = modFile.Go.Version 106 } 107 return info 108 } 109 110 info := &modinfo.ModulePublic{ 111 Path: m.Path, 112 Version: m.Version, 113 Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path], 114 } 115 if loaded != nil { 116 info.GoVersion = loaded.goVersion[m.Path] 117 } 118 119 if cfg.BuildMod == "vendor" { 120 info.Dir = filepath.Join(ModRoot, "vendor", m.Path) 121 return info 122 } 123 124 // complete fills in the extra fields in m. 125 complete := func(m *modinfo.ModulePublic) { 126 if m.Version != "" { 127 if q, err := Query(m.Path, m.Version, nil); err != nil { 128 m.Error = &modinfo.ModuleError{Err: err.Error()} 129 } else { 130 m.Version = q.Version 131 m.Time = &q.Time 132 } 133 134 mod := module.Version{Path: m.Path, Version: m.Version} 135 gomod, err := modfetch.CachePath(mod, "mod") 136 if err == nil { 137 if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() { 138 m.GoMod = gomod 139 } 140 } 141 dir, err := modfetch.DownloadDir(mod) 142 if err == nil { 143 if info, err := os.Stat(dir); err == nil && info.IsDir() { 144 m.Dir = dir 145 } 146 } 147 } 148 if cfg.BuildMod == "vendor" { 149 m.Dir = filepath.Join(ModRoot, "vendor", m.Path) 150 } 151 } 152 153 complete(info) 154 155 if fromBuildList { 156 if r := Replacement(m); r.Path != "" { 157 info.Replace = &modinfo.ModulePublic{ 158 Path: r.Path, 159 Version: r.Version, 160 GoVersion: info.GoVersion, 161 } 162 if r.Version == "" { 163 if filepath.IsAbs(r.Path) { 164 info.Replace.Dir = r.Path 165 } else { 166 info.Replace.Dir = filepath.Join(ModRoot, r.Path) 167 } 168 } 169 complete(info.Replace) 170 info.Dir = info.Replace.Dir 171 info.GoMod = filepath.Join(info.Dir, "go.mod") 172 info.Error = nil // ignore error loading original module version (it has been replaced) 173 } 174 } 175 176 return info 177 } 178 179 func PackageBuildInfo(path string, deps []string) string { 180 if isStandardImportPath(path) || !Enabled() { 181 return "" 182 } 183 target := findModule(path, path) 184 mdeps := make(map[module.Version]bool) 185 for _, dep := range deps { 186 if !isStandardImportPath(dep) { 187 mdeps[findModule(path, dep)] = true 188 } 189 } 190 var mods []module.Version 191 delete(mdeps, target) 192 for mod := range mdeps { 193 mods = append(mods, mod) 194 } 195 module.Sort(mods) 196 197 var buf bytes.Buffer 198 fmt.Fprintf(&buf, "path\t%s\n", path) 199 tv := target.Version 200 if tv == "" { 201 tv = "(devel)" 202 } 203 fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target)) 204 for _, mod := range mods { 205 mv := mod.Version 206 if mv == "" { 207 mv = "(devel)" 208 } 209 r := Replacement(mod) 210 h := "" 211 if r.Path == "" { 212 h = "\t" + modfetch.Sum(mod) 213 } 214 fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h) 215 if r.Path != "" { 216 fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r)) 217 } 218 } 219 return buf.String() 220 } 221 222 func findModule(target, path string) module.Version { 223 // TODO: This should use loaded. 224 if path == "." { 225 return buildList[0] 226 } 227 for _, mod := range buildList { 228 if maybeInModule(path, mod.Path) { 229 return mod 230 } 231 } 232 base.Fatalf("build %v: cannot find module for path %v", target, path) 233 panic("unreachable") 234 } 235 236 func ModInfoProg(info string) []byte { 237 // Inject a variable with the debug information as runtime/debug.modinfo, 238 // but compile it in package main so that it is specific to the binary. 239 // Populate it in an init func so that it will work with go:linkname, 240 // but use a string constant instead of the name 'string' in case 241 // package main shadows the built-in 'string' with some local declaration. 242 return []byte(fmt.Sprintf(`package main 243 import _ "unsafe" 244 //go:linkname __debug_modinfo__ runtime/debug.modinfo 245 var __debug_modinfo__ = "" 246 func init() { __debug_modinfo__ = %q } 247 `, string(infoStart)+info+string(infoEnd))) 248 }