GoPLS Viewer

Home|gopls/go/packages/packagestest/modules.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
5package packagestest
6
7import (
8    "context"
9    "fmt"
10    "io/ioutil"
11    "os"
12    "path"
13    "path/filepath"
14    "regexp"
15    "strings"
16
17    "golang.org/x/tools/internal/gocommand"
18    "golang.org/x/tools/internal/packagesinternal"
19    "golang.org/x/tools/internal/proxydir"
20)
21
22// Modules is the exporter that produces module layouts.
23// Each "repository" is put in it's own module, and the module file generated
24// will have replace directives for all other modules.
25// Given the two files
26//
27//    golang.org/repoa#a/a.go
28//    golang.org/repob#b/b.go
29//
30// You would get the directory layout
31//
32//    /sometemporarydirectory
33//    ├── repoa
34//    │   ├── a
35//    │   │   └── a.go
36//    │   └── go.mod
37//    └── repob
38//        ├── b
39//        │   └── b.go
40//        └── go.mod
41//
42// and the working directory would be
43//
44//    /sometemporarydirectory/repoa
45var Modules = modules{}
46
47type modules struct{}
48
49type moduleAtVersion struct {
50    module  string
51    version string
52}
53
54func (modulesName() string {
55    return "Modules"
56}
57
58func (modulesFilename(exported *Exportedmodulefragment stringstring {
59    if module == exported.primary {
60        return filepath.Join(primaryDir(exported), fragment)
61    }
62    return filepath.Join(moduleDir(exportedmodule), fragment)
63}
64
65func (modulesFinalize(exported *Exportederror {
66    // Write out the primary module. This module can use symlinks and
67    // other weird stuff, and will be the working dir for the go command.
68    // It depends on all the other modules.
69    primaryDir := primaryDir(exported)
70    if err := os.MkdirAll(primaryDir0755); err != nil {
71        return err
72    }
73    exported.Config.Dir = primaryDir
74    if exported.written[exported.primary] == nil {
75        exported.written[exported.primary] = make(map[string]string)
76    }
77
78    // Create a map of modulepath -> {module, version} for modulepaths
79    // that are of the form `repoa/mod1@v1.1.0`.
80    versions := make(map[string]moduleAtVersion)
81    for module := range exported.written {
82        if splt := strings.Split(module"@"); len(splt) > 1 {
83            versions[module] = moduleAtVersion{
84                module:  splt[0],
85                versionsplt[1],
86            }
87        }
88    }
89
90    // If the primary module already has a go.mod, write the contents to a temp
91    // go.mod for now and then we will reset it when we are getting all the markers.
92    if gomod := exported.written[exported.primary]["go.mod"]; gomod != "" {
93        contentserr := ioutil.ReadFile(gomod)
94        if err != nil {
95            return err
96        }
97        if err := ioutil.WriteFile(gomod+".temp"contents0644); err != nil {
98            return err
99        }
100    }
101
102    exported.written[exported.primary]["go.mod"] = filepath.Join(primaryDir"go.mod")
103    primaryGomod := "module " + exported.primary + "\nrequire (\n"
104    for other := range exported.written {
105        if other == exported.primary {
106            continue
107        }
108        version := moduleVersion(other)
109        // If other is of the form `repo1/mod1@v1.1.0`,
110        // then we need to extract the module and the version.
111        if vok := versions[other]; ok {
112            other = v.module
113            version = v.version
114        }
115        primaryGomod += fmt.Sprintf("\t%v %v\n"otherversion)
116    }
117    primaryGomod += ")\n"
118    if err := ioutil.WriteFile(filepath.Join(primaryDir"go.mod"), []byte(primaryGomod), 0644); err != nil {
119        return err
120    }
121
122    // Create the mod cache so we can rename it later, even if we don't need it.
123    if err := os.MkdirAll(modCache(exported), 0755); err != nil {
124        return err
125    }
126
127    // Write out the go.mod files for the other modules.
128    for modulefiles := range exported.written {
129        if module == exported.primary {
130            continue
131        }
132        dir := moduleDir(exportedmodule)
133        modfile := filepath.Join(dir"go.mod")
134        // If other is of the form `repo1/mod1@v1.1.0`,
135        // then we need to extract the module name without the version.
136        if vok := versions[module]; ok {
137            module = v.module
138        }
139        if err := ioutil.WriteFile(modfile, []byte("module "+module+"\n"), 0644); err != nil {
140            return err
141        }
142        files["go.mod"] = modfile
143    }
144
145    // Zip up all the secondary modules into the proxy dir.
146    modProxyDir := filepath.Join(exported.temp"modproxy")
147    for modulefiles := range exported.written {
148        if module == exported.primary {
149            continue
150        }
151        version := moduleVersion(module)
152        // If other is of the form `repo1/mod1@v1.1.0`,
153        // then we need to extract the module and the version.
154        if vok := versions[module]; ok {
155            module = v.module
156            version = v.version
157        }
158        if err := writeModuleFiles(modProxyDirmoduleversionfiles); err != nil {
159            return fmt.Errorf("creating module proxy dir for %v: %v"moduleerr)
160        }
161    }
162
163    // Discard the original mod cache dir, which contained the files written
164    // for us by Export.
165    if err := os.Rename(modCache(exported), modCache(exported)+".orig"); err != nil {
166        return err
167    }
168    exported.Config.Env = append(exported.Config.Env,
169        "GO111MODULE=on",
170        "GOPATH="+filepath.Join(exported.temp"modcache"),
171        "GOMODCACHE=",
172        "GOPROXY="+proxydir.ToURL(modProxyDir),
173        "GOSUMDB=off",
174    )
175    gocmdRunner := &gocommand.Runner{}
176    packagesinternal.SetGoCmdRunner(exported.ConfiggocmdRunner)
177
178    // Run go mod download to recreate the mod cache dir with all the extra
179    // stuff in cache. All the files created by Export should be recreated.
180    inv := gocommand.Invocation{
181        Verb:       "mod",
182        Args:       []string{"download""all"},
183        Env:        exported.Config.Env,
184        BuildFlagsexported.Config.BuildFlags,
185        WorkingDirexported.Config.Dir,
186    }
187    if _err := gocmdRunner.Run(context.Background(), inv); err != nil {
188        return err
189    }
190    return nil
191}
192
193func writeModuleFiles(rootDirmodulever stringfilePaths map[string]stringerror {
194    fileData := make(map[string][]byte)
195    for namepath := range filePaths {
196        contentserr := ioutil.ReadFile(path)
197        if err != nil {
198            return err
199        }
200        fileData[name] = contents
201    }
202    return proxydir.WriteModuleVersion(rootDirmoduleverfileData)
203}
204
205func modCache(exported *Exportedstring {
206    return filepath.Join(exported.temp"modcache/pkg/mod")
207}
208
209func primaryDir(exported *Exportedstring {
210    return filepath.Join(exported.temppath.Base(exported.primary))
211}
212
213func moduleDir(exported *Exportedmodule stringstring {
214    if strings.Contains(module"@") {
215        return filepath.Join(modCache(exported), module)
216    }
217    return filepath.Join(modCache(exported), path.Dir(module), path.Base(module)+"@"+moduleVersion(module))
218}
219
220var versionSuffixRE = regexp.MustCompile(`v\d+`)
221
222func moduleVersion(module stringstring {
223    if versionSuffixRE.MatchString(path.Base(module)) {
224        return path.Base(module) + ".0.0"
225    }
226    return "v1.0.0"
227}
228
MembersX
proxydir
modules
modules.Finalize.RangeStmt_2805.other
modules.Finalize.exported
modules.Finalize.err
modules.Finalize.inv
modules.Filename.module
primaryDir.exported
moduleVersion.module
modules.Finalize
modules.Finalize.primaryDir
writeModuleFiles.module
modules.Finalize.RangeStmt_2805.BlockStmt.version
modules.Finalize.RangeStmt_4145.BlockStmt.version
modules.Finalize.versions
context
modules.Filename.exported
moduleAtVersion.module
modules.Finalize.RangeStmt_3538.files
primaryDir
modules.Finalize.RangeStmt_2058.BlockStmt.splt
modules.Finalize.BlockStmt.err
writeModuleFiles.filePaths
modCache
moduleDir.module
modCache.exported
writeModuleFiles.ver
writeModuleFiles.fileData
writeModuleFiles.RangeStmt_5712.BlockStmt.err
writeModuleFiles.RangeStmt_5712.path
packagesinternal
modules.Finalize.RangeStmt_3538.BlockStmt.err
writeModuleFiles.rootDir
modules.Finalize.modProxyDir
modules.Finalize.RangeStmt_4145.BlockStmt.err
modules.Finalize.gocmdRunner
gocommand
modules.Filename
modules.Filename.fragment
modules.Finalize.RangeStmt_2058.module
modules.Finalize.RangeStmt_3538.BlockStmt.dir
modules.Finalize.RangeStmt_3538.BlockStmt.modfile
moduleAtVersion.version
modules.Name
writeModuleFiles.RangeStmt_5712.name
moduleDir
modules.Finalize.RangeStmt_3538.module
modules.Finalize.RangeStmt_4145.module
writeModuleFiles
writeModuleFiles.RangeStmt_5712.BlockStmt.contents
moduleAtVersion
modules.Finalize.RangeStmt_4145.files
modules.Finalize._
moduleDir.exported
modules.Finalize.BlockStmt.contents
moduleVersion
Members
X