func ReadableObjectName(cr *v1alpha1.Flux, object runtime.Object) string {
	return fmt.Sprintf("flux instance '%s': %s (hash: %s)",
		cr.Name, ObjectName(object), GetObjectHash(object))
}
Return a human readable string representing the object.
package utils
import (
	"context"
	"errors"
	"fmt"
	"github.com/cnf/structhash"
	"github.com/google/go-github/github"
	"github.com/justinbarrick/flux-operator/pkg/apis/flux/v1alpha1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"os"
	"strconv"
	"strings"
)
const (
	FLUX_LABEL          = "flux.codesink.net.flux"
	FluxcloudImage      = "justinbarrick/fluxcloud"
	FluxcloudVersion    = "v0.3.4"
	FluxOperatorImage   = "justinbarrick/flux-operator"
	FluxImage           = "quay.io/weaveworks/flux"
	FluxVersion         = "1.8.1"
	HelmOperatorImage   = "quay.io/weaveworks/helm-operator"
	HelmOperatorVersion = "0.4.0"
	MemcachedImage      = "memcached"
	MemcachedVersion    = "1.4.36-alpine"
	TillerImage         = "gcr.io/kubernetes-helm/tiller"
	TillerVersion       = "v2.9.1"
)
func BoolEnv(name string) bool {
	val, _ := strconv.ParseBool(os.Getenv(name))
	return val
}
func FluxNamespace(cr *v1alpha1.Flux) string {
	if cr.ObjectMeta.Namespace == "" {
		if cr.Spec.Namespace == "" {
			return "default"
		} else {
			return cr.Spec.Namespace
		}
	} else {
		return cr.ObjectMeta.Namespace
	}
}
func Getenv(name, value string) string {
	ret := os.Getenv(name)
	if ret == "" {
		return value
	}
	return ret
}
func NewObjectMeta(cr *v1alpha1.Flux, name string) metav1.ObjectMeta {
	if name == "" {
		name = fmt.Sprintf("flux-%s", cr.Name)
	}
	return metav1.ObjectMeta{
		Name:      name,
		Namespace: FluxNamespace(cr),
		OwnerReferences: []metav1.OwnerReference{
			*metav1.NewControllerRef(cr, schema.GroupVersionKind{
				Group:   v1alpha1.SchemeGroupVersion.Group,
				Version: v1alpha1.SchemeGroupVersion.Version,
				Kind:    "Flux",
			}),
		},
	}
}
func FluxLabels(cr *v1alpha1.Flux) map[string]string {
	label := cr.ObjectMeta.Name
	if cr.ObjectMeta.Namespace != "" {
		label = fmt.Sprintf("%s-%s", cr.ObjectMeta.Namespace, label)
	}
	return map[string]string{
		FLUX_LABEL: label,
	}
}
func ListOptionsForFlux(cr *v1alpha1.Flux) *metav1.ListOptions {
	return &metav1.ListOptions{LabelSelector: labels.SelectorFromSet(FluxLabels(cr)).String()}
}
func OwnedByFlux(cr *v1alpha1.Flux, obj runtime.Object) bool {
	objectMeta, err := meta.Accessor(obj)
	if err != nil {
		fmt.Println(err)
	}
	labels := objectMeta.GetLabels()
	if labels == nil {
		return false
	}
	for k, v := range FluxLabels(cr) {
		if labels[k] != v {
			return false
		}
	}
	return true
}
func SetObjectOwner(cr *v1alpha1.Flux, obj runtime.Object) {
	objectMeta, err := meta.Accessor(obj)
	if err != nil {
		fmt.Println(err)
		return
	}
	labels := objectMeta.GetLabels()
	if labels == nil {
		labels = map[string]string{}
	}
	for k, v := range FluxLabels(cr) {
		labels[k] = v
	}
	objectMeta.SetLabels(labels)
}
func GetObjectHash(obj runtime.Object) string {
	objectMeta, _ := meta.Accessor(obj)
	annotations := objectMeta.GetAnnotations()
	if annotations == nil {
		annotations = map[string]string{}
	}
	return annotations["flux.codesink.net.hash"]
}
func SetObjectHash(obj runtime.Object) {
	objectMeta, err := meta.Accessor(obj)
	if err != nil {
		fmt.Println(err)
	}
	annotations := objectMeta.GetAnnotations()
	if annotations == nil {
		annotations = map[string]string{}
	}
	annotations["flux.codesink.net.hash"] = HashObject(obj)
	objectMeta.SetAnnotations(annotations)
}
func ClearObjectHash(obj runtime.Object) {
	objectMeta, _ := meta.Accessor(obj)
	annotations := objectMeta.GetAnnotations()
	if annotations == nil {
		return
	}
	delete(annotations, "flux.codesink.net.hash")
	objectMeta.SetAnnotations(annotations)
}
func HashObject(obj runtime.Object) string {
	copied := obj.DeepCopyObject()
	objectMeta, _ := meta.Accessor(copied)
	ownerReferences := objectMeta.GetOwnerReferences()
	if len(ownerReferences) > 0 {
		ownerReferences[0].UID = ""
	}
	objectMeta.SetOwnerReferences(ownerReferences)
	return fmt.Sprintf("%x", structhash.Sha1(copied, 1))
}
func ObjectName(object runtime.Object) string {
	objectMeta, err := meta.Accessor(object)
	if err != nil {
		return err.Error()
	}
	return fmt.Sprintf("%s:%s/%s", objectMeta.GetNamespace(),
		object.GetObjectKind().GroupVersionKind().Kind,
		objectMeta.GetName())
}