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