forked from buildpacks/lifecycle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanalyzer.go
128 lines (110 loc) · 3.5 KB
/
analyzer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package lifecycle
import (
"github.com/buildpacks/imgutil"
"github.com/pkg/errors"
"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/buildpack"
"github.com/buildpacks/lifecycle/image"
"github.com/buildpacks/lifecycle/internal/layer"
"github.com/buildpacks/lifecycle/platform"
)
type Platform interface {
API() *api.Version
}
type Analyzer struct {
PreviousImage imgutil.Image
RunImage imgutil.Image
Logger Logger
Platform Platform
SBOMRestorer layer.SBOMRestorer
// Platform API < 0.7
Buildpacks []buildpack.GroupBuildpack
Cache Cache
LayerMetadataRestorer layer.MetadataRestorer
}
// Analyze fetches the layers metadata from the previous image and writes analyzed.toml.
func (a *Analyzer) Analyze() (platform.AnalyzedMetadata, error) {
var (
appMeta platform.LayersMetadata
cacheMeta platform.CacheMetadata
previousImageID *platform.ImageIdentifier
runImageID *platform.ImageIdentifier
err error
)
if a.PreviousImage != nil { // Previous image is optional in Platform API >= 0.7
previousImageID, err = a.getImageIdentifier(a.PreviousImage)
if err != nil {
return platform.AnalyzedMetadata{}, errors.Wrap(err, "retrieving image identifier")
}
// continue even if the label cannot be decoded
if err := image.DecodeLabel(a.PreviousImage, platform.LayerMetadataLabel, &appMeta); err != nil {
appMeta = platform.LayersMetadata{}
}
if err := a.SBOMRestorer.RestoreFromPrevious(a.PreviousImage, bomSHA(appMeta)); err != nil {
return platform.AnalyzedMetadata{}, errors.Wrap(err, "retrieving launch SBOM layer")
}
} else {
appMeta = platform.LayersMetadata{}
}
if a.RunImage != nil {
runImageID, err = a.getImageIdentifier(a.RunImage)
if err != nil {
return platform.AnalyzedMetadata{}, errors.Wrap(err, "retrieving image identifier")
}
}
if a.restoresLayerMetadata() {
cacheMeta, err = retrieveCacheMetadata(a.Cache, a.Logger)
if err != nil {
return platform.AnalyzedMetadata{}, err
}
useShaFiles := true
if err := a.LayerMetadataRestorer.Restore(a.Buildpacks, appMeta, cacheMeta, layer.NewSHAStore(useShaFiles)); err != nil {
return platform.AnalyzedMetadata{}, err
}
}
return platform.AnalyzedMetadata{
PreviousImage: previousImageID,
RunImage: runImageID,
Metadata: appMeta,
}, nil
}
func (a *Analyzer) restoresLayerMetadata() bool {
return a.Platform.API().LessThan("0.7")
}
func (a *Analyzer) getImageIdentifier(image imgutil.Image) (*platform.ImageIdentifier, error) {
if !image.Found() {
a.Logger.Infof("Previous image with name %q not found", image.Name())
return nil, nil
}
identifier, err := image.Identifier()
if err != nil {
return nil, err
}
a.Logger.Debugf("Analyzing image %q", identifier.String())
return &platform.ImageIdentifier{
Reference: identifier.String(),
}, nil
}
func bomSHA(appMeta platform.LayersMetadata) string {
if appMeta.BOM == nil {
return ""
}
return appMeta.BOM.SHA
}
func retrieveCacheMetadata(cache Cache, logger Logger) (platform.CacheMetadata, error) {
// Create empty cache metadata in case a usable cache is not provided.
var cacheMeta platform.CacheMetadata
if cache != nil {
var err error
if !cache.Exists() {
logger.Info("Layer cache not found")
}
cacheMeta, err = cache.RetrieveMetadata()
if err != nil {
return cacheMeta, errors.Wrap(err, "retrieving cache metadata")
}
} else {
logger.Debug("Usable cache not provided, using empty cache metadata")
}
return cacheMeta, nil
}