github.com/quay/claircore@v1.5.28/linux/coalescer.go (about) 1 package linux 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/quay/claircore" 8 "github.com/quay/claircore/indexer" 9 ) 10 11 type Coalescer struct { 12 // the IndexReport this Coalescer is working on 13 ir *claircore.IndexReport 14 } 15 16 // NewCoalescer is a constructor for a Coalescer 17 func NewCoalescer() *Coalescer { 18 return &Coalescer{ 19 ir: &claircore.IndexReport{ 20 // we will only fill these fields 21 Environments: map[string][]*claircore.Environment{}, 22 Packages: map[string]*claircore.Package{}, 23 Distributions: map[string]*claircore.Distribution{}, 24 Repositories: map[string]*claircore.Repository{}, 25 }, 26 } 27 } 28 29 // Coalesce coalesces artifacts found in layers and creates an IndexReport with 30 // the final package details found in the image. This method blocks and when its finished 31 // the c.ir field will hold the final IndexReport 32 func (c *Coalescer) Coalesce(ctx context.Context, layerArtifacts []*indexer.LayerArtifacts) (*claircore.IndexReport, error) { 33 distSearcher := NewDistSearcher(layerArtifacts) 34 packageSearcher := NewPackageSearcher(layerArtifacts) 35 36 // get all dists the seacher knows about 37 dists := distSearcher.Dists() 38 for _, dist := range dists { 39 c.ir.Distributions[dist.ID] = dist 40 } 41 42 // walk layers backwards, grouping packages by package databases the first time we see them. 43 // at the end of this loop we have searched all layers for the newest occurence of a 44 // package database. 45 dbs := make(map[string][]*claircore.Package) 46 for i := len(layerArtifacts) - 1; i >= 0; i-- { 47 artifacts := layerArtifacts[i] 48 if len(artifacts.Pkgs) == 0 { 49 continue 50 } 51 52 tmp := make(map[string][]*claircore.Package) 53 for _, pkg := range artifacts.Pkgs { 54 if _, ok := dbs[pkg.PackageDB]; !ok { 55 tmp[pkg.PackageDB] = append(tmp[pkg.PackageDB], pkg) 56 } 57 } 58 for db, pkgs := range tmp { 59 dbs[db] = pkgs 60 } 61 } 62 63 for db, packages := range dbs { 64 for _, pkg := range packages { 65 // create our environment 66 env := &claircore.Environment{} 67 68 // get the digest and index of the layer this pkg was introduced in. 69 introDigest, introIndex, err := packageSearcher.Search(pkg) 70 if err != nil { 71 return nil, fmt.Errorf("search for package introduction info failed: %v", err) 72 } 73 74 // get the distribution associated with ths layer index 75 dist, err := distSearcher.Search(introIndex) 76 if err != nil { 77 return nil, fmt.Errorf("search for distribution to tag package failed: %v", err) 78 } 79 80 // pack env 81 if dist != nil { 82 env.DistributionID = dist.ID 83 } 84 env.IntroducedIn = *introDigest 85 env.PackageDB = db 86 87 // pack ir 88 c.ir.Packages[pkg.ID] = pkg 89 c.ir.Environments[pkg.ID] = append(c.ir.Environments[pkg.ID], env) 90 } 91 } 92 93 return c.ir, nil 94 }