github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/acceptance/config/lifecycle_asset.go (about)

     1  //go:build acceptance
     2  // +build acceptance
     3  
     4  package config
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/Masterminds/semver"
    11  	"github.com/buildpacks/lifecycle/api"
    12  
    13  	"github.com/buildpacks/pack/internal/builder"
    14  )
    15  
    16  type LifecycleAsset struct {
    17  	path       string
    18  	descriptor builder.LifecycleDescriptor
    19  	image      string
    20  }
    21  
    22  func (a AssetManager) NewLifecycleAsset(kind ComboValue) LifecycleAsset {
    23  	return LifecycleAsset{
    24  		path:       a.LifecyclePath(kind),
    25  		descriptor: a.LifecycleDescriptor(kind),
    26  		image:      a.LifecycleImage(kind),
    27  	}
    28  }
    29  
    30  func (l *LifecycleAsset) Version() string {
    31  	return l.SemVer().String()
    32  }
    33  
    34  func (l *LifecycleAsset) SemVer() *builder.Version {
    35  	return l.descriptor.Info.Version
    36  }
    37  
    38  func (l *LifecycleAsset) Identifier() string {
    39  	if l.HasLocation() {
    40  		return l.path
    41  	} else {
    42  		return l.Version()
    43  	}
    44  }
    45  
    46  func (l *LifecycleAsset) HasLocation() bool {
    47  	return l.path != ""
    48  }
    49  
    50  func (l *LifecycleAsset) EscapedPath() string {
    51  	return strings.ReplaceAll(l.path, `\`, `\\`)
    52  }
    53  
    54  func (l *LifecycleAsset) Image() string {
    55  	return l.image
    56  }
    57  
    58  func earliestVersion(versions []*api.Version) *api.Version {
    59  	var earliest *api.Version
    60  	for _, version := range versions {
    61  		switch {
    62  		case version == nil:
    63  			continue
    64  		case earliest == nil:
    65  			earliest = version
    66  		case earliest.Compare(version) > 0:
    67  			earliest = version
    68  		}
    69  	}
    70  	return earliest
    71  }
    72  
    73  func latestVersion(versions []*api.Version) *api.Version {
    74  	var latest *api.Version
    75  	for _, version := range versions {
    76  		switch {
    77  		case version == nil:
    78  			continue
    79  		case latest == nil:
    80  			latest = version
    81  		case latest.Compare(version) < 0:
    82  			latest = version
    83  		}
    84  	}
    85  	return latest
    86  }
    87  func (l *LifecycleAsset) EarliestBuildpackAPIVersion() string {
    88  	return earliestVersion(l.descriptor.APIs.Buildpack.Supported).String()
    89  }
    90  
    91  func (l *LifecycleAsset) EarliestPlatformAPIVersion() string {
    92  	return earliestVersion(l.descriptor.APIs.Platform.Supported).String()
    93  }
    94  
    95  func (l *LifecycleAsset) LatestPlatformAPIVersion() string {
    96  	return latestVersion(l.descriptor.APIs.Platform.Supported).String()
    97  }
    98  
    99  func (l *LifecycleAsset) OutputForAPIs() (deprecatedBuildpackAPIs, supportedBuildpackAPIs, deprecatedPlatformAPIs, supportedPlatformAPIs string) {
   100  	stringify := func(apiSet builder.APISet) string {
   101  		versions := apiSet.AsStrings()
   102  		if len(versions) == 0 {
   103  			return "(none)"
   104  		}
   105  		return strings.Join(versions, ", ")
   106  	}
   107  
   108  	return stringify(l.descriptor.APIs.Buildpack.Deprecated),
   109  		stringify(l.descriptor.APIs.Buildpack.Supported),
   110  		stringify(l.descriptor.APIs.Platform.Deprecated),
   111  		stringify(l.descriptor.APIs.Platform.Supported)
   112  }
   113  
   114  func (l *LifecycleAsset) TOMLOutputForAPIs() (deprecatedBuildpacksAPIs,
   115  	supportedBuildpacksAPIs,
   116  	deprectatedPlatformAPIs,
   117  	supportedPlatformAPIS string,
   118  ) {
   119  	stringify := func(apiSet builder.APISet) string {
   120  		if len(apiSet) < 1 || apiSet == nil {
   121  			return "[]"
   122  		}
   123  
   124  		var quotedAPIs []string
   125  		for _, a := range apiSet {
   126  			quotedAPIs = append(quotedAPIs, fmt.Sprintf("%q", a))
   127  		}
   128  
   129  		return fmt.Sprintf("[%s]", strings.Join(quotedAPIs, ", "))
   130  	}
   131  
   132  	return stringify(l.descriptor.APIs.Buildpack.Deprecated),
   133  		stringify(l.descriptor.APIs.Buildpack.Supported),
   134  		stringify(l.descriptor.APIs.Platform.Deprecated),
   135  		stringify(l.descriptor.APIs.Platform.Supported)
   136  }
   137  
   138  func (l *LifecycleAsset) YAMLOutputForAPIs(baseIndentationWidth int) (deprecatedBuildpacksAPIs,
   139  	supportedBuildpacksAPIs,
   140  	deprectatedPlatformAPIs,
   141  	supportedPlatformAPIS string,
   142  ) {
   143  	stringify := func(apiSet builder.APISet, baseIndentationWidth int) string {
   144  		if len(apiSet) < 1 || apiSet == nil {
   145  			return "[]"
   146  		}
   147  
   148  		apiIndentation := strings.Repeat(" ", baseIndentationWidth+2)
   149  
   150  		var quotedAPIs []string
   151  		for _, a := range apiSet {
   152  			quotedAPIs = append(quotedAPIs, fmt.Sprintf(`%s- %q`, apiIndentation, a))
   153  		}
   154  
   155  		return fmt.Sprintf(`
   156  %s`, strings.Join(quotedAPIs, "\n"))
   157  	}
   158  
   159  	return stringify(l.descriptor.APIs.Buildpack.Deprecated, baseIndentationWidth),
   160  		stringify(l.descriptor.APIs.Buildpack.Supported, baseIndentationWidth),
   161  		stringify(l.descriptor.APIs.Platform.Deprecated, baseIndentationWidth),
   162  		stringify(l.descriptor.APIs.Platform.Supported, baseIndentationWidth)
   163  }
   164  
   165  func (l *LifecycleAsset) JSONOutputForAPIs(baseIndentationWidth int) (
   166  	deprecatedBuildpacksAPIs,
   167  	supportedBuildpacksAPIs,
   168  	deprectatedPlatformAPIs,
   169  	supportedPlatformAPIS string,
   170  ) {
   171  	stringify := func(apiSet builder.APISet, baseIndentationWidth int) string {
   172  		if len(apiSet) < 1 {
   173  			if apiSet == nil {
   174  				return "null"
   175  			}
   176  			return "[]"
   177  		}
   178  
   179  		apiIndentation := strings.Repeat(" ", baseIndentationWidth+2)
   180  
   181  		var quotedAPIs []string
   182  		for _, a := range apiSet {
   183  			quotedAPIs = append(quotedAPIs, fmt.Sprintf(`%s%q`, apiIndentation, a))
   184  		}
   185  
   186  		lineEndSeparator := `,
   187  `
   188  
   189  		return fmt.Sprintf(`[
   190  %s
   191  %s]`, strings.Join(quotedAPIs, lineEndSeparator), strings.Repeat(" ", baseIndentationWidth))
   192  	}
   193  
   194  	return stringify(l.descriptor.APIs.Buildpack.Deprecated, baseIndentationWidth),
   195  		stringify(l.descriptor.APIs.Buildpack.Supported, baseIndentationWidth),
   196  		stringify(l.descriptor.APIs.Platform.Deprecated, baseIndentationWidth),
   197  		stringify(l.descriptor.APIs.Platform.Supported, baseIndentationWidth)
   198  }
   199  
   200  type LifecycleFeature int
   201  
   202  const (
   203  	CreationTime = iota
   204  	BuildImageExtensions
   205  	RunImageExtensions
   206  )
   207  
   208  type LifecycleAssetSupported func(l *LifecycleAsset) bool
   209  
   210  func supportsPlatformAPI(version string) LifecycleAssetSupported {
   211  	return func(i *LifecycleAsset) bool {
   212  		for _, platformAPI := range i.descriptor.APIs.Platform.Supported {
   213  			if platformAPI.AtLeast(version) {
   214  				return true
   215  			}
   216  		}
   217  		for _, platformAPI := range i.descriptor.APIs.Platform.Deprecated {
   218  			if platformAPI.AtLeast(version) {
   219  				return true
   220  			}
   221  		}
   222  		return false
   223  	}
   224  }
   225  
   226  var lifecycleFeatureTests = map[LifecycleFeature]LifecycleAssetSupported{
   227  	CreationTime:         supportsPlatformAPI("0.9"),
   228  	BuildImageExtensions: supportsPlatformAPI("0.10"),
   229  	RunImageExtensions:   supportsPlatformAPI("0.12"),
   230  }
   231  
   232  func (l *LifecycleAsset) SupportsFeature(f LifecycleFeature) bool {
   233  	return lifecycleFeatureTests[f](l)
   234  }
   235  
   236  func (l *LifecycleAsset) atLeast074() bool {
   237  	return !l.SemVer().LessThan(semver.MustParse("0.7.4"))
   238  }