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  }