...
1 package fs
2
3 import (
4 "bytes"
5 "io"
6 "os"
7
8 "gotest.tools/v3/assert"
9 )
10
11
12
13 type resourcePath struct{}
14
15 func (p *resourcePath) Path() string {
16 return "manifest: not a filesystem path"
17 }
18
19 func (p *resourcePath) Remove() {}
20
21 type filePath struct {
22 resourcePath
23 file *file
24 }
25
26 func (p *filePath) SetContent(content io.ReadCloser) {
27 p.file.content = content
28 }
29
30 func (p *filePath) SetUID(uid uint32) {
31 p.file.uid = uid
32 }
33
34 func (p *filePath) SetGID(gid uint32) {
35 p.file.gid = gid
36 }
37
38 type directoryPath struct {
39 resourcePath
40 directory *directory
41 }
42
43 func (p *directoryPath) SetUID(uid uint32) {
44 p.directory.uid = uid
45 }
46
47 func (p *directoryPath) SetGID(gid uint32) {
48 p.directory.gid = gid
49 }
50
51 func (p *directoryPath) AddSymlink(path, target string) error {
52 p.directory.items[path] = &symlink{
53 resource: newResource(defaultSymlinkMode),
54 target: target,
55 }
56 return nil
57 }
58
59 func (p *directoryPath) AddFile(path string, ops ...PathOp) error {
60 newFile := &file{resource: newResource(0)}
61 p.directory.items[path] = newFile
62 exp := &filePath{file: newFile}
63 return applyPathOps(exp, ops)
64 }
65
66 func (p *directoryPath) AddGlobFiles(glob string, ops ...PathOp) error {
67 newFile := &file{resource: newResource(0)}
68 newFilePath := &filePath{file: newFile}
69 p.directory.filepathGlobs[glob] = newFilePath
70 return applyPathOps(newFilePath, ops)
71 }
72
73 func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error {
74 newDir := newDirectoryWithDefaults()
75 p.directory.items[path] = newDir
76 exp := &directoryPath{directory: newDir}
77 return applyPathOps(exp, ops)
78 }
79
80
81
82
83 func Expected(t assert.TestingT, ops ...PathOp) Manifest {
84 if ht, ok := t.(helperT); ok {
85 ht.Helper()
86 }
87
88 newDir := newDirectoryWithDefaults()
89 e := &directoryPath{directory: newDir}
90 assert.NilError(t, applyPathOps(e, ops))
91 return Manifest{root: newDir}
92 }
93
94 func newDirectoryWithDefaults() *directory {
95 return &directory{
96 resource: newResource(defaultRootDirMode),
97 items: make(map[string]dirEntry),
98 filepathGlobs: make(map[string]*filePath),
99 }
100 }
101
102 func newResource(mode os.FileMode) resource {
103 return resource{
104 mode: mode,
105 uid: currentUID(),
106 gid: currentGID(),
107 }
108 }
109
110 func currentUID() uint32 {
111 return normalizeID(os.Getuid())
112 }
113
114 func currentGID() uint32 {
115 return normalizeID(os.Getgid())
116 }
117
118 func normalizeID(id int) uint32 {
119
120 if id < 0 {
121 return 0
122 }
123 return uint32(id)
124 }
125
126 var anyFileContent = io.NopCloser(bytes.NewReader(nil))
127
128
129
130 func MatchAnyFileContent(path Path) error {
131 if m, ok := path.(*filePath); ok {
132 m.SetContent(anyFileContent)
133 }
134 return nil
135 }
136
137
138
139 func MatchContentIgnoreCarriageReturn(path Path) error {
140 if m, ok := path.(*filePath); ok {
141 m.file.ignoreCariageReturn = true
142 }
143 return nil
144 }
145
146 const anyFile = "*"
147
148
149
150 func MatchExtraFiles(path Path) error {
151 if m, ok := path.(*directoryPath); ok {
152 return m.AddFile(anyFile)
153 }
154 return nil
155 }
156
157
158
159
160
161 type CompareResult interface {
162 Success() bool
163 FailureMessage() string
164 }
165
166
167
168 func MatchFileContent(f func([]byte) CompareResult) PathOp {
169 return func(path Path) error {
170 if m, ok := path.(*filePath); ok {
171 m.file.compareContentFunc = f
172 }
173 return nil
174 }
175 }
176
177
178
179 func MatchFilesWithGlob(glob string, ops ...PathOp) PathOp {
180 return func(path Path) error {
181 if m, ok := path.(*directoryPath); ok {
182 return m.AddGlobFiles(glob, ops...)
183 }
184 return nil
185 }
186 }
187
188
189 const anyFileMode os.FileMode = 4294967295
190
191
192
193 func MatchAnyFileMode(path Path) error {
194 if m, ok := path.(manifestResource); ok {
195 m.SetMode(anyFileMode)
196 }
197 return nil
198 }
199
View as plain text