@@ -7,7 +7,9 @@ package modcmd
7
7
import (
8
8
"bytes"
9
9
"context"
10
+ "errors"
10
11
"fmt"
12
+ "go/build"
11
13
"io"
12
14
"io/fs"
13
15
"os"
@@ -19,7 +21,9 @@ import (
19
21
"cmd/go/internal/cfg"
20
22
"cmd/go/internal/fsys"
21
23
"cmd/go/internal/imports"
24
+ "cmd/go/internal/load"
22
25
"cmd/go/internal/modload"
26
+ "cmd/go/internal/str"
23
27
24
28
"golang.org/x/mod/module"
25
29
"golang.org/x/mod/semver"
@@ -182,19 +186,76 @@ func moduleLine(m, r module.Version) string {
182
186
}
183
187
184
188
func vendorPkg (vdir , pkg string ) {
189
+ // TODO(#42504): Instead of calling modload.ImportMap then build.ImportDir,
190
+ // just call load.PackagesAndErrors. To do that, we need to add a good way
191
+ // to ignore build constraints.
185
192
realPath := modload .ImportMap (pkg )
186
193
if realPath != pkg && modload .ImportMap (realPath ) != "" {
187
194
fmt .Fprintf (os .Stderr , "warning: %s imported as both %s and %s; making two copies.\n " , realPath , realPath , pkg )
188
195
}
189
196
197
+ copiedFiles := make (map [string ]bool )
190
198
dst := filepath .Join (vdir , pkg )
191
199
src := modload .PackageDir (realPath )
192
200
if src == "" {
193
201
fmt .Fprintf (os .Stderr , "internal error: no pkg for %s -> %s\n " , pkg , realPath )
194
202
}
195
- copyDir (dst , src , matchPotentialSourceFile )
203
+ copyDir (dst , src , matchPotentialSourceFile , copiedFiles )
196
204
if m := modload .PackageModule (realPath ); m .Path != "" {
197
- copyMetadata (m .Path , realPath , dst , src )
205
+ copyMetadata (m .Path , realPath , dst , src , copiedFiles )
206
+ }
207
+
208
+ ctx := build .Default
209
+ ctx .UseAllFiles = true
210
+ bp , err := ctx .ImportDir (src , build .IgnoreVendor )
211
+ // Because UseAllFiles is set on the build.Context, it's possible ta get
212
+ // a MultiplePackageError on an otherwise valid package: the package could
213
+ // have different names for GOOS=windows and GOOS=mac for example. On the
214
+ // other hand if there's a NoGoError, the package might have source files
215
+ // specifying "// +build ignore" those packages should be skipped because
216
+ // embeds from ignored files can't be used.
217
+ // TODO(#42504): Find a better way to avoid errors from ImportDir. We'll
218
+ // need to figure this out when we switch to PackagesAndErrors as per the
219
+ // TODO above.
220
+ var multiplePackageError * build.MultiplePackageError
221
+ var noGoError * build.NoGoError
222
+ if err != nil {
223
+ if errors .As (err , & noGoError ) {
224
+ return // No source files in this package are built. Skip embeds in ignored files.
225
+ } else if ! errors .As (err , & multiplePackageError ) { // multiplePackgeErrors are okay, but others are not.
226
+ base .Fatalf ("internal error: failed to find embedded files of %s: %v\n " , pkg , err )
227
+ }
228
+ }
229
+ embedPatterns := str .StringList (bp .EmbedPatterns , bp .TestEmbedPatterns , bp .XTestEmbedPatterns )
230
+ embeds , err := load .ResolveEmbed (bp .Dir , embedPatterns )
231
+ if err != nil {
232
+ base .Fatalf ("go mod vendor: %v" , err )
233
+ }
234
+ for _ , embed := range embeds {
235
+ embedDst := filepath .Join (dst , embed )
236
+ if copiedFiles [embedDst ] {
237
+ continue
238
+ }
239
+
240
+ // Copy the file as is done by copyDir below.
241
+ r , err := os .Open (filepath .Join (src , embed ))
242
+ if err != nil {
243
+ base .Fatalf ("go mod vendor: %v" , err )
244
+ }
245
+ if err := os .MkdirAll (filepath .Dir (embedDst ), 0777 ); err != nil {
246
+ base .Fatalf ("go mod vendor: %v" , err )
247
+ }
248
+ w , err := os .Create (embedDst )
249
+ if err != nil {
250
+ base .Fatalf ("go mod vendor: %v" , err )
251
+ }
252
+ if _ , err := io .Copy (w , r ); err != nil {
253
+ base .Fatalf ("go mod vendor: %v" , err )
254
+ }
255
+ r .Close ()
256
+ if err := w .Close (); err != nil {
257
+ base .Fatalf ("go mod vendor: %v" , err )
258
+ }
198
259
}
199
260
}
200
261
@@ -207,14 +268,14 @@ var copiedMetadata = make(map[metakey]bool)
207
268
208
269
// copyMetadata copies metadata files from parents of src to parents of dst,
209
270
// stopping after processing the src parent for modPath.
210
- func copyMetadata (modPath , pkg , dst , src string ) {
271
+ func copyMetadata (modPath , pkg , dst , src string , copiedFiles map [ string ] bool ) {
211
272
for parent := 0 ; ; parent ++ {
212
273
if copiedMetadata [metakey {modPath , dst }] {
213
274
break
214
275
}
215
276
copiedMetadata [metakey {modPath , dst }] = true
216
277
if parent > 0 {
217
- copyDir (dst , src , matchMetadata )
278
+ copyDir (dst , src , matchMetadata , copiedFiles )
218
279
}
219
280
if modPath == pkg {
220
281
break
@@ -282,7 +343,7 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
282
343
}
283
344
284
345
// copyDir copies all regular files satisfying match(info) from src to dst.
285
- func copyDir (dst , src string , match func (dir string , info fs.DirEntry ) bool ) {
346
+ func copyDir (dst , src string , match func (dir string , info fs.DirEntry ) bool , copiedFiles map [ string ] bool ) {
286
347
files , err := os .ReadDir (src )
287
348
if err != nil {
288
349
base .Fatalf ("go mod vendor: %v" , err )
@@ -294,11 +355,14 @@ func copyDir(dst, src string, match func(dir string, info fs.DirEntry) bool) {
294
355
if file .IsDir () || ! file .Type ().IsRegular () || ! match (src , file ) {
295
356
continue
296
357
}
358
+ copiedFiles [file .Name ()] = true
297
359
r , err := os .Open (filepath .Join (src , file .Name ()))
298
360
if err != nil {
299
361
base .Fatalf ("go mod vendor: %v" , err )
300
362
}
301
- w , err := os .Create (filepath .Join (dst , file .Name ()))
363
+ dstPath := filepath .Join (dst , file .Name ())
364
+ copiedFiles [dstPath ] = true
365
+ w , err := os .Create (dstPath )
302
366
if err != nil {
303
367
base .Fatalf ("go mod vendor: %v" , err )
304
368
}
0 commit comments