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