Skip to content

Commit

Permalink
cmd/go/internal/vgo: main vgo drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
rsc committed Feb 20, 2018
1 parent 901a8b1 commit ad748cc
Show file tree
Hide file tree
Showing 9 changed files with 1,891 additions and 0 deletions.
79 changes: 79 additions & 0 deletions vendor/cmd/go/internal/vgo/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vgo

import (
"bytes"
"cmd/go/internal/base"
"cmd/go/internal/module"
"cmd/go/internal/search"
"encoding/hex"
"fmt"
)

var (
infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
)

func PackageModuleInfo(path string, deps []string) string {
if search.IsStandardImportPath(path) {
return ""
}
target := findModule(path, path)
mdeps := make(map[module.Version]bool)
for _, dep := range deps {
if !search.IsStandardImportPath(dep) {
mdeps[findModule(path, dep)] = true
}
}
var mods []module.Version
delete(mdeps, target)
for mod := range mdeps {
mods = append(mods, mod)
}
sortModules(mods)

var buf bytes.Buffer
fmt.Fprintf(&buf, "path\t%s\n", path)
tv := target.Version
if tv == "" {
tv = "(devel)"
}
fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, findModHash(target))
for _, mod := range mods {
mv := mod.Version
if mv == "" {
mv = "(devel)"
}
fmt.Fprintf(&buf, "dep\t%s\t%s\t%s\n", mod.Path, mod.Version, findModHash(mod))
}
return buf.String()
}

func findModule(target, path string) module.Version {
if path == "." {
return buildList[0]
}
for _, mod := range buildList {
if importPathInModule(path, mod.Path) {
return mod
}
}
base.Fatalf("build %v: cannot find module for path %v", target, path)
panic("unreachable")
}

func ModInfoProg(info string) []byte {
return []byte(fmt.Sprintf(`
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime/debug.modinfo
var __debug_modinfo__ string
func init() {
__debug_modinfo__ = %q
}
`, string(infoStart)+info+string(infoEnd)))
}
231 changes: 231 additions & 0 deletions vendor/cmd/go/internal/vgo/fetch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vgo

import (
"archive/zip"
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"

"cmd/go/internal/base"
"cmd/go/internal/dirhash"
"cmd/go/internal/modfetch"
"cmd/go/internal/module"
"cmd/go/internal/semver"
)

// fetch returns the directory in the local download cache
// holding the root of mod's source tree.
// It downloads the module if needed.
func fetch(mod module.Version) (dir string, err error) {
if r := replaced(mod); r != nil {
if r.New.Version == "" {
dir = r.New.Path
if !filepath.IsAbs(dir) {
dir = filepath.Join(ModRoot, dir)
}
return dir, nil
}
mod = r.New
}

modpath := mod.Path + "@" + mod.Version
dir = filepath.Join(srcV, modpath)
if files, _ := ioutil.ReadDir(dir); len(files) == 0 {
zipfile := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".zip")
if _, err := os.Stat(zipfile); err == nil {
// Use it.
// This should only happen if the v/cache directory is preinitialized
// or if src/v/modpath was removed but not src/v/cache.
fmt.Fprintf(os.Stderr, "vgo: extracting %s %s\n", mod.Path, mod.Version)
} else {
if err := os.MkdirAll(filepath.Join(srcV, "cache", mod.Path, "@v"), 0777); err != nil {
return "", err
}
fmt.Fprintf(os.Stderr, "vgo: downloading %s %s\n", mod.Path, mod.Version)
if err := downloadZip(mod, zipfile); err != nil {
return "", err
}
}
if err := modfetch.Unzip(dir, zipfile, modpath, 0); err != nil {
fmt.Fprintf(os.Stderr, "-> %s\n", err)
return "", err
}
}
checkModHash(mod)
return dir, nil
}

