github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/cmd/gosbom/cli/poweruser/poweruser.go (about)

     1  package poweruser
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/gookit/color"
     9  	"github.com/nextlinux/gosbom/cmd/gosbom/cli/eventloop"
    10  	"github.com/nextlinux/gosbom/cmd/gosbom/cli/options"
    11  	"github.com/nextlinux/gosbom/cmd/gosbom/cli/packages"
    12  	"github.com/nextlinux/gosbom/gosbom"
    13  	"github.com/nextlinux/gosbom/gosbom/artifact"
    14  	"github.com/nextlinux/gosbom/gosbom/event"
    15  	"github.com/nextlinux/gosbom/gosbom/formats/gosbomjson"
    16  	"github.com/nextlinux/gosbom/gosbom/sbom"
    17  	"github.com/nextlinux/gosbom/gosbom/source"
    18  	"github.com/nextlinux/gosbom/internal"
    19  	"github.com/nextlinux/gosbom/internal/bus"
    20  	"github.com/nextlinux/gosbom/internal/config"
    21  	"github.com/nextlinux/gosbom/internal/ui"
    22  	"github.com/nextlinux/gosbom/internal/version"
    23  	"github.com/wagoodman/go-partybus"
    24  
    25  	"github.com/anchore/stereoscope"
    26  )
    27  
    28  func Run(_ context.Context, app *config.Application, args []string) error {
    29  	f := gosbomjson.Format()
    30  	writer, err := options.MakeSBOMWriterForFormat(f, app.File)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	defer func() {
    35  		// inform user at end of run that command will be removed
    36  		deprecated := color.Style{color.Red, color.OpBold}.Sprint("DEPRECATED: This command will be removed in v1.0.0")
    37  		fmt.Fprintln(os.Stderr, deprecated)
    38  	}()
    39  
    40  	userInput := args[0]
    41  	si, err := source.ParseInputWithNameVersion(userInput, app.Platform, app.SourceName, app.SourceVersion, app.DefaultImagePullSource)
    42  	if err != nil {
    43  		return fmt.Errorf("could not generate source input for packages command: %w", err)
    44  	}
    45  
    46  	eventBus := partybus.NewBus()
    47  	stereoscope.SetBus(eventBus)
    48  	gosbom.SetBus(eventBus)
    49  	subscription := eventBus.Subscribe()
    50  
    51  	return eventloop.EventLoop(
    52  		execWorker(app, *si, writer),
    53  		eventloop.SetupSignals(),
    54  		subscription,
    55  		stereoscope.Cleanup,
    56  		ui.Select(options.IsVerbose(app), app.Quiet)...,
    57  	)
    58  }
    59  
    60  func execWorker(app *config.Application, si source.Input, writer sbom.Writer) <-chan error {
    61  	errs := make(chan error)
    62  	go func() {
    63  		defer close(errs)
    64  
    65  		app.Secrets.Cataloger.Enabled = true
    66  		app.FileMetadata.Cataloger.Enabled = true
    67  		app.FileContents.Cataloger.Enabled = true
    68  		app.FileClassification.Cataloger.Enabled = true
    69  		tasks, err := eventloop.Tasks(app)
    70  		if err != nil {
    71  			errs <- err
    72  			return
    73  		}
    74  
    75  		src, cleanup, err := source.New(si, app.Registry.ToOptions(), app.Exclusions)
    76  		if err != nil {
    77  			errs <- err
    78  			return
    79  		}
    80  		if cleanup != nil {
    81  			defer cleanup()
    82  		}
    83  
    84  		s := sbom.SBOM{
    85  			Source: src.Metadata,
    86  			Descriptor: sbom.Descriptor{
    87  				Name:          internal.ApplicationName,
    88  				Version:       version.FromBuild().Version,
    89  				Configuration: app,
    90  			},
    91  		}
    92  
    93  		var relationships []<-chan artifact.Relationship
    94  		for _, task := range tasks {
    95  			c := make(chan artifact.Relationship)
    96  			relationships = append(relationships, c)
    97  
    98  			go eventloop.RunTask(task, &s.Artifacts, src, c, errs)
    99  		}
   100  
   101  		s.Relationships = append(s.Relationships, packages.MergeRelationships(relationships...)...)
   102  
   103  		bus.Publish(partybus.Event{
   104  			Type:  event.Exit,
   105  			Value: func() error { return writer.Write(s) },
   106  		})
   107  	}()
   108  
   109  	return errs
   110  }