+++ /dev/null
-// 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 packagestest
-
-import (
- "context"
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "path/filepath"
- "regexp"
- "strings"
-
- "golang.org/x/tools/internal/gocommand"
- "golang.org/x/tools/internal/packagesinternal"
- "golang.org/x/tools/internal/proxydir"
-)
-
-// Modules is the exporter that produces module layouts.
-// Each "repository" is put in it's own module, and the module file generated
-// will have replace directives for all other modules.
-// Given the two files
-// golang.org/repoa#a/a.go
-// golang.org/repob#b/b.go
-// You would get the directory layout
-// /sometemporarydirectory
-// ├── repoa
-// │ ├── a
-// │ │ └── a.go
-// │ └── go.mod
-// └── repob
-// ├── b
-// │ └── b.go
-// └── go.mod
-// and the working directory would be
-// /sometemporarydirectory/repoa
-var Modules = modules{}
-
-type modules struct{}
-
-type moduleAtVersion struct {
- module string
- version string
-}
-
-func (modules) Name() string {
- return "Modules"
-}
-
-func (modules) Filename(exported *Exported, module, fragment string) string {
- if module == exported.primary {
- return filepath.Join(primaryDir(exported), fragment)
- }
- return filepath.Join(moduleDir(exported, module), fragment)
-}
-
-func (modules) Finalize(exported *Exported) error {
- // Write out the primary module. This module can use symlinks and
- // other weird stuff, and will be the working dir for the go command.
- // It depends on all the other modules.
- primaryDir := primaryDir(exported)
- if err := os.MkdirAll(primaryDir, 0755); err != nil {
- return err
- }
- exported.Config.Dir = primaryDir
- if exported.written[exported.primary] == nil {
- exported.written[exported.primary] = make(map[string]string)
- }
-
- // Create a map of modulepath -> {module, version} for modulepaths
- // that are of the form `repoa/mod1@v1.1.0`.
- versions := make(map[string]moduleAtVersion)
- for module := range exported.written {
- if splt := strings.Split(module, "@"); len(splt) > 1 {
- versions[module] = moduleAtVersion{
- module: splt[0],
- version: splt[1],
- }
- }
- }
-
- // If the primary module already has a go.mod, write the contents to a temp
- // go.mod for now and then we will reset it when we are getting all the markers.
- if gomod := exported.written[exported.primary]["go.mod"]; gomod != "" {
- contents, err := ioutil.ReadFile(gomod)
- if err != nil {
- return err
- }
- if err := ioutil.WriteFile(gomod+".temp", contents, 0644); err != nil {
- return err
- }
- }
-
- exported.written[exported.primary]["go.mod"] = filepath.Join(primaryDir, "go.mod")
- primaryGomod := "module " + exported.primary + "\nrequire (\n"
- for other := range exported.written {
- if other == exported.primary {
- continue
- }
- version := moduleVersion(other)
- // If other is of the form `repo1/mod1@v1.1.0`,
- // then we need to extract the module and the version.
- if v, ok := versions[other]; ok {
- other = v.module
- version = v.version
- }
- primaryGomod += fmt.Sprintf("\t%v %v\n", other, version)
- }
- primaryGomod += ")\n"
- if err := ioutil.WriteFile(filepath.Join(primaryDir, "go.mod"), []byte(primaryGomod), 0644); err != nil {
- return err
- }
-
- // Create the mod cache so we can rename it later, even if we don't need it.
- if err := os.MkdirAll(modCache(exported), 0755); err != nil {
- return err
- }
-
- // Write out the go.mod files for the other modules.
- for module, files := range exported.written {
- if module == exported.primary {
- continue
- }
- dir := moduleDir(exported, module)
- modfile := filepath.Join(dir, "go.mod")
- // If other is of the form `repo1/mod1@v1.1.0`,
- // then we need to extract the module name without the version.
- if v, ok := versions[module]; ok {
- module = v.module
- }
- if err := ioutil.WriteFile(modfile, []byte("module "+module+"\n"), 0644); err != nil {
- return err
- }
- files["go.mod"] = modfile
- }
-
- // Zip up all the secondary modules into the proxy dir.
- modProxyDir := filepath.Join(exported.temp, "modproxy")
- for module, files := range exported.written {
- if module == exported.primary {
- continue
- }
- version := moduleVersion(module)
- // If other is of the form `repo1/mod1@v1.1.0`,
- // then we need to extract the module and the version.
- if v, ok := versions[module]; ok {
- module = v.module
- version = v.version
- }
- if err := writeModuleFiles(modProxyDir, module, version, files); err != nil {
- return fmt.Errorf("creating module proxy dir for %v: %v", module, err)
- }
- }
-
- // Discard the original mod cache dir, which contained the files written
- // for us by Export.
- if err := os.Rename(modCache(exported), modCache(exported)+".orig"); err != nil {
- return err
- }
- exported.Config.Env = append(exported.Config.Env,
- "GO111MODULE=on",
- "GOPATH="+filepath.Join(exported.temp, "modcache"),
- "GOMODCACHE=",
- "GOPROXY="+proxydir.ToURL(modProxyDir),
- "GOSUMDB=off",
- )
- gocmdRunner := &gocommand.Runner{}
- packagesinternal.SetGoCmdRunner(exported.Config, gocmdRunner)
-
- // Run go mod download to recreate the mod cache dir with all the extra
- // stuff in cache. All the files created by Export should be recreated.
- inv := gocommand.Invocation{
- Verb: "mod",
- Args: []string{"download"},
- Env: exported.Config.Env,
- BuildFlags: exported.Config.BuildFlags,
- WorkingDir: exported.Config.Dir,
- }
- if _, err := gocmdRunner.Run(context.Background(), inv); err != nil {
- return err
- }
- return nil
-}
-
-func writeModuleFiles(rootDir, module, ver string, filePaths map[string]string) error {
- fileData := make(map[string][]byte)
- for name, path := range filePaths {
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- fileData[name] = contents
- }
- return proxydir.WriteModuleVersion(rootDir, module, ver, fileData)
-}
-
-func modCache(exported *Exported) string {
- return filepath.Join(exported.temp, "modcache/pkg/mod")
-}
-
-func primaryDir(exported *Exported) string {
- return filepath.Join(exported.temp, path.Base(exported.primary))
-}
-
-func moduleDir(exported *Exported, module string) string {
- if strings.Contains(module, "@") {
- return filepath.Join(modCache(exported), module)
- }
- return filepath.Join(modCache(exported), path.Dir(module), path.Base(module)+"@"+moduleVersion(module))
-}
-
-var versionSuffixRE = regexp.MustCompile(`v\d+`)
-
-func moduleVersion(module string) string {
- if versionSuffixRE.MatchString(path.Base(module)) {
- return path.Base(module) + ".0.0"
- }
- return "v1.0.0"
-}