...
1
2
3
4 package kio
5
6 import (
7 "bytes"
8 "fmt"
9 "os"
10 "path/filepath"
11 "strings"
12
13 "sigs.k8s.io/kustomize/kyaml/errors"
14 "sigs.k8s.io/kustomize/kyaml/filesys"
15 "sigs.k8s.io/kustomize/kyaml/kio/kioutil"
16 "sigs.k8s.io/kustomize/kyaml/yaml"
17 )
18
19
20 type LocalPackageWriter struct {
21 Kind string `yaml:"kind,omitempty"`
22
23
24 PackagePath string `yaml:"path,omitempty"`
25
26
27 KeepReaderAnnotations bool `yaml:"keepReaderAnnotations,omitempty"`
28
29
30 ClearAnnotations []string `yaml:"clearAnnotations,omitempty"`
31
32
33 FileSystem filesys.FileSystemOrOnDisk
34 }
35
36 var _ Writer = LocalPackageWriter{}
37
38 func (r LocalPackageWriter) Write(nodes []*yaml.RNode) error {
39
40 if err := kioutil.DefaultPathAndIndexAnnotation("", nodes); err != nil {
41 return err
42 }
43
44 if !r.FileSystem.Exists(r.PackagePath) {
45 return errors.WrapPrefixf(os.ErrNotExist, "could not write to %q", r.PackagePath)
46 }
47 if !r.FileSystem.IsDir(r.PackagePath) {
48
49
50 r.PackagePath = filepath.Dir(r.PackagePath)
51 }
52
53
54 if err := r.errorIfMissingRequiredAnnotation(nodes); err != nil {
55 return err
56 }
57 outputFiles, err := r.indexByFilePath(nodes)
58 if err != nil {
59 return err
60 }
61 for k := range outputFiles {
62 if err = kioutil.SortNodes(outputFiles[k]); err != nil {
63 return errors.Wrap(err)
64 }
65 }
66
67 if !r.KeepReaderAnnotations {
68 r.ClearAnnotations = append(r.ClearAnnotations, kioutil.PathAnnotation)
69 r.ClearAnnotations = append(r.ClearAnnotations, kioutil.LegacyPathAnnotation)
70 }
71
72
73 for path := range outputFiles {
74 outputPath := filepath.Join(r.PackagePath, path)
75 if r.FileSystem.IsDir(outputPath) {
76 return fmt.Errorf("config.kubernetes.io/path cannot be a directory: %s", path)
77 }
78
79 err = r.FileSystem.MkdirAll(filepath.Dir(outputPath))
80 if err != nil {
81 return errors.Wrap(err)
82 }
83 }
84
85
86 buf := bytes.NewBuffer(nil)
87 for path := range outputFiles {
88 outputPath := filepath.Join(r.PackagePath, path)
89 err = r.FileSystem.MkdirAll(filepath.Dir(filepath.Join(r.PackagePath, path)))
90 if err != nil {
91 return errors.Wrap(err)
92 }
93
94 buf.Reset()
95 w := ByteWriter{
96 Writer: buf,
97 KeepReaderAnnotations: r.KeepReaderAnnotations,
98 ClearAnnotations: r.ClearAnnotations,
99 }
100 if err = w.Write(outputFiles[path]); err != nil {
101 return errors.Wrap(err)
102 }
103
104 if err := r.FileSystem.WriteFile(outputPath, buf.Bytes()); err != nil {
105 return errors.Wrap(err)
106 }
107 }
108
109 return nil
110 }
111
112 func (r LocalPackageWriter) errorIfMissingRequiredAnnotation(nodes []*yaml.RNode) error {
113 for i := range nodes {
114 for _, s := range requiredResourcePackageAnnotations {
115 key, err := nodes[i].Pipe(yaml.GetAnnotation(s))
116 if err != nil {
117 return errors.Wrap(err)
118 }
119 if key == nil || key.YNode() == nil || key.YNode().Value == "" {
120 return errors.Errorf(
121 "resources must be annotated with %s to be written to files", s)
122 }
123 }
124 }
125 return nil
126 }
127
128 func (r LocalPackageWriter) indexByFilePath(nodes []*yaml.RNode) (map[string][]*yaml.RNode, error) {
129 outputFiles := map[string][]*yaml.RNode{}
130 for i := range nodes {
131
132 node := nodes[i]
133 value, err := node.Pipe(yaml.GetAnnotation(kioutil.PathAnnotation))
134 if err != nil {
135
136 return nil, errors.Wrap(err)
137 }
138 path := value.YNode().Value
139 outputFiles[path] = append(outputFiles[path], node)
140
141 if filepath.IsAbs(path) {
142 return nil, errors.Errorf("package paths may not be absolute paths")
143 }
144 if strings.Contains(filepath.Clean(path), "..") {
145 return nil, fmt.Errorf("resource must be written under package %s: %s",
146 r.PackagePath, filepath.Clean(path))
147 }
148 }
149 return outputFiles, nil
150 }
151
View as plain text