github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/file/cataloger/filemetadata/cataloger.go (about)

     1  package filemetadata
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/dustin/go-humanize"
     8  
     9  	"github.com/anchore/syft/internal/bus"
    10  	"github.com/anchore/syft/internal/log"
    11  	"github.com/anchore/syft/syft/event/monitor"
    12  	"github.com/anchore/syft/syft/file"
    13  )
    14  
    15  type Cataloger struct {
    16  }
    17  
    18  func NewCataloger() *Cataloger {
    19  	return &Cataloger{}
    20  }
    21  
    22  func (i *Cataloger) Catalog(ctx context.Context, resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates]file.Metadata, error) {
    23  	results := make(map[file.Coordinates]file.Metadata)
    24  	var locations <-chan file.Location
    25  	ctx, cancel := context.WithCancel(ctx)
    26  	defer cancel()
    27  	if len(coordinates) == 0 {
    28  		locations = resolver.AllLocations(ctx)
    29  	} else {
    30  		locations = func() <-chan file.Location {
    31  			ch := make(chan file.Location)
    32  			go func() {
    33  				defer close(ch)
    34  				for _, c := range coordinates {
    35  					locs, err := resolver.FilesByPath(c.RealPath)
    36  					if err != nil {
    37  						log.Warn("unable to get file locations for path %q: %w", c.RealPath, err)
    38  						continue
    39  					}
    40  					for _, loc := range locs {
    41  						select {
    42  						case <-ctx.Done():
    43  							return
    44  						case ch <- loc:
    45  							continue
    46  						}
    47  					}
    48  				}
    49  			}()
    50  			return ch
    51  		}()
    52  	}
    53  
    54  	prog := catalogingProgress(-1)
    55  	for location := range locations {
    56  		prog.AtomicStage.Set(location.Path())
    57  
    58  		metadata, err := resolver.FileMetadataByLocation(location)
    59  		if err != nil {
    60  			prog.SetError(err)
    61  			return nil, err
    62  		}
    63  
    64  		prog.Increment()
    65  
    66  		results[location.Coordinates] = metadata
    67  	}
    68  
    69  	log.Debugf("file metadata cataloger processed %d files", prog.Current())
    70  
    71  	prog.AtomicStage.Set(fmt.Sprintf("%s locations", humanize.Comma(prog.Current())))
    72  	prog.SetCompleted()
    73  
    74  	return results, nil
    75  }
    76  
    77  func catalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
    78  	info := monitor.GenericTask{
    79  		Title: monitor.Title{
    80  			Default: "File metadata",
    81  		},
    82  		ParentID: monitor.TopLevelCatalogingTaskID,
    83  	}
    84  
    85  	return bus.StartCatalogerTask(info, locations, "")
    86  }