]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/bootstrap_test/overlaydir_test.go
cmd/dist: drop host test support
[gostls13.git] / src / cmd / internal / bootstrap_test / overlaydir_test.go
1 // Copyright 2019 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 bootstrap_test
6
7 import (
8         "io"
9         "io/fs"
10         "os"
11         "path/filepath"
12         "strings"
13 )
14
15 // overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
16 //
17 // TODO: Once we no longer need to support the misc module in GOPATH mode,
18 // factor this function out into a package to reduce duplication.
19 func overlayDir(dstRoot, srcRoot string) error {
20         dstRoot = filepath.Clean(dstRoot)
21         if err := os.MkdirAll(dstRoot, 0777); err != nil {
22                 return err
23         }
24
25         srcRoot, err := filepath.Abs(srcRoot)
26         if err != nil {
27                 return err
28         }
29
30         return filepath.WalkDir(srcRoot, func(srcPath string, entry fs.DirEntry, err error) error {
31                 if err != nil || srcPath == srcRoot {
32                         return err
33                 }
34                 if filepath.Base(srcPath) == "testdata" {
35                         // We're just building, so no need to copy those.
36                         return fs.SkipDir
37                 }
38
39                 suffix := strings.TrimPrefix(srcPath, srcRoot)
40                 for len(suffix) > 0 && suffix[0] == filepath.Separator {
41                         suffix = suffix[1:]
42                 }
43                 dstPath := filepath.Join(dstRoot, suffix)
44
45                 info, err := entry.Info()
46                 perm := info.Mode() & os.ModePerm
47                 if info.Mode()&os.ModeSymlink != 0 {
48                         info, err = os.Stat(srcPath)
49                         if err != nil {
50                                 return err
51                         }
52                         perm = info.Mode() & os.ModePerm
53                 }
54
55                 // Always make copies of directories.
56                 // If we add a file in the overlay, we don't want to add it in the original.
57                 if info.IsDir() {
58                         return os.MkdirAll(dstPath, perm|0200)
59                 }
60
61                 // If we can use a hard link, do that instead of copying bytes.
62                 // Go builds don't like symlinks in some cases, such as go:embed.
63                 if err := os.Link(srcPath, dstPath); err == nil {
64                         return nil
65                 }
66
67                 // Otherwise, copy the bytes.
68                 src, err := os.Open(srcPath)
69                 if err != nil {
70                         return err
71                 }
72                 defer src.Close()
73
74                 dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
75                 if err != nil {
76                         return err
77                 }
78
79                 _, err = io.Copy(dst, src)
80                 if closeErr := dst.Close(); err == nil {
81                         err = closeErr
82                 }
83                 return err
84         })
85 }