github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/internal/builder/writer/structured_format.go (about) 1 package writer 2 3 import ( 4 "fmt" 5 6 "github.com/buildpacks/pack/internal/style" 7 "github.com/buildpacks/pack/pkg/client" 8 9 pubbldr "github.com/buildpacks/pack/builder" 10 "github.com/buildpacks/pack/internal/builder" 11 "github.com/buildpacks/pack/internal/config" 12 "github.com/buildpacks/pack/pkg/dist" 13 "github.com/buildpacks/pack/pkg/logging" 14 ) 15 16 type InspectOutput struct { 17 SharedBuilderInfo 18 RemoteInfo *BuilderInfo `json:"remote_info" yaml:"remote_info" toml:"remote_info"` 19 LocalInfo *BuilderInfo `json:"local_info" yaml:"local_info" toml:"local_info"` 20 } 21 22 type RunImage struct { 23 Name string `json:"name" yaml:"name" toml:"name"` 24 UserConfigured bool `json:"user_configured,omitempty" yaml:"user_configured,omitempty" toml:"user_configured,omitempty"` 25 } 26 27 type Lifecycle struct { 28 builder.LifecycleInfo `yaml:"lifecycleinfo,inline"` 29 BuildpackAPIs builder.APIVersions `json:"buildpack_apis" yaml:"buildpack_apis" toml:"buildpack_apis"` 30 PlatformAPIs builder.APIVersions `json:"platform_apis" yaml:"platform_apis" toml:"platform_apis"` 31 } 32 33 type Stack struct { 34 ID string `json:"id" yaml:"id" toml:"id"` 35 Mixins []string `json:"mixins,omitempty" yaml:"mixins,omitempty" toml:"mixins,omitempty"` 36 } 37 38 type BuilderInfo struct { 39 Description string `json:"description,omitempty" yaml:"description,omitempty" toml:"description,omitempty"` 40 CreatedBy builder.CreatorMetadata `json:"created_by" yaml:"created_by" toml:"created_by"` 41 Stack *Stack `json:"stack,omitempty" yaml:"stack,omitempty" toml:"stack,omitempty"` 42 Lifecycle Lifecycle `json:"lifecycle" yaml:"lifecycle" toml:"lifecycle"` 43 RunImages []RunImage `json:"run_images" yaml:"run_images" toml:"run_images"` 44 Buildpacks []dist.ModuleInfo `json:"buildpacks" yaml:"buildpacks" toml:"buildpacks"` 45 pubbldr.DetectionOrder `json:"detection_order" yaml:"detection_order" toml:"detection_order"` 46 Extensions []dist.ModuleInfo `json:"extensions,omitempty" yaml:"extensions,omitempty" toml:"extensions,omitempty"` 47 OrderExtensions pubbldr.DetectionOrder `json:"order_extensions,omitempty" yaml:"order_extensions,omitempty" toml:"order_extensions,omitempty"` 48 } 49 50 type StructuredFormat struct { 51 MarshalFunc func(interface{}) ([]byte, error) 52 } 53 54 func (w *StructuredFormat) Print( 55 logger logging.Logger, 56 localRunImages []config.RunImage, 57 local, remote *client.BuilderInfo, 58 localErr, remoteErr error, 59 builderInfo SharedBuilderInfo, 60 ) error { 61 if localErr != nil { 62 return fmt.Errorf("preparing output for %s: %w", style.Symbol(builderInfo.Name), localErr) 63 } 64 65 if remoteErr != nil { 66 return fmt.Errorf("preparing output for %s: %w", style.Symbol(builderInfo.Name), remoteErr) 67 } 68 69 outputInfo := InspectOutput{SharedBuilderInfo: builderInfo} 70 71 if local != nil { 72 var stack *Stack 73 if local.Stack != "" { 74 stack = &Stack{ID: local.Stack} 75 } 76 77 if logger.IsVerbose() { 78 stack.Mixins = local.Mixins 79 } 80 81 outputInfo.LocalInfo = &BuilderInfo{ 82 Description: local.Description, 83 CreatedBy: local.CreatedBy, 84 Stack: stack, 85 Lifecycle: Lifecycle{ 86 LifecycleInfo: local.Lifecycle.Info, 87 BuildpackAPIs: local.Lifecycle.APIs.Buildpack, 88 PlatformAPIs: local.Lifecycle.APIs.Platform, 89 }, 90 RunImages: runImages(local.RunImages, localRunImages), 91 Buildpacks: local.Buildpacks, 92 DetectionOrder: local.Order, 93 Extensions: local.Extensions, 94 OrderExtensions: local.OrderExtensions, 95 } 96 } 97 98 if remote != nil { 99 var stack *Stack 100 if remote.Stack != "" { 101 stack = &Stack{ID: remote.Stack} 102 } 103 104 if logger.IsVerbose() { 105 stack.Mixins = remote.Mixins 106 } 107 108 outputInfo.RemoteInfo = &BuilderInfo{ 109 Description: remote.Description, 110 CreatedBy: remote.CreatedBy, 111 Stack: stack, 112 Lifecycle: Lifecycle{ 113 LifecycleInfo: remote.Lifecycle.Info, 114 BuildpackAPIs: remote.Lifecycle.APIs.Buildpack, 115 PlatformAPIs: remote.Lifecycle.APIs.Platform, 116 }, 117 RunImages: runImages(remote.RunImages, localRunImages), 118 Buildpacks: remote.Buildpacks, 119 DetectionOrder: remote.Order, 120 Extensions: remote.Extensions, 121 OrderExtensions: remote.OrderExtensions, 122 } 123 } 124 125 if outputInfo.LocalInfo == nil && outputInfo.RemoteInfo == nil { 126 return fmt.Errorf("unable to find builder %s locally or remotely", style.Symbol(builderInfo.Name)) 127 } 128 129 var ( 130 output []byte 131 err error 132 ) 133 if output, err = w.MarshalFunc(outputInfo); err != nil { 134 return fmt.Errorf("untested, unexpected failure while marshaling: %w", err) 135 } 136 137 logger.Info(string(output)) 138 139 return nil 140 } 141 142 func runImages(runImages []pubbldr.RunImageConfig, localRunImages []config.RunImage) []RunImage { 143 images := []RunImage{} 144 145 for _, i := range localRunImages { 146 for _, runImage := range runImages { 147 if i.Image == runImage.Image { 148 for _, m := range i.Mirrors { 149 images = append(images, RunImage{Name: m, UserConfigured: true}) 150 } 151 } 152 } 153 } 154 155 for _, runImage := range runImages { 156 images = append(images, RunImage{Name: runImage.Image}) 157 for _, m := range runImage.Mirrors { 158 images = append(images, RunImage{Name: m}) 159 } 160 } 161 162 return images 163 }