func (r *Reconciler) loadRawManifest(ctx context.Context, o DeclarativeObject) (map[string]string, error) {
	s, err := r.options.manifestController.ResolveManifest(ctx, o)
	if err != nil {
		return nil, err
	}
	return s, nil
}
loadRawManifest loads the raw manifest YAML from the repository
package declarative
import (
	"context"
	"errors"
	"fmt"
	"path/filepath"
	"strings"
	"k8s.io/apimachinery/pkg/api/meta"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/rest"
	recorder "k8s.io/client-go/tools/record"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
	"sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/applier"
	"sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/manifest"
	"sigs.k8s.io/kustomize/api/filesys"
	"sigs.k8s.io/kustomize/api/krusty"
)
var _ reconcile.Reconciler = &Reconciler{}
type Reconciler struct {
	prototype DeclarativeObject
	client    client.Client
	config    *rest.Config
	kubectl   kubectlClient
	metrics reconcileMetrics
	mgr     manager.Manager
	recorder      recorder.EventRecorder
	dynamicClient dynamic.Interface
	restMapper meta.RESTMapper
	options    reconcilerParams
}
type kubectlClient interface {
	applier.Applier
}
type DeclarativeObject interface {
	runtime.Object
	metav1.Object
}
var kubectl = applier.NewDirectApplier()
func (r *Reconciler) Init(mgr manager.Manager, prototype DeclarativeObject, opts ...reconcilerOption) error {
	r.prototype = prototype
	r.kubectl = kubectl
	controllerName := "addon-controller"
	r.recorder = mgr.GetEventRecorderFor(controllerName)
	r.client = mgr.GetClient()
	r.config = mgr.GetConfig()
	r.mgr = mgr
	globalObjectTracker.mgr = mgr
	d, err := dynamic.NewForConfig(r.config)
	if err != nil {
		return err
	}
	r.dynamicClient = d
	r.restMapper = mgr.GetRESTMapper()
	if err = r.applyOptions(opts...); err != nil {
		return err
	}
	if err := r.validateOptions(); err != nil {
		return err
	}
	if r.CollectMetrics() {
		if gvk, err := apiutil.GVKForObject(prototype, r.mgr.GetScheme()); err != nil {
			return err
		} else {
			r.metrics = reconcileMetricsFor(gvk)
		}
	}
	return nil
}
func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (result reconcile.Result, err error) {
	log := log.Log
	defer r.collectMetrics(request, result, err)
	instance := r.prototype.DeepCopyObject().(DeclarativeObject)
	if err = r.client.Get(ctx, request.NamespacedName, instance); err != nil {
		if apierrors.IsNotFound(err) {
			return reconcile.Result{}, nil
		}
		log.Error(err, "error reading object")
		return reconcile.Result{}, err
	}
	if r.options.status != nil {
		if err := r.options.status.Preflight(ctx, instance); err != nil {
			log.Error(err, "preflight check failed, not reconciling")
			return reconcile.Result{}, err
		}
	}
	return r.reconcileExists(ctx, request.NamespacedName, instance)
}
func (r *Reconciler) reconcileExists(ctx context.Context, name types.NamespacedName, instance DeclarativeObject) (reconcile.Result, error) {
	log := log.Log
	log.WithValues("object", name.String()).Info("reconciling")
	var fs filesys.FileSystem
	if r.IsKustomizeOptionUsed() {
		fs = filesys.MakeFsInMemory()
	}
	objects, err := r.BuildDeploymentObjectsWithFs(ctx, name, instance, fs)
	if err != nil {
		log.Error(err, "building deployment objects")
		return reconcile.Result{}, fmt.Errorf("error building deployment objects: %v", err)
	}
	log.WithValues("objects", fmt.Sprintf("%d", len(objects.Items))).Info("built deployment objects")
	if r.options.status != nil {
		isValidVersion, err := r.options.status.VersionCheck(ctx, instance, objects)
		if err != nil {
			if !isValidVersion {
				if err := r.client.Status().Update(ctx, instance); err != nil {
					return reconcile.Result{}, err
				}
				r.recorder.Event(instance, "Warning", "Failed version check", err.Error())
				log.Error(err, "Version check failed, not reconciling")
				return reconcile.Result{}, nil
			}
			log.Error(err, "Version check failed, trying to reconcile")
			return reconcile.Result{}, err
		}
	}
	defer func() {
		if r.options.status != nil {
			if err := r.options.status.Reconciled(ctx, instance, objects); err != nil {
				log.Error(err, "failed to reconcile status")
			}
		}
	}()
	objects, err = parseListKind(objects)
	if err != nil {
		log.Error(err, "Parsing list kind")
		return reconcile.Result{}, fmt.Errorf("error parsing list kind: %v", err)
	}
	err = r.injectOwnerRef(ctx, instance, objects)
	if err != nil {
		return reconcile.Result{}, err
	}
	var newItems []*manifest.Object
	for _, obj := range objects.Items {
		unstruct, err := GetObjectFromCluster(obj, r)
		if err != nil && !apierrors.IsNotFound(errors.Unwrap(err)) {
			log.WithValues("name", obj.Name).Error(err, "Unable to get resource")
		}
		if unstruct != nil {
			annotations := unstruct.GetAnnotations()
			if _, ok := annotations["addons.k8s.io/ignore"]; ok {
				log.WithValues("kind", obj.Kind).WithValues("name", obj.Name).Info("Found ignore annotation on object, " +
					"skipping object")
				continue
			}
		}
		newItems = append(newItems, obj)
	}
	objects.Items = newItems
	var manifestStr string
	m, err := objects.JSONManifest()
	if err != nil {
		log.Error(err, "creating final manifest")
		return reconcile.Result{}, fmt.Errorf("error creating manifest: %v", err)
	}
	manifestStr = m
	extraArgs := []string{"--force"}
	if r.options.prune {
		var labels []string
		for k, v := range r.options.labelMaker(ctx, instance) {
			labels = append(labels, fmt.Sprintf("%s=%s", k, v))
		}
		extraArgs = append(extraArgs, "--prune", "--selector", strings.Join(labels, ","))
	}
	ns := ""
	if !r.options.preserveNamespace {
		ns = name.Namespace
	}
	if r.CollectMetrics() {
		if errs := globalObjectTracker.addIfNotPresent(objects.Items, ns); errs != nil {
			for _, err := range errs.Errors() {
				if errors.Is(err, noRESTMapperErr{}) {
					log.WithName("declarative_reconciler").Error(err, "failed to get corresponding RESTMapper from API server")
				} else if errors.Is(err, emptyNamespaceErr{}) {
					log.WithName("declarative_reconciler").Info("Scoped object, but no namespace specified")
				} else {
					log.WithName("declarative_reconciler").Error(err, "Unknown error")
				}
			}
		}
	}
	applyOpt := applier.ApplierOptions{
		RESTConfig: r.config,
		RESTMapper: r.restMapper,
		Namespace:  ns,
		Manifest:   manifestStr,
		Validate:   r.options.validate,
		ExtraArgs:  extraArgs,
	}
	if err := r.kubectl.Apply(ctx, applyOpt); err != nil {
		log.Error(err, "applying manifest")
		return reconcile.Result{}, fmt.Errorf("error applying manifest: %v", err)
	}
	if r.options.sink != nil {
		if err := r.options.sink.Notify(ctx, instance, objects); err != nil {
			log.Error(err, "notifying sink")
			return reconcile.Result{}, err
		}
	}
	return reconcile.Result{}, nil
}
func (r *Reconciler) BuildDeploymentObjects(ctx context.Context, name types.NamespacedName, instance DeclarativeObject) (*manifest.Objects, error) {
	return r.BuildDeploymentObjectsWithFs(ctx, name, instance, nil)
}
func (r *Reconciler) BuildDeploymentObjectsWithFs(ctx context.Context, name types.NamespacedName, instance DeclarativeObject, fs filesys.FileSystem) (*manifest.Objects, error) {
	log := log.Log
	manifestFiles, err := r.loadRawManifest(ctx, instance)
	if err != nil {
		log.Error(err, "error loading raw manifest")
		return nil, err
	}
	manifestObjects := &manifest.Objects{}
	for manifestPath, manifestStr := range manifestFiles {
		for _, t := range r.options.rawManifestOperations {
			transformed, err := t(ctx, instance, manifestStr)
			if err != nil {
				log.Error(err, "error performing raw manifest operations")
				return nil, err
			}
			manifestStr = transformed
		}
		objects, err := r.parseManifest(ctx, instance, manifestStr)
		if err != nil {
			log.Error(err, "error parsing manifest")
			return nil, err
		}
		if !r.IsKustomizeOptionUsed() {
			if err := r.transformManifest(ctx, instance, objects); err != nil {
				log.Error(err, "error transforming manifest")
				return nil, err
			}
		}
		if fs != nil {
			for _, item := range objects.Items {
				json, err := item.JSON()
				if err != nil {
					log.Error(err, "error converting object to json")
					return nil, err
				}
				fs.WriteFile(string(manifestPath), json)
			}
			for _, blob := range objects.Blobs {
				fs.WriteFile(string(manifestPath), blob)
			}
		}
		manifestObjects.Path = filepath.Dir(manifestPath)
		manifestObjects.Items = append(manifestObjects.Items, objects.Items...)
		manifestObjects.Blobs = append(manifestObjects.Blobs, objects.Blobs...)
	}
	if r.IsKustomizeOptionUsed() {
		opts := krusty.MakeDefaultOptions()
		k := krusty.MakeKustomizer(opts)
		m, err := k.Run(fs, manifestObjects.Path)
		if err != nil {
			log.Error(err, "running kustomize to create final manifest")
			return nil, fmt.Errorf("error running kustomize: %v", err)
		}
		manifestYaml, err := m.AsYaml()
		if err != nil {
			log.Error(err, "creating final manifest yaml")
			return nil, fmt.Errorf("error converting kustomize output to yaml: %v", err)
		}
		objects, err := r.parseManifest(ctx, instance, string(manifestYaml))
		if err != nil {
			log.Error(err, "creating final manifest yaml")
			return nil, err
		}
		if err := r.transformManifest(ctx, instance, objects); err != nil {
			log.Error(err, "error transforming manifest")
			return nil, err
		}
		manifestObjects.Items = objects.Items
	}
	manifestObjects.Sort(DefaultObjectOrder(ctx))
	return manifestObjects, nil
}
func (r *Reconciler) parseManifest(ctx context.Context, instance DeclarativeObject, manifestStr string) (*manifest.Objects, error) {
	log := log.Log
	objects, err := manifest.ParseObjects(ctx, manifestStr)
	if err != nil {
		log.Error(err, "error parsing manifest")
		return nil, err
	}
	return objects, nil
}
func (r *Reconciler) transformManifest(ctx context.Context, instance DeclarativeObject, objects *manifest.Objects) error {
	transforms := r.options.objectTransformations
	if r.options.labelMaker != nil {
		transforms = append(transforms, AddLabels(r.options.labelMaker(ctx, instance)))
	}
	for _, t := range transforms {
		err := t(ctx, instance, objects)
		if err != nil {
			return err
		}
	}
	return nil
}