github.com/quay/claircore@v1.5.28/indexer/ecosystem.go (about)

     1  package indexer
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/quay/zlog"
     7  )
     8  
     9  // Ecosystems group together scanners and a Coalescer which are commonly used
    10  // together.
    11  //
    12  // A typical ecosystem is "dpkg" which will use the "dpkg" package indexer, the
    13  // "os-release" distribution scanner and the "apt" repository scanner.
    14  //
    15  // A Controller will scan layers with all scanners present in its configured
    16  // ecosystems.
    17  type Ecosystem struct {
    18  	PackageScanners      func(ctx context.Context) ([]PackageScanner, error)
    19  	DistributionScanners func(ctx context.Context) ([]DistributionScanner, error)
    20  	RepositoryScanners   func(ctx context.Context) ([]RepositoryScanner, error)
    21  	FileScanners         func(ctx context.Context) ([]FileScanner, error)
    22  	Coalescer            func(ctx context.Context) (Coalescer, error)
    23  	Name                 string
    24  }
    25  
    26  // EcosystemsToScanners extracts and dedupes multiple ecosystems and returns
    27  // their discrete scanners.
    28  func EcosystemsToScanners(ctx context.Context, ecosystems []*Ecosystem) ([]PackageScanner, []DistributionScanner, []RepositoryScanner, []FileScanner, error) {
    29  	ctx = zlog.ContextWithValues(ctx, "component", "indexer/EcosystemsToScanners")
    30  	ps := []PackageScanner{}
    31  	ds := []DistributionScanner{}
    32  	rs := []RepositoryScanner{}
    33  	fis := []FileScanner{}
    34  	seen := struct{ pkg, dist, repo, file map[string]struct{} }{
    35  		make(map[string]struct{}),
    36  		make(map[string]struct{}),
    37  		make(map[string]struct{}),
    38  		make(map[string]struct{}),
    39  	}
    40  
    41  	for _, ecosystem := range ecosystems {
    42  		pscanners, err := ecosystem.PackageScanners(ctx)
    43  		if err != nil {
    44  			return nil, nil, nil, nil, err
    45  		}
    46  		for _, s := range pscanners {
    47  			n := s.Name()
    48  			if _, ok := seen.pkg[n]; ok {
    49  				continue
    50  			}
    51  			seen.pkg[n] = struct{}{}
    52  			ps = append(ps, s)
    53  		}
    54  
    55  		dscanners, err := ecosystem.DistributionScanners(ctx)
    56  		if err != nil {
    57  			return nil, nil, nil, nil, err
    58  		}
    59  		for _, s := range dscanners {
    60  			n := s.Name()
    61  			if _, ok := seen.dist[n]; ok {
    62  				continue
    63  			}
    64  			seen.dist[n] = struct{}{}
    65  			ds = append(ds, s)
    66  		}
    67  
    68  		rscanners, err := ecosystem.RepositoryScanners(ctx)
    69  		if err != nil {
    70  			return nil, nil, nil, nil, err
    71  		}
    72  		for _, s := range rscanners {
    73  			n := s.Name()
    74  			if _, ok := seen.repo[n]; ok {
    75  				continue
    76  			}
    77  			seen.repo[n] = struct{}{}
    78  			rs = append(rs, s)
    79  		}
    80  
    81  		if ecosystem.FileScanners != nil {
    82  			fscanners, err := ecosystem.FileScanners(ctx)
    83  			if err != nil {
    84  				return nil, nil, nil, nil, err
    85  			}
    86  			for _, s := range fscanners {
    87  				n := s.Name()
    88  				if _, ok := seen.file[n]; ok {
    89  					continue
    90  				}
    91  				seen.file[n] = struct{}{}
    92  				fis = append(fis, s)
    93  			}
    94  		}
    95  	}
    96  	return ps, ds, rs, fis, nil
    97  }