github.com/anchore/syft@v1.38.2/internal/task/executor.go (about)

     1  package task
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"runtime/debug"
     7  	"slices"
     8  	"time"
     9  
    10  	"github.com/anchore/syft/internal/log"
    11  	"github.com/anchore/syft/internal/sbomsync"
    12  	"github.com/anchore/syft/internal/unknown"
    13  	"github.com/anchore/syft/syft/event/monitor"
    14  	"github.com/anchore/syft/syft/file"
    15  	"github.com/anchore/syft/syft/sbom"
    16  )
    17  
    18  func RunTask(ctx context.Context, tsk Task, resolver file.Resolver, s sbomsync.Builder, prog *monitor.TaskProgress) error {
    19  	err := runTaskSafely(ctx, tsk, resolver, s)
    20  	unknowns, remainingErrors := unknown.ExtractCoordinateErrors(err)
    21  	if len(unknowns) > 0 {
    22  		appendUnknowns(s, tsk.Name(), unknowns)
    23  	}
    24  	if remainingErrors != nil {
    25  		prog.SetError(remainingErrors)
    26  	}
    27  	prog.Increment()
    28  	return remainingErrors
    29  }
    30  
    31  func appendUnknowns(builder sbomsync.Builder, taskName string, unknowns []unknown.CoordinateError) {
    32  	if accessor, ok := builder.(sbomsync.Accessor); ok {
    33  		accessor.WriteToSBOM(func(sb *sbom.SBOM) {
    34  			for _, u := range unknowns {
    35  				if sb.Artifacts.Unknowns == nil {
    36  					sb.Artifacts.Unknowns = map[file.Coordinates][]string{}
    37  				}
    38  				unknownText := formatUnknown(u.Reason.Error(), taskName)
    39  				existing := sb.Artifacts.Unknowns[u.Coordinates]
    40  				// don't include duplicate unknowns
    41  				if slices.Contains(existing, unknownText) {
    42  					continue
    43  				}
    44  				sb.Artifacts.Unknowns[u.Coordinates] = append(existing, unknownText)
    45  			}
    46  		})
    47  	}
    48  }
    49  
    50  func runTaskSafely(ctx context.Context, t Task, resolver file.Resolver, s sbomsync.Builder) (err error) {
    51  	// handle individual cataloger panics
    52  	defer func() {
    53  		if e := recover(); e != nil {
    54  			err = fmt.Errorf("%v at:\n%s", e, string(debug.Stack()))
    55  		}
    56  	}()
    57  
    58  	start := time.Now()
    59  	res := t.Execute(ctx, resolver, s)
    60  	log.WithFields("task", t.Name(), "elapsed", time.Since(start)).Info("task completed")
    61  	return res
    62  }