-
Notifications
You must be signed in to change notification settings - Fork 0
/
files.go
152 lines (127 loc) · 4.6 KB
/
files.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Package files allows to interact with files on a file system.
package files
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// FileExists returns true if the given file exists.
func FileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
// CopyTerraformFolderToTemp creates a copy of the given folder and all its contents in a temp folder with a unique name and the given prefix.
// This is useful when running multiple tests in parallel against the same set of Terraform files to ensure the
// tests don't overwrite each other's .terraform working directory and terraform.tfstate files. This method returns
// the path to the temp folder with the copied contents. Hidden files and folders, Terraform state files, and
// terraform.tfvars files are not copied to this temp folder, as you typically don't want them interfering with your
// tests.
func CopyTerraformFolderToTemp(folderPath string, tempFolderPrefix string) (string, error) {
tmpDir, err := ioutil.TempDir("", tempFolderPrefix)
if err != nil {
return "", err
}
// Inside of the temp folder, we create a subfolder that preserves the name of the folder we're copying from.
absFolderPath, err := filepath.Abs(folderPath)
if err != nil {
return "", err
}
folderName := filepath.Base(absFolderPath)
destFolder := filepath.Join(tmpDir, folderName)
if err := os.MkdirAll(destFolder, 0777); err != nil {
return "", err
}
filter := func(path string) bool {
return !PathContainsHiddenFileOrFolder(path) && !PathContainsTerraformStateOrVars(path)
}
if err := CopyFolderContentsWithFilter(folderPath, destFolder, filter); err != nil {
return "", err
}
return destFolder, nil
}
// CopyFolderContents copies all the files and folders within the given source folder to the destination folder.
func CopyFolderContents(source string, destination string) error {
return CopyFolderContentsWithFilter(source, destination, func(path string) bool {
return true
})
}
// CopyFolderContentsWithFilter copies the files and folders within the given source folder that pass the given filter (return true) to the
// destination folder.
func CopyFolderContentsWithFilter(source string, destination string, filter func(path string) bool) error {
files, err := ioutil.ReadDir(source)
if err != nil {
return err
}
for _, file := range files {
src := filepath.Join(source, file.Name())
dest := filepath.Join(destination, file.Name())
if !filter(src) {
continue
} else if file.IsDir() {
if err := os.MkdirAll(dest, file.Mode()); err != nil {
return err
}
if err := CopyFolderContentsWithFilter(src, dest, filter); err != nil {
return err
}
} else if isSymLink(file) {
if err := copySymLink(src, dest); err != nil {
return err
}
} else {
if err := CopyFile(src, dest); err != nil {
return err
}
}
}
return nil
}
// PathContainsTerraformStateOrVars returns true if the path corresponds to a Terraform state file or .tfvars file.
func PathContainsTerraformStateOrVars(path string) bool {
filename := filepath.Base(path)
return filename == "terraform.tfstate" || filename == "terraform.tfstate.backup" || filename == "terraform.tfvars"
}
// PathContainsHiddenFileOrFolder returns true if the given path contains a hidden file or folder.
func PathContainsHiddenFileOrFolder(path string) bool {
pathParts := strings.Split(path, string(filepath.Separator))
for _, pathPart := range pathParts {
if strings.HasPrefix(pathPart, ".") && pathPart != "." && pathPart != ".." {
return true
}
}
return false
}
// CopyFile copies a file from source to destination.
func CopyFile(source string, destination string) error {
contents, err := ioutil.ReadFile(source)
if err != nil {
return err
}
return WriteFileWithSamePermissions(source, destination, contents)
}
// WriteFileWithSamePermissions writes a file to the given destination with the given contents using the same permissions as the file at source.
func WriteFileWithSamePermissions(source string, destination string, contents []byte) error {
fileInfo, err := os.Stat(source)
if err != nil {
return err
}
return ioutil.WriteFile(destination, contents, fileInfo.Mode())
}
// isSymLink returns true if the given file is a symbolic link
// Per https://stackoverflow.com/a/18062079/2308858
func isSymLink(file os.FileInfo) bool {
return file.Mode()&os.ModeSymlink != 0
}
// copySymLink copies the source symbolic link to the given destination.
func copySymLink(source string, destination string) error {
symlinkPath, err := os.Readlink(source)
if err != nil {
return err
}
err = os.Symlink(symlinkPath, destination)
if err != nil {
return err
}
return nil
}