main shinobi / tests / runner / preserve.go
 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}