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  }