github.com/paketoio/libpak@v1.3.1/binding.go (about) 1 /* 2 * Copyright 2018-2020 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libpak 18 19 import ( 20 "fmt" 21 "strings" 22 23 "github.com/buildpacks/libcnb" 24 ) 25 26 // BindingResolver provides functionality for resolving a binding given a collection of constraints. 27 type BindingResolver struct { 28 29 // Bindings are the bindings to resolve against. 30 Bindings libcnb.Bindings 31 } 32 33 // BindingConstraint is the collection of constraints to use during resolution. 34 type BindingConstraint struct { 35 36 // Name is the name of the binding. 37 Name string 38 39 // Kind is the kind of the binding. 40 Kind string 41 42 // Provider is the provider of the binding. 43 Provider string 44 45 // Tags are the tags of the binding. The contents of Tags must be a strict subset of the binding's tags. 46 Tags []string 47 } 48 49 // Resolve returns the matching binding within the collection of Bindings. The candidate set is filtered by the 50 // constraints. 51 func (b *BindingResolver) Resolve(constraint BindingConstraint) (libcnb.Binding, bool, error) { 52 var m []libcnb.Binding 53 for name, binding := range b.Bindings { 54 if b.matches(name, binding, constraint) { 55 m = append(m, binding) 56 } 57 } 58 59 if len(m) < 1 { 60 return libcnb.Binding{}, false, nil 61 } else if len(m) > 1 { 62 return libcnb.Binding{}, false, fmt.Errorf("multiple bindings found for %+v in %+v", constraint, b.Bindings) 63 } 64 65 return m[0], true, nil 66 } 67 68 func (BindingResolver) contains(candidates []string, value string) bool { 69 for _, c := range candidates { 70 if c == value { 71 return true 72 } 73 } 74 75 return false 76 } 77 78 func (b BindingResolver) matches(name string, binding libcnb.Binding, constraint BindingConstraint) bool { 79 if constraint.Name != "" && constraint.Name != name { 80 return false 81 } 82 83 if constraint.Kind != "" && constraint.Kind != binding.Metadata[libcnb.BindingKind] { 84 return false 85 } 86 87 if constraint.Provider != "" && constraint.Provider != binding.Metadata[libcnb.BindingProvider] { 88 return false 89 } 90 91 tags := strings.Split(binding.Metadata[libcnb.BindingTags], "\n") 92 for _, t := range constraint.Tags { 93 if !b.contains(tags, t) { 94 return false 95 } 96 } 97 98 return true 99 }