1package main
2
3import (
4 "io"
5 "io/fs"
6 "os"
7 "path/filepath"
8)
9
10func preservecasedir(cfg suiteconfig, relpath, src string) (string, error) {
11 dst := filepath.Join(cfg.workroot, filepath.FromSlash(relpath))
12 if err := os.RemoveAll(dst); err != nil {
13 return "", err
14 }
15 if err := copytree(src, dst); err != nil {
16 return "", err
17 }
18 if !cfg.keep {
19 _ = os.RemoveAll(src)
20 }
21 return dst, nil
22}
23
24func copytree(src, dst string) error {
25 return filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error {
26 if err != nil {
27 return err
28 }
29 rel, err := filepath.Rel(src, path)
30 if err != nil {
31 return err
32 }
33 target := dst
34 if rel != "." {
35 target = filepath.Join(dst, rel)
36 }
37
38 info, err := os.Lstat(path)
39 if err != nil {
40 return err
41 }
42
43 switch mode := info.Mode(); {
44 case mode.IsDir():
45 return os.MkdirAll(target, mode.Perm())
46 case mode&fs.ModeSymlink != 0:
47 link, err := os.Readlink(path)
48 if err != nil {
49 return err
50 }
51 if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
52 return err
53 }
54 return os.Symlink(link, target)
55 default:
56 if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
57 return err
58 }
59 in, err := os.Open(path)
60 if err != nil {
61 return err
62 }
63 defer in.Close()
64 out, err := os.OpenFile(target, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode.Perm())
65 if err != nil {
66 return err
67 }
68 if _, err := io.Copy(out, in); err != nil {
69 out.Close()
70 return err
71 }
72 if err := out.Close(); err != nil {
73 return err
74 }
75 return nil
76 }
77 })
78}