1
2
3
4 package kio
5
6 import (
7 "fmt"
8 "os"
9 "path/filepath"
10
11 "sigs.k8s.io/kustomize/kyaml/errors"
12 "sigs.k8s.io/kustomize/kyaml/filesys"
13 "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
14 "sigs.k8s.io/kustomize/kyaml/sets"
15 "sigs.k8s.io/kustomize/kyaml/yaml"
16 )
17
18
19
20 var requiredResourcePackageAnnotations = []string{kioutil.IndexAnnotation, kioutil.PathAnnotation}
21
22
23 type PackageBuffer struct {
24 Nodes []*yaml.RNode
25 }
26
27 func (r *PackageBuffer) Read() ([]*yaml.RNode, error) {
28 return r.Nodes, nil
29 }
30
31 func (r *PackageBuffer) Write(nodes []*yaml.RNode) error {
32 r.Nodes = nodes
33 return nil
34 }
35
36
37
38
39 type LocalPackageReadWriter struct {
40 Kind string `yaml:"kind,omitempty"`
41
42 KeepReaderAnnotations bool `yaml:"keepReaderAnnotations,omitempty"`
43
44
45 PreserveSeqIndent bool
46
47
48 PackagePath string `yaml:"path,omitempty"`
49
50
51
52 PackageFileName string `yaml:"packageFileName,omitempty"`
53
54
55
56
57 MatchFilesGlob []string `yaml:"matchFilesGlob,omitempty"`
58
59
60
61 IncludeSubpackages bool `yaml:"includeSubpackages,omitempty"`
62
63
64
65 ErrorIfNonResources bool `yaml:"errorIfNonResources,omitempty"`
66
67
68
69 OmitReaderAnnotations bool `yaml:"omitReaderAnnotations,omitempty"`
70
71
72 SetAnnotations map[string]string `yaml:"setAnnotations,omitempty"`
73
74
75 NoDeleteFiles bool `yaml:"noDeleteFiles,omitempty"`
76
77 files sets.String
78
79
80
81 FileSkipFunc LocalPackageSkipFileFunc
82
83
84 FileSystem filesys.FileSystemOrOnDisk
85
86
87
88
89
90
91 WrapBareSeqNode bool
92 }
93
94 func (r *LocalPackageReadWriter) Read() ([]*yaml.RNode, error) {
95 nodes, err := LocalPackageReader{
96 PackagePath: r.PackagePath,
97 MatchFilesGlob: r.MatchFilesGlob,
98 IncludeSubpackages: r.IncludeSubpackages,
99 ErrorIfNonResources: r.ErrorIfNonResources,
100 SetAnnotations: r.SetAnnotations,
101 PackageFileName: r.PackageFileName,
102 FileSkipFunc: r.FileSkipFunc,
103 PreserveSeqIndent: r.PreserveSeqIndent,
104 FileSystem: r.FileSystem,
105 WrapBareSeqNode: r.WrapBareSeqNode,
106 }.Read()
107 if err != nil {
108 return nil, errors.Wrap(err)
109 }
110
111 if !r.NoDeleteFiles {
112 r.files, err = r.getFiles(nodes)
113 if err != nil {
114 return nil, errors.Wrap(err)
115 }
116 }
117 return nodes, nil
118 }
119
120 func (r *LocalPackageReadWriter) Write(nodes []*yaml.RNode) error {
121 newFiles, err := r.getFiles(nodes)
122 if err != nil {
123 return errors.Wrap(err)
124 }
125 var clear []string
126 for k := range r.SetAnnotations {
127 clear = append(clear, k)
128 }
129 err = LocalPackageWriter{
130 PackagePath: r.PackagePath,
131 ClearAnnotations: clear,
132 KeepReaderAnnotations: r.KeepReaderAnnotations,
133 FileSystem: r.FileSystem,
134 }.Write(nodes)
135 if err != nil {
136 return errors.Wrap(err)
137 }
138 deleteFiles := r.files.Difference(newFiles)
139 for f := range deleteFiles {
140 if err = r.FileSystem.RemoveAll(filepath.Join(r.PackagePath, f)); err != nil {
141 return errors.Wrap(err)
142 }
143 }
144 return nil
145 }
146
147 func (r *LocalPackageReadWriter) getFiles(nodes []*yaml.RNode) (sets.String, error) {
148 val := sets.String{}
149 for _, n := range nodes {
150 path, _, err := kioutil.GetFileAnnotations(n)
151 if err != nil {
152 return nil, errors.Wrap(err)
153 }
154 val.Insert(path)
155 }
156 return val, nil
157 }
158
159
160
161
162 type LocalPackageSkipFileFunc func(relPath string) bool
163
164
165 type LocalPackageReader struct {
166 Kind string `yaml:"kind,omitempty"`
167
168
169 PackagePath string `yaml:"path,omitempty"`
170
171
172
173 PackageFileName string `yaml:"packageFileName,omitempty"`
174
175
176
177
178 MatchFilesGlob []string `yaml:"matchFilesGlob,omitempty"`
179
180
181
182 IncludeSubpackages bool `yaml:"includeSubpackages,omitempty"`
183
184
185
186 ErrorIfNonResources bool `yaml:"errorIfNonResources,omitempty"`
187
188
189
190 OmitReaderAnnotations bool `yaml:"omitReaderAnnotations,omitempty"`
191
192
193 SetAnnotations map[string]string `yaml:"setAnnotations,omitempty"`
194
195
196
197 FileSkipFunc LocalPackageSkipFileFunc
198
199
200 PreserveSeqIndent bool
201
202
203 FileSystem filesys.FileSystemOrOnDisk
204
205
206
207
208
209
210 WrapBareSeqNode bool
211 }
212
213 var _ Reader = LocalPackageReader{}
214
215 var DefaultMatch = []string{"*.yaml", "*.yml"}
216 var JSONMatch = []string{"*.json"}
217 var MatchAll = append(DefaultMatch, JSONMatch...)
218
219
220 func (r LocalPackageReader) Read() ([]*yaml.RNode, error) {
221 if r.PackagePath == "" {
222 return nil, fmt.Errorf("must specify package path")
223 }
224
225
226 r.PackagePath = filepath.ToSlash(r.PackagePath)
227 if len(r.MatchFilesGlob) == 0 {
228 r.MatchFilesGlob = DefaultMatch
229 }
230
231 var operand ResourceNodeSlice
232 var pathRelativeTo string
233 var err error
234 ignoreFilesMatcher := &ignoreFilesMatcher{
235 fs: r.FileSystem,
236 }
237 dir, file, err := r.FileSystem.CleanedAbs(r.PackagePath)
238 if err != nil {
239 return nil, errors.Wrap(err)
240 }
241 r.PackagePath = filepath.Join(string(dir), file)
242 err = r.FileSystem.Walk(r.PackagePath, func(
243 path string, info os.FileInfo, err error) error {
244 if err != nil {
245 return errors.Wrap(err)
246 }
247
248
249 if path == r.PackagePath {
250 if info.IsDir() {
251
252
253 pathRelativeTo = r.PackagePath
254 return ignoreFilesMatcher.readIgnoreFile(path)
255 }
256
257
258
259 pathRelativeTo = filepath.Dir(r.PackagePath)
260 }
261
262
263 if info.IsDir() {
264 return r.shouldSkipDir(path, ignoreFilesMatcher)
265 }
266
267
268
269 relPath, err := filepath.Rel(pathRelativeTo, path)
270 if err != nil {
271 return errors.WrapPrefixf(err, pathRelativeTo)
272 }
273 if match, err := r.shouldSkipFile(path, relPath, ignoreFilesMatcher); err != nil {
274 return err
275 } else if match {
276
277 return nil
278 }
279
280 r.initReaderAnnotations(relPath, info)
281 nodes, err := r.readFile(path, info)
282 if err != nil {
283 return errors.WrapPrefixf(err, path)
284 }
285 operand = append(operand, nodes...)
286 return nil
287 })
288 return operand, err
289 }
290
291
292 func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode, error) {
293 f, err := r.FileSystem.Open(path)
294 if err != nil {
295 return nil, err
296 }
297 defer f.Close()
298
299 rr := &ByteReader{
300 DisableUnwrapping: true,
301 Reader: f,
302 OmitReaderAnnotations: r.OmitReaderAnnotations,
303 SetAnnotations: r.SetAnnotations,
304 PreserveSeqIndent: r.PreserveSeqIndent,
305 WrapBareSeqNode: r.WrapBareSeqNode,
306 }
307 return rr.Read()
308 }
309
310
311 func (r *LocalPackageReader) shouldSkipFile(path, relPath string, matcher *ignoreFilesMatcher) (bool, error) {
312
313 if matcher.matchFile(path) {
314 return true, nil
315 }
316
317 if r.FileSkipFunc != nil && r.FileSkipFunc(relPath) {
318 return true, nil
319 }
320
321
322 for _, g := range r.MatchFilesGlob {
323 if match, err := filepath.Match(g, filepath.Base(path)); err != nil {
324 return true, errors.Wrap(err)
325 } else if match {
326 return false, nil
327 }
328 }
329 return true, nil
330 }
331
332
333 func (r *LocalPackageReader) initReaderAnnotations(path string, _ os.FileInfo) {
334 if r.SetAnnotations == nil {
335 r.SetAnnotations = map[string]string{}
336 }
337 if !r.OmitReaderAnnotations {
338 r.SetAnnotations[kioutil.PathAnnotation] = path
339 r.SetAnnotations[kioutil.LegacyPathAnnotation] = path
340 }
341 }
342
343
344 func (r *LocalPackageReader) shouldSkipDir(path string, matcher *ignoreFilesMatcher) error {
345 if matcher.matchDir(path) {
346 return filepath.SkipDir
347 }
348
349 if r.PackageFileName == "" {
350 return nil
351 }
352
353 if !r.FileSystem.Exists(filepath.Join(path, r.PackageFileName)) {
354 return nil
355 }
356 if !r.IncludeSubpackages {
357 return filepath.SkipDir
358 }
359 return matcher.readIgnoreFile(path)
360 }
361
View as plain text