func downloadZip(mod module.Version, target string) error {
repo, err := modfetch.Lookup(mod.Path)
if err != nil {
return err
}
tmpfile, err := repo.Zip(mod.Version, os.TempDir())
if err != nil {
return err
}
defer os.Remove(tmpfile)

// Double-check zip file looks OK.
z, err := zip.OpenReader(tmpfile)
if err != nil {
z.Close()
return err
}
prefix := mod.Path + "@" + mod.Version
for _, f := range z.File {
if !strings.HasPrefix(f.Name, prefix) {
z.Close()
return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
}
}
z.Close()

hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash)
if err != nil {
return err
}
r, err := os.Open(tmpfile)
if err != nil {
return err
}
defer r.Close()
w, err := os.Create(target)
if err != nil {
return err
}
if _, err := io.Copy(w, r); err != nil {
w.Close()
return fmt.Errorf("copying: %v", err)
}
if err := w.Close(); err != nil {
return err
}
if err := ioutil.WriteFile(target+"hash", []byte(hash), 0666); err != nil {
return err
}
return nil
}

var useModHash = false
var modHash map[module.Version][]string

func initModHash() {
if modHash != nil {
return
}
modHash = make(map[module.Version][]string)
file := filepath.Join(ModRoot, "go.modverify")
data, err := ioutil.ReadFile(file)
if err != nil && os.IsNotExist(err) {
return
}
if err != nil {
base.Fatalf("vgo: %v", err)
}
useModHash = true
lineno := 0
for len(data) > 0 {
var line []byte
lineno++
i := bytes.IndexByte(data, '\n')
if i < 0 {
line, data = data, nil
} else {
line, data = data[:i], data[i+1:]
}
f := strings.Fields(string(line))
if len(f) != 3 {
base.Fatalf("vgo: malformed go.modverify:\n%s:%d: wrong number of fields", file, lineno)
}
mod := module.Version{Path: f[0], Version: f[1]}
modHash[mod] = append(modHash[mod], f[2])
}
}

func checkModHash(mod module.Version) {
initModHash()
if !useModHash {
return
}

data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash"))
if err != nil {
base.Fatalf("vgo: verifying %s %s: %v", mod.Path, mod.Version, err)
}
h := strings.TrimSpace(string(data))
if !strings.HasPrefix(h, "h1:") {
base.Fatalf("vgo: verifying %s %s: unexpected ziphash: %q", mod.Path, mod.Version, h)
}

for _, vh := range modHash[mod] {
if h == vh {
return
}
if strings.HasPrefix(vh, "h1:") {
base.Fatalf("vgo: verifying %s %s: module hash mismatch\n\tdownloaded: %v\n\tgo.modverify: %v", mod.Path, mod.Version, h, vh)
}
}
if len(modHash[mod]) > 0 {
fmt.Fprintf(os.Stderr, "warning: verifying %s %s: unknown hashes in go.modverify: %v; adding %v", mod.Path, mod.Version, strings.Join(modHash[mod], ", "), h)
}
modHash[mod] = append(modHash[mod], h)
}

func findModHash(mod module.Version) string {
data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash"))
if err != nil {
return ""
}
return strings.TrimSpace(string(data))
}

func writeModHash() {
if !useModHash {
return
}

var mods []module.Version
for m := range modHash {
mods = append(mods, m)
}
sortModules(mods)
var buf bytes.Buffer
for _, m := range mods {
list := modHash[m]
sort.Strings(list)
for _, h := range list {
fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
}
}

file := filepath.Join(ModRoot, "go.modverify")
data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "go.modverify"))
if bytes.Equal(data, buf.Bytes()) {
return
}

if err := ioutil.WriteFile(file, buf.Bytes(), 0666); err != nil {
base.Fatalf("vgo: writing go.modverify: %v", err)
}
}

func sortModules(mods []module.Version) {
sort.Slice(mods, func(i, j int) bool {
mi := mods[i]
mj := mods[j]
if mi.Path != mj.Path {
return mi.Path < mj.Path
}
return semver.Compare(mi.Version, mj.Version) < 0
})
}
Loading

0 comments on commit ad748cc

Please sign in to comment.