github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-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  	"encoding/hex"
    10  	"fmt"
    11  	"github.com/gagliardetto/golang-go/not-internal/goroot"
    12  	"os"
    13  	"path/filepath"
    14  	"runtime/debug"
    15  	"strings"
    16  
    17  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/base"
    18  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg"
    19  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/modfetch"
    20  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/modinfo"
    21  	"github.com/gagliardetto/golang-go/cmd/go/not-internal/search"
    22  
    23  	"golang.org/x/mod/module"
    24  	"golang.org/x/mod/semver"
    25  )
    26  
    27  var (
    28  	infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
    29  	infoEnd, _   = hex.DecodeString("f932433186182072008242104116d8f2")
    30  )
    31  
    32  func isStandardImportPath(path string) bool {
    33  	return findStandardImportPath(path) != ""
    34  }
    35  
    36  func findStandardImportPath(path string) string {
    37  	if path == "" {
    38  		panic("findStandardImportPath called with empty path")
    39  	}
    40  	if search.IsStandardImportPath(path) {
    41  		if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
    42  			return filepath.Join(cfg.GOROOT, "src", path)
    43  		}
    44  	}
    45  	return ""
    46  }
    47  
    48  // PackageModuleInfo returns information about the module that provides
    49  // a given package. If modules are not enabled or if the package is in the
    50  // standard library or if the package was not successfully loaded with
    51  // ImportPaths or a similar loading function, nil is returned.
    52  func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
    53  	if isStandardImportPath(pkgpath) || !Enabled() {
    54  		return nil
    55  	}
    56  	m, ok := findModule(pkgpath)
    57  	if !ok {
    58  		return nil
    59  	}
    60  	return moduleInfo(m, true)
    61  }
    62  
    63  func ModuleInfo(path string) *modinfo.ModulePublic {
    64  	if !Enabled() {
    65  		return nil
    66  	}
    67  
    68  	if i := strings.Index(path, "@"); i >= 0 {
    69  		return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false)
    70  	}
    71  
    72  	for _, m := range BuildList() {
    73  		if m.Path == path {
    74  			return moduleInfo(m, true)
    75  		}
    76  	}
    77  
    78  	return &modinfo.ModulePublic{
    79  		Path: path,
    80  		Error: &modinfo.ModuleError{
    81  			Err: "module not in current build",
    82  		},
    83  	}
    84  }
    85  
    86  // addUpdate fills in m.Update if an updated version is available.
    87  func addUpdate(m *modinfo.ModulePublic) {
    88  	if m.Version == "" {
    89  		return
    90  	}
    91  
    92  	if info, err := Query(m.Path, "upgrade", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
    93  		m.Update = &modinfo.ModulePublic{
    94  			Path:    m.Path,
    95  			Version: info.Version,
    96  			Time:    &info.Time,
    97  		}
    98  	}
    99  }
   100  
   101  // addVersions fills in m.Versions with the list of known versions.
   102  func addVersions(m *modinfo.ModulePublic) {
   103  	m.Versions, _ = versions(m.Path)
   104  }
   105  
   106  func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
   107  	if m == Target {
   108  		info := &modinfo.ModulePublic{
   109  			Path:    m.Path,
   110  			Version: m.Version,
   111  			Main:    true,
   112  		}
   113  		if HasModRoot() {
   114  			info.Dir = ModRoot()
   115  			info.GoMod = ModFilePath()
   116  			if modFile.Go != nil {
   117  				info.GoVersion = modFile.Go.Version
   118  			}
   119  		}
   120  		return info
   121  	}
   122  
   123  	info := &modinfo.ModulePublic{
   124  		Path:     m.Path,
   125  		Version:  m.Version,
   126  		Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
   127  	}
   128  	if loaded != nil {
   129  		info.GoVersion = loaded.goVersion[m.Path]
   130  	}
   131  
   132  	// completeFromModCache fills in the extra fields in m using the module cache.
   133  	completeFromModCache := func(m *modinfo.ModulePublic) {
   134  		if m.Version != "" {
   135  			if q, err := Query(m.Path, m.Version, "", nil); err != nil {
   136  				m.Error = &modinfo.ModuleError{Err: err.Error()}
   137  			} else {
   138  				m.Version = q.Version
   139  				m.Time = &q.Time
   140  			}
   141  
   142  			mod := module.Version{Path: m.Path, Version: m.Version}
   143  			gomod, err := modfetch.CachePath(mod, "mod")
   144  			if err == nil {
   145  				if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
   146  					m.GoMod = gomod
   147  				}
   148  			}
   149  			dir, err := modfetch.DownloadDir(mod)
   150  			if err == nil {
   151  				m.Dir = dir
   152  			}
   153  		}
   154  	}
   155  
   156  	if !fromBuildList {
   157  		completeFromModCache(info) // Will set m.Error in vendor mode.
   158  		return info
   159  	}
   160  
   161  	r := Replacement(m)
   162  	if r.Path == "" {
   163  		if cfg.BuildMod == "vendor" {
   164  			// It's tempting to fill in the "Dir" field to point within the vendor
   165  			// directory, but that would be misleading: the vendor directory contains
   166  			// a flattened package tree, not complete modules, and it can even
   167  			// interleave packages from different modules if one module path is a
   168  			// prefix of the other.
   169  		} else {
   170  			completeFromModCache(info)
   171  		}
   172  		return info
   173  	}
   174  
   175  	// Don't hit the network to fill in extra data for replaced modules.
   176  	// The original resolved Version and Time don't matter enough to be
   177  	// worth the cost, and we're going to overwrite the GoMod and Dir from the
   178  	// replacement anyway. See https://golang.org/issue/27859.
   179  	info.Replace = &modinfo.ModulePublic{
   180  		Path:      r.Path,
   181  		Version:   r.Version,
   182  		GoVersion: info.GoVersion,
   183  	}
   184  	if r.Version == "" {
   185  		if filepath.IsAbs(r.Path) {
   186  			info.Replace.Dir = r.Path
   187  		} else {
   188  			info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
   189  		}
   190  		info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
   191  	}
   192  	if cfg.BuildMod != "vendor" {
   193  		completeFromModCache(info.Replace)
   194  		info.Dir = info.Replace.Dir
   195  		info.GoMod = info.Replace.GoMod
   196  	}
   197  	return info
   198  }
   199  
   200  // PackageBuildInfo returns a string containing module version information
   201  // for modules providing packages named by path and deps. path and deps must
   202  // name packages that were resolved successfully with ImportPaths or one of
   203  // the Load functions.
   204  func PackageBuildInfo(path string, deps []string) string {
   205  	if isStandardImportPath(path) || !Enabled() {
   206  		return ""
   207  	}
   208  	target := mustFindModule(path, path)
   209  	mdeps := make(map[module.Version]bool)
   210  	for _, dep := range deps {
   211  		if !isStandardImportPath(dep) {
   212  			mdeps[mustFindModule(path, dep)] = true
   213  		}
   214  	}
   215  	var mods []module.Version
   216  	delete(mdeps, target)
   217  	for mod := range mdeps {
   218  		mods = append(mods, mod)
   219  	}
   220  	module.Sort(mods)
   221  
   222  	var buf bytes.Buffer
   223  	fmt.Fprintf(&buf, "path\t%s\n", path)
   224  	tv := target.Version
   225  	if tv == "" {
   226  		tv = "(devel)"
   227  	}
   228  	fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target))
   229  	for _, mod := range mods {
   230  		mv := mod.Version
   231  		if mv == "" {
   232  			mv = "(devel)"
   233  		}
   234  		r := Replacement(mod)
   235  		h := ""
   236  		if r.Path == "" {
   237  			h = "\t" + modfetch.Sum(mod)
   238  		}
   239  		fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mv, h)
   240  		if r.Path != "" {
   241  			fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
   242  		}
   243  	}
   244  	return buf.String()
   245  }
   246  
   247  // mustFindModule is like findModule, but it calls base.Fatalf if the
   248  // module can't be found.
   249  //
   250  // TODO(jayconrod): remove this. Callers should use findModule and return
   251  // errors instead of relying on base.Fatalf.
   252  func mustFindModule(target, path string) module.Version {
   253  	pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   254  	if ok {
   255  		if pkg.err != nil {
   256  			base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
   257  		}
   258  		return pkg.mod
   259  	}
   260  
   261  	if path == "command-line-arguments" {
   262  		return Target
   263  	}
   264  
   265  	if printStackInDie {
   266  		debug.PrintStack()
   267  	}
   268  	base.Fatalf("build %v: cannot find module for path %v", target, path)
   269  	panic("unreachable")
   270  }
   271  
   272  // findModule searches for the module that contains the package at path.
   273  // If the package was loaded with ImportPaths or one of the other loading
   274  // functions, its containing module and true are returned. Otherwise,
   275  // module.Version{} and false are returend.
   276  func findModule(path string) (module.Version, bool) {
   277  	if pkg, ok := loaded.pkgCache.Get(path).(*loadPkg); ok {
   278  		return pkg.mod, pkg.mod != module.Version{}
   279  	}
   280  	if path == "command-line-arguments" {
   281  		return Target, true
   282  	}
   283  	return module.Version{}, false
   284  }
   285  
   286  func ModInfoProg(info string, isgccgo bool) []byte {
   287  	// Inject a variable with the debug information as runtime.modinfo,
   288  	// but compile it in package main so that it is specific to the binary.
   289  	// The variable must be a literal so that it will have the correct value
   290  	// before the initializer for package main runs.
   291  	//
   292  	// The runtime startup code refers to the variable, which keeps it live
   293  	// in all binaries.
   294  	//
   295  	// Note: we use an alternate recipe below for gccgo (based on an
   296  	// init function) due to the fact that gccgo does not support
   297  	// applying a "//go:linkname" directive to a variable. This has
   298  	// drawbacks in that other packages may want to look at the module
   299  	// info in their init functions (see issue 29628), which won't
   300  	// work for gccgo. See also issue 30344.
   301  
   302  	if !isgccgo {
   303  		return []byte(fmt.Sprintf(`package main
   304  import _ "unsafe"
   305  //go:linkname __debug_modinfo__ runtime.modinfo
   306  var __debug_modinfo__ = %q
   307  	`, string(infoStart)+info+string(infoEnd)))
   308  	} else {
   309  		return []byte(fmt.Sprintf(`package main
   310  import _ "unsafe"
   311  //go:linkname __set_debug_modinfo__ runtime.setmodinfo
   312  func __set_debug_modinfo__(string)
   313  func init() { __set_debug_modinfo__(%q) }
   314  	`, string(infoStart)+info+string(infoEnd)))
   315  	}
   316  }