github.com/paketoio/libpak@v1.3.1/buildpack_plan.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 "reflect" 22 "strings" 23 24 "github.com/buildpacks/libcnb" 25 "github.com/imdario/mergo" 26 ) 27 28 // PlanEntryResolver provides functionality for resolving a Buildpack Plan Entry given a name. 29 type PlanEntryResolver struct { 30 31 // Plan is the BuildpackPlan to resolve against. 32 Plan libcnb.BuildpackPlan 33 } 34 35 // MergeFunc takes two BuildpackPlanEntry's and returns a merged entry. 36 type MergeFunc func(a, b libcnb.BuildpackPlanEntry) (libcnb.BuildpackPlanEntry, error) 37 38 // ResolveWithMerge returns a single BuildpackPlanEntry that is a merged version of all entries that have a given name. 39 // A merge function is used to describe how two entries are merged together. 40 func (p *PlanEntryResolver) ResolveWithMerge(name string, f MergeFunc) (libcnb.BuildpackPlanEntry, bool, error) { 41 m := libcnb.BuildpackPlanEntry{} 42 43 var err error 44 for _, e := range p.Plan.Entries { 45 if e.Name == name { 46 if m, err = f(m, e); err != nil { 47 return libcnb.BuildpackPlanEntry{}, false, fmt.Errorf("error merging %+v and %+v: %w", m, e, err) 48 } 49 } 50 } 51 52 if reflect.DeepEqual(m, libcnb.BuildpackPlanEntry{}) { 53 return libcnb.BuildpackPlanEntry{}, false, nil 54 } 55 56 return m, true, nil 57 } 58 59 // ShallowMerge merges two BuildpackPlanEntry's together. Declared versions are combined with a comma delimiter and 60 // metadata is combined with the values for b taking priority over the values of a when the keys are duplicated. 61 func ShallowMerge(a, b libcnb.BuildpackPlanEntry) (libcnb.BuildpackPlanEntry, error) { 62 var v []string 63 if a.Version != "" { 64 v = append(v, a.Version) 65 } 66 if b.Version != "" { 67 v = append(v, b.Version) 68 } 69 70 if err := mergo.Merge(&b, a); err != nil { 71 return libcnb.BuildpackPlanEntry{}, fmt.Errorf("unable to merge %+v and %+v: %w", a, b, err) 72 } 73 74 b.Version = strings.Join(v, ",") 75 return b, nil 76 } 77 78 // Resolve calls ResolveWithMerge function passing in the ShallowMerge function as the merge strategy. 79 func (p *PlanEntryResolver) Resolve(name string) (libcnb.BuildpackPlanEntry, bool, error) { 80 return p.ResolveWithMerge(name, ShallowMerge) 81 }