Switch UI to bubbletea (#1888)

* add bubbletea UI

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* swap pipeline to go 1.20.x and add attest guard for cosign binary

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* update note in developing.md about the required golang version

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix merge conflict for windows path handling

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* temp test for attest handler

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* add addtional test iterations for background reader

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2023-07-06 09:00:46 -04:00
committed by GitHub
parent a00a3df10c
commit f8b832e6c3
77 changed files with 3250 additions and 618 deletions
+30 -16
View File
@@ -4,37 +4,51 @@ defined here there should be a corresponding event parser defined in the parsers
*/
package event
import "github.com/wagoodman/go-partybus"
import (
"github.com/wagoodman/go-partybus"
"github.com/anchore/syft/internal"
)
const (
// AppUpdateAvailable is a partybus event that occurs when an application update is available
AppUpdateAvailable partybus.EventType = "syft-app-update-available"
typePrefix = internal.ApplicationName
cliTypePrefix = typePrefix + "-cli"
// Events from the syft library
// PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun
PackageCatalogerStarted partybus.EventType = "syft-package-cataloger-started-event"
PackageCatalogerStarted partybus.EventType = typePrefix + "-package-cataloger-started-event"
//nolint:gosec
// SecretsCatalogerStarted is a partybus event that occurs when the secrets cataloging has begun
SecretsCatalogerStarted partybus.EventType = "syft-secrets-cataloger-started-event"
SecretsCatalogerStarted partybus.EventType = typePrefix + "-secrets-cataloger-started-event"
// FileMetadataCatalogerStarted is a partybus event that occurs when the file metadata cataloging has begun
FileMetadataCatalogerStarted partybus.EventType = "syft-file-metadata-cataloger-started-event"
FileMetadataCatalogerStarted partybus.EventType = typePrefix + "-file-metadata-cataloger-started-event"
// FileDigestsCatalogerStarted is a partybus event that occurs when the file digests cataloging has begun
FileDigestsCatalogerStarted partybus.EventType = "syft-file-digests-cataloger-started-event"
FileDigestsCatalogerStarted partybus.EventType = typePrefix + "-file-digests-cataloger-started-event"
// FileIndexingStarted is a partybus event that occurs when the directory resolver begins indexing a filesystem
FileIndexingStarted partybus.EventType = "syft-file-indexing-started-event"
// Exit is a partybus event that occurs when an analysis result is ready for final presentation
Exit partybus.EventType = "syft-exit-event"
// ImportStarted is a partybus event that occurs when an SBOM upload process has begun
ImportStarted partybus.EventType = "syft-import-started-event"
FileIndexingStarted partybus.EventType = typePrefix + "-file-indexing-started-event"
// AttestationStarted is a partybus event that occurs when starting an SBOM attestation process
AttestationStarted partybus.EventType = "syft-attestation-started-event"
AttestationStarted partybus.EventType = typePrefix + "-attestation-started-event"
// CatalogerTaskStarted is a partybus event that occurs when starting a task within a cataloger
CatalogerTaskStarted partybus.EventType = "syft-cataloger-task-started"
CatalogerTaskStarted partybus.EventType = typePrefix + "-cataloger-task-started"
// Events exclusively for the CLI
// CLIAppUpdateAvailable is a partybus event that occurs when an application update is available
CLIAppUpdateAvailable partybus.EventType = cliTypePrefix + "-app-update-available"
// CLIReport is a partybus event that occurs when an analysis result is ready for final presentation to stdout
CLIReport partybus.EventType = cliTypePrefix + "-report"
// CLINotification is a partybus event that occurs when auxiliary information is ready for presentation to stderr
CLINotification partybus.EventType = cliTypePrefix + "-notification"
// CLIExit is a partybus event that occurs when an analysis result is ready for final presentation
CLIExit partybus.EventType = cliTypePrefix + "-exit-event"
)
@@ -1,12 +1,15 @@
package event
package monitor
import (
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/syft/event"
)
// TODO: this should be refactored to support read-only/write-only access using idioms of the progress lib
type CatalogerTask struct {
prog *progress.Manual
// Title
@@ -25,7 +28,7 @@ func (e *CatalogerTask) init() {
e.prog = progress.NewManual(-1)
bus.Publish(partybus.Event{
Type: CatalogerTaskStarted,
Type: event.CatalogerTaskStarted,
Source: e,
})
}
+1 -1
View File
@@ -8,7 +8,7 @@ import (
type ShellProgress struct {
io.Reader
*progress.Manual
progress.Progressable
}
type Title struct {
+70 -48
View File
@@ -23,7 +23,7 @@ type ErrBadPayload struct {
}
func (e *ErrBadPayload) Error() string {
return fmt.Sprintf("event='%s' has bad event payload field='%v': '%+v'", string(e.Type), e.Field, e.Value)
return fmt.Sprintf("event='%s' has bad event payload field=%q: %q", string(e.Type), e.Field, e.Value)
}
func newPayloadErr(t partybus.EventType, field string, value interface{}) error {
@@ -111,12 +111,12 @@ func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgress
return path, prog, nil
}
func ParseCatalogerTaskStarted(e partybus.Event) (*event.CatalogerTask, error) {
func ParseCatalogerTaskStarted(e partybus.Event) (*monitor.CatalogerTask, error) {
if err := checkEventType(e.Type, event.CatalogerTaskStarted); err != nil {
return nil, err
}
source, ok := e.Source.(*event.CatalogerTask)
source, ok := e.Source.(*monitor.CatalogerTask)
if !ok {
return nil, newPayloadErr(e.Type, "Source", e.Source)
}
@@ -124,50 +124,6 @@ func ParseCatalogerTaskStarted(e partybus.Event) (*event.CatalogerTask, error) {
return source, nil
}
func ParseExit(e partybus.Event) (func() error, error) {
if err := checkEventType(e.Type, event.Exit); err != nil {
return nil, err
}
fn, ok := e.Value.(func() error)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}
return fn, nil
}
func ParseAppUpdateAvailable(e partybus.Event) (string, error) {
if err := checkEventType(e.Type, event.AppUpdateAvailable); err != nil {
return "", err
}
newVersion, ok := e.Value.(string)
if !ok {
return "", newPayloadErr(e.Type, "Value", e.Value)
}
return newVersion, nil
}
func ParseImportStarted(e partybus.Event) (string, progress.StagedProgressable, error) {
if err := checkEventType(e.Type, event.ImportStarted); err != nil {
return "", nil, err
}
host, ok := e.Source.(string)
if !ok {
return "", nil, newPayloadErr(e.Type, "Source", e.Source)
}
prog, ok := e.Value.(progress.StagedProgressable)
if !ok {
return "", nil, newPayloadErr(e.Type, "Value", e.Value)
}
return host, prog, nil
}
func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progressable, *monitor.GenericTask, error) {
if err := checkEventType(e.Type, event.AttestationStarted); err != nil {
return nil, nil, nil, err
@@ -183,5 +139,71 @@ func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progres
return nil, nil, nil, newPayloadErr(e.Type, "Value", e.Value)
}
return sp.Reader, sp.Manual, &source, nil
return sp.Reader, sp.Progressable, &source, nil
}
// CLI event types
func ParseCLIExit(e partybus.Event) (func() error, error) {
if err := checkEventType(e.Type, event.CLIExit); err != nil {
return nil, err
}
fn, ok := e.Value.(func() error)
if !ok {
return nil, newPayloadErr(e.Type, "Value", e.Value)
}
return fn, nil
}
func ParseCLIAppUpdateAvailable(e partybus.Event) (string, error) {
if err := checkEventType(e.Type, event.CLIAppUpdateAvailable); err != nil {
return "", err
}
newVersion, ok := e.Value.(string)
if !ok {
return "", newPayloadErr(e.Type, "Value", e.Value)
}
return newVersion, nil
}
func ParseCLIReport(e partybus.Event) (string, string, error) {
if err := checkEventType(e.Type, event.CLIReport); err != nil {
return "", "", err
}
context, ok := e.Source.(string)
if !ok {
// this is optional
context = ""
}
report, ok := e.Value.(string)
if !ok {
return "", "", newPayloadErr(e.Type, "Value", e.Value)
}
return context, report, nil
}
func ParseCLINotification(e partybus.Event) (string, string, error) {
if err := checkEventType(e.Type, event.CLINotification); err != nil {
return "", "", err
}
context, ok := e.Source.(string)
if !ok {
// this is optional
context = ""
}
notification, ok := e.Value.(string)
if !ok {
return "", "", newPayloadErr(e.Type, "Value", e.Value)
}
return context, notification, nil
}
@@ -332,14 +332,15 @@ func (r directoryIndexer) addFileToIndex(p string, info os.FileInfo) error {
func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string, error) {
linkTarget, err := os.Readlink(p)
if err != nil {
if runtime.GOOS == WindowsOS {
p = posixToWindows(p)
isOnWindows := windows.HostRunningOnWindows()
if isOnWindows {
p = windows.FromPosix(p)
}
linkTarget, err = filepath.EvalSymlinks(p)
if runtime.GOOS == WindowsOS {
p = windowsToPosix(p)
if isOnWindows {
p = windows.ToPosix(p)
}
if err != nil {
+2 -2
View File
@@ -94,10 +94,10 @@ func newSourceRelationshipsFromCatalog(src source.Source, c *pkg.Collection) []a
// SetLogger sets the logger object used for all syft logging calls.
func SetLogger(logger logger.Logger) {
log.Log = logger
log.Set(logger)
}
// SetBus sets the event bus for all syft library bus publish events onto (in-library subscriptions are not allowed).
func SetBus(b *partybus.Bus) {
bus.SetPublisher(b)
bus.Set(b)
}
+2 -2
View File
@@ -6,7 +6,7 @@ package golang
import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
@@ -37,7 +37,7 @@ func NewGoModuleBinaryCataloger(opts GoCatalogerOpts) pkg.Cataloger {
}
type progressingCataloger struct {
progress *event.CatalogerTask
progress *monitor.CatalogerTask
cataloger *generic.Cataloger
}
+6 -6
View File
@@ -21,7 +21,7 @@ import (
"github.com/anchore/syft/internal/licenses"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/event/monitor"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/internal/fileresolver"
"github.com/anchore/syft/syft/pkg"
@@ -30,14 +30,14 @@ import (
type goLicenses struct {
opts GoCatalogerOpts
localModCacheResolver file.WritableResolver
progress *event.CatalogerTask
progress *monitor.CatalogerTask
}
func newGoLicenses(opts GoCatalogerOpts) goLicenses {
return goLicenses{
opts: opts,
localModCacheResolver: modCacheResolver(opts.localModCacheDir),
progress: &event.CatalogerTask{
progress: &monitor.CatalogerTask{
SubStatus: true,
RemoveOnCompletion: true,
Title: "Downloading go mod",
@@ -195,7 +195,7 @@ func processCaps(s string) string {
})
}
func getModule(progress *event.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
for _, proxy := range proxies {
u, _ := url.Parse(proxy)
if proxy == "direct" {
@@ -217,7 +217,7 @@ func getModule(progress *event.CatalogerTask, proxies []string, moduleName, modu
return
}
func getModuleProxy(progress *event.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
progress.SetValue(u)
// get the module zip
@@ -265,7 +265,7 @@ func findVersionPath(f fs.FS, dir string) string {
return ""
}
func getModuleRepository(progress *event.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
func getModuleRepository(progress *monitor.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
repoName := moduleName
parts := strings.Split(moduleName, "/")
if len(parts) > 2 {
@@ -49,8 +49,7 @@ func parseAuditBinaryEntry(reader unionreader.UnionReader, filename string) []ru
// binary, we should not show warnings/logs in this case.
return nil
}
// Use an Info level log here like golang/scan_bin.go
log.Infof("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
log.Tracef("rust cataloger: unable to read dependency information (file=%q): %v", filename, err)
return nil
}