@@ -88,11 +88,48 @@ func UpdateWithSetters(inpath, outpath string, policies []imagev1alpha1_reflect.
8888 // would be interpreted as part of the $ref path.
8989
9090 var settersSchema spec.Schema
91- var setters []* setters2.Set
92- setterToImage := make (map [string ]imageRef )
9391
9492 // collect setter defs and setters by going through all the image
9593 // policies available.
94+ result := Result {
95+ Files : make (map [string ]FileResult ),
96+ }
97+
98+ // Compilng the result needs the file, the image ref used, and the
99+ // object. Each setter will supply its own name to its callback,
100+ // which can be used to look up the image ref; the file and object
101+ // we will get from `setAll` which keeps track of those as it
102+ // iterates.
103+ imageRefs := make (map [string ]imageRef )
104+ setAllCallback := func (file , setterName string , node * yaml.RNode ) {
105+ ref , ok := imageRefs [setterName ]
106+ if ! ok {
107+ return
108+ }
109+
110+ meta , err := node .GetMeta ()
111+ if err != nil {
112+ return
113+ }
114+ oid := ObjectIdentifier {meta .GetIdentifier ()}
115+
116+ fileres , ok := result .Files [file ]
117+ if ! ok {
118+ fileres = FileResult {
119+ Objects : make (map [ObjectIdentifier ][]ImageRef ),
120+ }
121+ result .Files [file ] = fileres
122+ }
123+ objres , ok := fileres .Objects [oid ]
124+ for _ , n := range objres {
125+ if n == ref {
126+ return
127+ }
128+ }
129+ objres = append (objres , ref )
130+ fileres .Objects [oid ] = objres
131+ }
132+
96133 defs := map [string ]spec.Schema {}
97134 for _ , policy := range policies {
98135 if policy .Status .LatestImage == "" {
@@ -119,40 +156,27 @@ func UpdateWithSetters(inpath, outpath string, policies []imagev1alpha1_reflect.
119156
120157 tag := ref .Identifier ()
121158 // annoyingly, neither the library imported above, nor an
122- // alternative, I found will yield the original image name;
159+ // alternative I found, will yield the original image name;
123160 // this is an easy way to get it
124161 name := image [:len (tag )+ 1 ]
125162
126163 imageSetter := fmt .Sprintf ("%s:%s" , policy .GetNamespace (), policy .GetName ())
127164 defs [fieldmeta .SetterDefinitionPrefix + imageSetter ] = setterSchema (imageSetter , policy .Status .LatestImage )
128- setterToImage [imageSetter ] = ref
129- setters = append (setters , & setters2.Set {
130- Name : imageSetter ,
131- SettersSchema : & settersSchema ,
132- })
165+ imageRefs [imageSetter ] = ref
133166
134167 tagSetter := imageSetter + ":tag"
135-
136168 defs [fieldmeta .SetterDefinitionPrefix + tagSetter ] = setterSchema (tagSetter , tag )
137- setterToImage [tagSetter ] = ref
138- setters = append (setters , & setters2.Set {
139- Name : tagSetter ,
140- SettersSchema : & settersSchema ,
141- })
169+ imageRefs [tagSetter ] = ref
142170
143171 // Context().Name() gives the image repository _as supplied_
144172 nameSetter := imageSetter + ":name"
145- setterToImage [nameSetter ] = ref
146173 defs [fieldmeta .SetterDefinitionPrefix + nameSetter ] = setterSchema (nameSetter , name )
147- setters = append (setters , & setters2.Set {
148- Name : nameSetter ,
149- SettersSchema : & settersSchema ,
150- })
174+ imageRefs [nameSetter ] = ref
151175 }
152176
153177 settersSchema .Definitions = defs
154- setAll := & setAllRecorder {
155- setters : setters ,
178+ set := & SetAllCallback {
179+ SettersSchema : & settersSchema ,
156180 }
157181
158182 // get ready with the reader and writer
@@ -168,7 +192,7 @@ func UpdateWithSetters(inpath, outpath string, policies []imagev1alpha1_reflect.
168192 Inputs : []kio.Reader {reader },
169193 Outputs : []kio.Writer {writer },
170194 Filters : []kio.Filter {
171- setAll ,
195+ setAll ( set , setAllCallback ) ,
172196 },
173197 }
174198
@@ -177,94 +201,49 @@ func UpdateWithSetters(inpath, outpath string, policies []imagev1alpha1_reflect.
177201 if err != nil {
178202 return Result {}, err
179203 }
180- return setAll . getResult ( setterToImage ) , nil
204+ return result , nil
181205}
182206
183- type update struct {
184- file , name string
185- object * yaml.RNode
186- }
187-
188- type setAllRecorder struct {
189- setters []* setters2.Set
190- updates []update
191- }
192-
193- func (s * setAllRecorder ) getResult (nameToImage map [string ]imageRef ) Result {
194- result := Result {
195- Files : make (map [string ]FileResult ),
196- }
197- updates:
198- for _ , update := range s .updates {
199- file , ok := result .Files [update .file ]
200- if ! ok {
201- file = FileResult {
202- Objects : make (map [ObjectIdentifier ][]ImageRef ),
203- }
204- result .Files [update .file ] = file
205- }
206- objects := file .Objects
207-
208- meta , err := update .object .GetMeta ()
209- if err != nil {
210- continue updates
211- }
212- id := ObjectIdentifier {meta .GetIdentifier ()}
207+ // setAll returns a kio.Filter using the supplied SetAllCallback
208+ // (dealing with individual nodes), amd calling the given callback
209+ // whenever a field value is changed, and returning only nodes from
210+ // files with changed nodes. This is based on
211+ // [`SetAll`](https://github.com/kubernetes-sigs/kustomize/blob/kyaml/v0.10.16/kyaml/setters2/set.go#L503
212+ // from kyaml/kio.
213+ func setAll (filter * SetAllCallback , callback func (file , setterName string , node * yaml.RNode )) kio.Filter {
214+ return kio .FilterFunc (
215+ func (nodes []* yaml.RNode ) ([]* yaml.RNode , error ) {
216+ filesToUpdate := sets.String {}
217+ for i := range nodes {
218+ path , _ , err := kioutil .GetFileAnnotations (nodes [i ])
219+ if err != nil {
220+ return nil , err
221+ }
213222
214- ref , ok := nameToImage [update .name ]
215- if ! ok { // this means an update was made that wasn't recorded as being an image
216- continue updates
217- }
218- // if the name and tag of an image are both used, we don't need to record it twice
219- for _ , n := range objects [id ] {
220- if n == ref {
221- continue updates
223+ filter .Callback = func (setter , oldValue , newValue string ) {
224+ if newValue != oldValue {
225+ callback (path , setter , nodes [i ])
226+ filesToUpdate .Insert (path )
227+ }
228+ }
229+ _ , err = filter .Filter (nodes [i ])
230+ if err != nil {
231+ return nil , err
232+ }
222233 }
223- }
224- objects [id ] = append (objects [id ], ref )
225- }
226- return result
227- }
228234
229- // Filter is an implementation of kio.Filter which records each use of
230- // a setter at each object in each file, and only includes the files
231- // that were updated in the output nodes. The implementation is
232- // adapted from
233- // https://github.com/kubernetes-sigs/kustomize/blob/kyaml/v0.10.13/kyaml/setters2/set.go#L503
234- func (s * setAllRecorder ) Filter (nodes []* yaml.RNode ) ([]* yaml.RNode , error ) {
235- filesToUpdate := sets.String {}
236- for i := range nodes {
237- for _ , setter := range s .setters {
238- preCount := setter .Count
239- _ , err := setter .Filter (nodes [i ])
240- if err != nil {
241- return nil , err
242- }
243- if setter .Count > preCount {
235+ var nodesInUpdatedFiles []* yaml.RNode
236+ for i := range nodes {
244237 path , _ , err := kioutil .GetFileAnnotations (nodes [i ])
245238 if err != nil {
246239 return nil , err
247240 }
248- filesToUpdate .Insert (path )
249- s .updates = append (s .updates , update {
250- file : path ,
251- name : setter .Name ,
252- object : nodes [i ],
253- })
241+ if filesToUpdate .Has (path ) {
242+ nodesInUpdatedFiles = append (nodesInUpdatedFiles , nodes [i ])
243+ }
254244 }
255- }
256- }
257- var nodesInUpdatedFiles []* yaml.RNode
258- for i := range nodes {
259- path , _ , err := kioutil .GetFileAnnotations (nodes [i ])
260- if err != nil {
261- return nil , err
262- }
263- if filesToUpdate .Has (path ) {
264- nodesInUpdatedFiles = append (nodesInUpdatedFiles , nodes [i ])
265- }
266- }
267- return nodesInUpdatedFiles , nil
245+ return nodesInUpdatedFiles , nil
246+ })
268247}
269248
270249func setterSchema (name , value string ) spec.Schema {
0 commit comments