func()

in pkg/options/patchtmpl/patch.go [179:283]


func (a *applier) makePatches(ptObjs, objs []*unstructured.Unstructured, opts options.JSONOptions) ([]*parsedPatch, []*unstructured.Unstructured, error) {
	// First parse the objects back into go-objects.
	var pts []*bundle.PatchTemplate
	for _, o := range ptObjs {
		pto := &bundle.PatchTemplate{}
		err := converter.FromUnstructured(o).ToObject(pto)
		if err != nil {
			return nil, nil, fmt.Errorf("while converting object %v to PatchTemplate: %v", pto, err)
		}
		pts = append(pts, pto)
	}

	if opts == nil {
		opts = options.JSONOptions{}
	}

	// Next, de-templatize the templates.
	var patches []*parsedPatch
	for j, pto := range pts {
		patchType := bundle.PatchType(pto.PatchType)
		switch patchType {
		case bundle.StrategicMergePatch, bundle.JSONPatch:
			// known types

		case "":
			// use default
			patchType = bundle.StrategicMergePatch

		default:
			return nil, nil, fmt.Errorf("bad patch type: %s", patchType)
		}

		useSafeYAMLTemplater := internal.HasSafeYAMLAnnotation(pto.ObjectMeta)
		tmpl, err := internal.NewTemplater(fmt.Sprintf("patch-tmpl-%d", j), pto.Template, patchFuncs, useSafeYAMLTemplater)
		if err != nil {
			return nil, nil, fmt.Errorf("parsing patch template %d, %s: %v", j, pto.Template, err)
		}
		tmpl = tmpl.Option(a.templateOpts...)

		newOpts := opts
		if pto.OptionsSchema != nil {
			newOpts, err = openapi.ApplyDefaults(opts, pto.OptionsSchema)
			if err != nil {
				return nil, nil, fmt.Errorf("applying schema defaults for patch template %d, %s: %v", j, pto.Template, err)
			}
		}

		// Detemplatize the patch
		var buf bytes.Buffer
		err = tmpl.Execute(&buf, newOpts)
		if err != nil {
			return nil, nil, fmt.Errorf("while applying options to patch template %d: %v", j, err)
		}

		// Convert the patch into a JSONMap to prepare for Strategic Merge Patch.
		by := buf.Bytes()
		jsonMap := make(map[string]interface{})
		err = converter.FromYAML(by).ToObject(&jsonMap)
		if err != nil {
			return nil, nil, fmt.Errorf("while converting patch template %d: %v", j, err)
		}

		// Neither Kind nor APIVersion are allowed as patchable fields in a
		// PatchTemplate -- we don't want to change the schema of the objects we're
		// patching. So, instead remove them from the PatchTemplate and add them as
		// an additional selector parameter (which supports the previous behavior).
		pKind := ""
		pAPIVersion := ""
		if jsonMap["kind"] != nil {
			var ok bool
			pKind, ok = jsonMap["kind"].(string)
			if !ok {
				return nil, nil, fmt.Errorf("found non-string type %T for Kind field for patch %s", jsonMap["kind"], string(by))
			}
			delete(jsonMap, "kind")
		}
		if jsonMap["apiVersion"] != nil {
			var ok bool
			pAPIVersion, ok = jsonMap["apiVersion"].(string)
			if !ok {
				return nil, nil, fmt.Errorf("found a non-string APIVersion field for patch %s", string(by))
			}
			delete(jsonMap, "apiVersion")
		}

		selector := pto.Selector
		if pKind != "" {
			if selector == nil {
				selector = &bundle.ObjectSelector{}
			}
			if pAPIVersion != "" {
				pKind = pAPIVersion + "," + pKind
			}
			selector.Kinds = append(selector.Kinds, pKind)
		}

		patches = append(patches, &parsedPatch{
			raw:       by,
			jsonMap:   jsonMap,
			selector:  selector,
			patchType: patchType,
		})
	}
	return patches, objs, nil
}