func (m *ImagePolicyMatchMapping) Map(from string) (string, error) {
	mfrom := m.From
	if mfrom == "" {
		mfrom = defaultMatch
	}
	parts := strings.Split(mfrom, defaultMatch)
	switch len(parts) {
	case 1:
		return "", errTagNotFound
	case 2:  
	default:
		return "", errTooManyTags
	}
	if parts[0] != "" {
		newFrom := strings.TrimPrefix(from, parts[0])
		if from == newFrom {
			return "", errNoMatch
		}
		from = newFrom
	}
	if parts[1] != "" {
		newFrom := strings.TrimSuffix(from, parts[1])
		if from == newFrom {
			return "", errNoMatch
		}
		from = newFrom
	}
	to := m.To
	if to == "" {
		to = defaultMatch
	}
	toT, err := template.New("").Parse(to)
	if err != nil {
		return "", err
	}
	w := &bytes.Buffer{}
	if err := toT.Execute(w, struct{ Tag string }{from}); err != nil {
		return "", err
	}
	if w.String() == m.To {
		return "", errTagNotFound
	}
	return w.String(), nil
}
Map translates the provided from string to a to string. It returns an
error if either the configured From or To value cannot be compiled.
package v1alpha1
import (
	"bytes"
	"errors"
	"strings"
	"text/template"
	"github.com/manifoldco/heighliner/internal/k8sutils"
	"k8s.io/api/core/v1"
	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const defaultMatch = "{{.Tag}}"
var defaultImagePolicyMatch = &ImagePolicyMatch{
	Name: &ImagePolicyMatchMapping{},
}
var defaultContainerRegistry = &ContainerRegistry{
	Name: "docker",
}
var (
	errTagNotFound = errors.New("no Tag template value found")
	errTooManyTags = errors.New("only one Tag template must be provided")
	errNoMatch     = errors.New("no match found for from template")
)
type ImagePolicy struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec   ImagePolicySpec   `json:"spec"`
	Status ImagePolicyStatus `json:"status"`
}
type ImagePolicyList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []ImagePolicy `json:"items"`
}
type ImagePolicySpec struct {
	Image             string             `json:"image"`
	ImagePullPolicy   *v1.PullPolicy     `json:"imagePullPolicy"`
	VersioningPolicy  v1.ObjectReference `json:"versioningPolicy"`
	Filter            ImagePolicyFilter  `json:"filter"`
	Match             *ImagePolicyMatch  `json:"match,omitempty"`
	ContainerRegistry *ContainerRegistry `json:"containerRegistry,omitempty"`
}
type ImagePolicyStatus struct {
	Releases []Release `json:"releases"`
}
type ImagePolicyMatch struct {
	Name *ImagePolicyMatchMapping `json:"name,omitempty"`
	Labels map[string]ImagePolicyMatchMapping `json:"labels,omitempty"`
}
func (m *ImagePolicyMatch) Config() (bool, bool) {
	if m == nil || (m.Name == nil && len(m.Labels) == 0) {
		m = defaultImagePolicyMatch
	}
	return m.Name != nil, len(m.Labels) > 0
}
func (m *ImagePolicyMatch) MapName(release string) (string, error) {
	if m == nil || m.Name == nil {
		m = defaultImagePolicyMatch
	}
	mapped, err := m.Name.Map(release)
	return mapped, err
}
func (m *ImagePolicyMatch) Matches(release, tag string, labels map[string]string) (bool, error) {
	if m == nil || (m.Name == nil && len(m.Labels) == 0) {
		m = defaultImagePolicyMatch
	}
	if m.Name != nil {
		mapped, err := m.Name.Map(release)
		if err != nil {
			return false, err
		}
		if mapped != tag {
			return false, nil
		}
	}
	for l, lm := range m.Labels {
		t, ok := labels[l]
		if !ok {
			return false, nil
		}
		mapped, err := lm.Map(release)
		if err != nil {
			return false, err
		}
		if mapped != t {
			return false, nil
		}
	}
	return true, nil
}
type ImagePolicyMatchMapping struct {
	From string `json:"from,omitempty"`
	To string `json:"to,omitempty"`
}