...

Source file src/pkg/cmd/go/internal/modload/build.go

     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		"cmd/go/internal/semver"
    16		"encoding/hex"
    17		"fmt"
    18		"internal/goroot"
    19		"os"
    20		"path/filepath"
    21		"runtime/debug"
    22		"strings"
    23	)
    24	
    25	var (
    26		infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
    27		infoEnd, _   = hex.DecodeString("f932433186182072008242104116d8f2")
    28	)
    29	
    30	func isStandardImportPath(path string) bool {
    31		return findStandardImportPath(path) != ""
    32	}
    33	
    34	func findStandardImportPath(path string) string {
    35		if path == "" {
    36			panic("findStandardImportPath called with empty path")
    37		}
    38		if search.IsStandardImportPath(path) {
    39			if goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
    40				return filepath.Join(cfg.GOROOT, "src", path)
    41			}
    42		}
    43		return ""
    44	}
    45	
    46	func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
    47		if isStandardImportPath(pkgpath) || !Enabled() {
    48			return nil
    49		}
    50		return moduleInfo(findModule(pkgpath, pkgpath), true)
    51	}
    52	
    53	func ModuleInfo(path string) *modinfo.ModulePublic {
    54		if !Enabled() {
    55			return nil
    56		}
    57	
    58		if i := strings.Index(path, "@"); i >= 0 {
    59			return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false)
    60		}
    61	
    62		for _, m := range BuildList() {
    63			if m.Path == path {
    64				return moduleInfo(m, true)
    65			}
    66		}
    67	
    68		return &modinfo.ModulePublic{
    69			Path: path,
    70			Error: &modinfo.ModuleError{
    71				Err: "module not in current build",
    72			},
    73		}
    74	}
    75	
    76	// addUpdate fills in m.Update if an updated version is available.
    77	func addUpdate(m *modinfo.ModulePublic) {
    78		if m.Version == "" {
    79			return
    80		}
    81	
    82		if info, err := Query(m.Path, "upgrade", m.Version, Allowed); err == nil && semver.Compare(info.Version, m.Version) > 0 {
    83			m.Update = &modinfo.ModulePublic{
    84				Path:    m.Path,
    85				Version: info.Version,
    86				Time:    &info.Time,
    87			}
    88		}
    89	}
    90	
    91	// addVersions fills in m.Versions with the list of known versions.
    92	func addVersions(m *modinfo.ModulePublic) {
    93		m.Versions, _ = versions(m.Path)
    94	}
    95	
    96	func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic {
    97		if m == Target {
    98			info := &modinfo.ModulePublic{
    99				Path:    m.Path,
   100				Version: m.Version,
   101				Main:    true,
   102			}
   103			if HasModRoot() {
   104				info.Dir = ModRoot()
   105				info.GoMod = filepath.Join(info.Dir, "go.mod")
   106				if modFile.Go != nil {
   107					info.GoVersion = modFile.Go.Version
   108				}
   109			}
   110			return info
   111		}
   112	
   113		info := &modinfo.ModulePublic{
   114			Path:     m.Path,
   115			Version:  m.Version,
   116			Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
   117		}
   118		if loaded != nil {
   119			info.GoVersion = loaded.goVersion[m.Path]
   120		}
   121	
   122		if cfg.BuildMod == "vendor" {
   123			info.Dir = filepath.Join(ModRoot(), "vendor", m.Path)
   124			return info
   125		}
   126	
   127		// complete fills in the extra fields in m.
   128		complete := func(m *modinfo.ModulePublic) {
   129			if m.Version != "" {
   130				if q, err := Query(m.Path, m.Version, "", nil); err != nil {
   131					m.Error = &modinfo.ModuleError{Err: err.Error()}
   132				} else {
   133					m.Version = q.Version
   134					m.Time = &q.Time
   135				}
   136	
   137				mod := module.Version{Path: m.Path, Version: m.Version}
   138				gomod, err := modfetch.CachePath(mod, "mod")
   139				if err == nil {
   140					if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() {
   141						m.GoMod = gomod
   142					}
   143				}
   144				dir, err := modfetch.DownloadDir(mod)
   145				if err == nil {
   146					if info, err := os.Stat(dir); err == nil && info.IsDir() {
   147						m.Dir = dir
   148					}
   149				}
   150			}
   151		}
   152	
   153		if !fromBuildList {
   154			complete(info)
   155			return info
   156		}
   157	
   158		r := Replacement(m)
   159		if r.Path == "" {
   160			complete(info)
   161			return info
   162		}
   163	
   164		// Don't hit the network to fill in extra data for replaced modules.
   165		// The original resolved Version and Time don't matter enough to be
   166		// worth the cost, and we're going to overwrite the GoMod and Dir from the
   167		// replacement anyway. See https://golang.org/issue/27859.
   168		info.Replace = &modinfo.ModulePublic{
   169			Path:      r.Path,
   170			Version:   r.Version,
   171			GoVersion: info.GoVersion,
   172		}
   173		if r.Version == "" {
   174			if filepath.IsAbs(r.Path) {
   175				info.Replace.Dir = r.Path
   176			} else {
   177				info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
   178			}
   179		}
   180		complete(info.Replace)
   181		info.Dir = info.Replace.Dir
   182		info.GoMod = filepath.Join(info.Dir, "go.mod")
   183		return info
   184	}
   185	
   186	func PackageBuildInfo(path string, deps []string) string {
   187		if isStandardImportPath(path) || !Enabled() {
   188			return ""
   189		}
   190	
   191		target := findModule(path, path)
   192		mdeps := make(map[module.Version]bool)
   193		for _, dep := range deps {
   194			if !isStandardImportPath(dep) {
   195				mdeps[findModule(path, dep)] = true
   196			}
   197		}
   198		var mods []module.Version
   199		delete(mdeps, target)
   200		for mod := range mdeps {
   201			mods = append(mods, mod)
   202		}
   203		module.Sort(mods)
   204	
   205		var buf bytes.Buffer
   206		fmt.Fprintf(&buf, "path\t%s\n", path)
   207		tv := target.Version
   208		if tv == "" {
   209			tv = "(devel)"
   210		}
   211		fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target))
   212		for _, mod := range mods {
   213			mv := mod.Version
   214			if mv == "" {
   215				mv = "(devel)"
   216			}
   217			r := Replacement(mod)
   218			h := ""
   219			if r.Path == "" {
   220				h = "\t" + modfetch.Sum(mod)
   221			}
   222			fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mv, h)
   223			if r.Path != "" {
   224				fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
   225			}
   226		}
   227		return buf.String()
   228	}
   229	
   230	// findModule returns the module containing the package at path,
   231	// needed to build the package at target.
   232	func findModule(target, path string) module.Version {
   233		pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
   234		if ok {
   235			if pkg.err != nil {
   236				base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
   237			}
   238			return pkg.mod
   239		}
   240	
   241		if path == "command-line-arguments" {
   242			return Target
   243		}
   244	
   245		if printStackInDie {
   246			debug.PrintStack()
   247		}
   248		base.Fatalf("build %v: cannot find module for path %v", target, path)
   249		panic("unreachable")
   250	}
   251	
   252	func ModInfoProg(info string) []byte {
   253		// Inject a variable with the debug information as runtime.modinfo,
   254		// but compile it in package main so that it is specific to the binary.
   255		// The variable must be a literal so that it will have the correct value
   256		// before the initializer for package main runs.
   257		//
   258		// The runtime startup code refers to the variable, which keeps it live in all binaries.
   259		return []byte(fmt.Sprintf(`package main
   260	import _ "unsafe"
   261	//go:linkname __debug_modinfo__ runtime.modinfo
   262	var __debug_modinfo__ = %q
   263		`, string(infoStart)+info+string(infoEnd)))
   264	}
   265	

View as plain text