Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wildcard support for creation in ReplacementTransformer #4886

Merged
merged 8 commits into from
Dec 6, 2022
69 changes: 22 additions & 47 deletions api/filters/replacement/replacement.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,63 +179,38 @@ func rejectId(rejects []*types.Selector, id *resid.ResId) bool {

func copyValueToTarget(target *yaml.RNode, value *yaml.RNode, selector *types.TargetSelector) error {
for _, fp := range selector.FieldPaths {
mutator := updateMatchingFields
createKind := yaml.Kind(0) // do not create
if selector.Options != nil && selector.Options.Create {
mutator = createOrUpdateOneField
createKind = value.YNode().Kind
}
if err := mutator(target, value, selector.Options, fp); err != nil {
return err
targetFieldList, err := target.Pipe(&yaml.PathMatcher{
Path: kyaml_utils.SmarterPathSplitter(fp, "."),
Create: createKind})
if err != nil {
return errors.WrapPrefixf(err, fieldRetrievalError(fp, createKind != 0))
}
targetFields, err := targetFieldList.Elements()
if err != nil {
return errors.WrapPrefixf(err, fieldRetrievalError(fp, createKind != 0))
}
if len(targetFields) == 0 {
return errors.Errorf(fieldRetrievalError(fp, createKind != 0))
}
}
return nil
}

// updateMatchingFields updates all fields in target that match the given field path.
// If the field path does not already exist in the target, an error is returned.
func updateMatchingFields(target *yaml.RNode, value *yaml.RNode, opts *types.FieldOptions, fp string) error {
fieldPath := kyaml_utils.SmarterPathSplitter(fp, ".")
// may return multiple fields, always wrapped in a sequence node
foundFieldSequence, lookupErr := target.Pipe(&yaml.PathMatcher{Path: fieldPath})
if lookupErr != nil {
return fmt.Errorf("error finding field in replacement target: %w", lookupErr)
}
targetFields, err := foundFieldSequence.Elements()
if err != nil {
return fmt.Errorf("error fetching elements in replacement target: %w", err)
}
if len(targetFields) == 0 {
return errors.Errorf("unable to find field %s in replacement target", fp)
}

for _, t := range targetFields {
if err := setFieldValue(opts, t, value); err != nil {
return err
for _, t := range targetFields {
if err := setFieldValue(selector.Options, t, value); err != nil {
return err
}
}
}
return nil
}

// createOrUpdateOneField updates the field in the target that matches the given field path.
// If the field path does not already exist in the target, it is created.
// Wildcard matching is not supported, nor is creating intermediate list nodes.
func createOrUpdateOneField(target *yaml.RNode, value *yaml.RNode, opts *types.FieldOptions, fp string) error {
fieldPath := kyaml_utils.SmarterPathSplitter(fp, ".")
for _, f := range fieldPath {
if f == "*" {
return fmt.Errorf("cannot support create option in a multi-value target")
}
func fieldRetrievalError(fieldPath string, isCreate bool) string {
if isCreate {
return "unable to find or create field " + fieldPath + " in replacement target"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit: suggest quoting the fieldPath, since it's a user input value

}
createdField, createErr := target.Pipe(yaml.LookupCreate(value.YNode().Kind, fieldPath...))
if createErr != nil {
return fmt.Errorf("error creating replacement node: %w", createErr)
}
if createdField == nil {
return errors.Errorf("unable to find or create field %s in replacement target", fp)
}
if err := setFieldValue(opts, createdField, value); err != nil {
return errors.WrapPrefixf(err, "unable to set field %s in replacement target", fp)
}
return nil
return "unable to find field " + fieldPath + " in replacement target"
}

func setFieldValue(options *types.FieldOptions, targetField *yaml.RNode, value *yaml.RNode) error {
Expand Down