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 }