From bef4943667bd5e4ac075dc76a4d5ecb3d5c9a640 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 27 Jul 2023 11:09:56 -0400 Subject: [PATCH 1/3] [wip] add image pull error handlers Signed-off-by: Alex Goodman --- cmd/syft/cli/packages/packages.go | 12 ++++++--- cmd/syft/cli/ui/handle_pull_docker_image.go | 30 +++++++++++++++++---- cmd/syft/internal/ui/ui.go | 3 ++- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/cmd/syft/cli/packages/packages.go b/cmd/syft/cli/packages/packages.go index a7c1d5521dc..c6ed8dacb6c 100644 --- a/cmd/syft/cli/packages/packages.go +++ b/cmd/syft/cli/packages/packages.go @@ -3,6 +3,7 @@ package packages import ( "context" "fmt" + "github.com/anchore/syft/internal/log" "github.com/wagoodman/go-partybus" @@ -101,14 +102,19 @@ func execWorker(app *config.Application, userInput string, writer sbom.Writer) < }, ) - if src != nil { - defer src.Close() - } if err != nil { errs <- fmt.Errorf("failed to construct source from user input %q: %w", userInput, err) return } + defer func() { + if src != nil { + if err := src.Close(); err != nil { + log.Tracef("unable to close source: %+v", err) + } + } + }() + s, err := GenerateSBOM(src, errs, app) if err != nil { errs <- err diff --git a/cmd/syft/cli/ui/handle_pull_docker_image.go b/cmd/syft/cli/ui/handle_pull_docker_image.go index 6675e3aeb94..21ab3124f77 100644 --- a/cmd/syft/cli/ui/handle_pull_docker_image.go +++ b/cmd/syft/cli/ui/handle_pull_docker_image.go @@ -2,18 +2,17 @@ package ui import ( "fmt" - "strings" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" "github.com/dustin/go-humanize" "github.com/wagoodman/go-partybus" "github.com/wagoodman/go-progress" + "strings" "github.com/anchore/bubbly/bubbles/taskprogress" stereoscopeParsers "github.com/anchore/stereoscope/pkg/event/parsers" "github.com/anchore/stereoscope/pkg/image/docker" "github.com/anchore/syft/internal/log" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" ) var _ interface { @@ -22,6 +21,7 @@ var _ interface { } = (*dockerPullProgressAdapter)(nil) type dockerPullStatus interface { + Error() error Complete() bool Layers() []docker.LayerID Current(docker.LayerID) docker.LayerState @@ -92,10 +92,25 @@ func (d dockerPullProgressAdapter) Current() int64 { } func (d dockerPullProgressAdapter) Error() error { + err := d.status.Error() + if err != nil { + return err + } + if d.status.Complete() { return progress.ErrCompleted } - // TODO: return intermediate error indications + for _, l := range d.status.Layers() { + cur := d.status.Current(l) + phaseErr := cur.PhaseProgress.Error() + dlErr := cur.DownloadProgress.Error() + if phaseErr != nil && !progress.IsErrCompleted(phaseErr) { + return phaseErr + } + if dlErr != nil && !progress.IsErrCompleted(dlErr) { + return dlErr + } + } return nil } @@ -107,6 +122,11 @@ func (d dockerPullProgressAdapter) Stage() string { func (f dockerPullStatusFormatter) Render(pullStatus dockerPullStatus) string { var size, current uint64 + err := pullStatus.Error() + if err != nil && !progress.IsErrCompleted(err) { + return "NOPE" + } + layers := pullStatus.Layers() status := make(map[docker.LayerID]docker.LayerState) completed := make([]string, len(layers)) diff --git a/cmd/syft/internal/ui/ui.go b/cmd/syft/internal/ui/ui.go index f8f0fd0ae49..442fa1bacef 100644 --- a/cmd/syft/internal/ui/ui.go +++ b/cmd/syft/internal/ui/ui.go @@ -82,11 +82,12 @@ func (m *UI) Teardown(force bool) error { if !force { m.handler.Running.Wait() m.program.Quit() + //m.running.Wait() // TODO? } else { m.program.Kill() } - m.running.Wait() + m.running.Wait() // TODO? // TODO: allow for writing out the full log output to the screen (only a partial log is shown currently) // this needs coordination to know what the last frame event is to change the state accordingly (which isn't possible now) From 64cfc616de04233d9e1f99347d374958866c096e Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 27 Jul 2023 11:14:31 -0400 Subject: [PATCH 2/3] fix panic and ui hang on docker pull failure Signed-off-by: Alex Goodman --- cmd/syft/cli/ui/handle_pull_docker_image.go | 30 ++++----------------- cmd/syft/internal/ui/ui.go | 8 +++--- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/cmd/syft/cli/ui/handle_pull_docker_image.go b/cmd/syft/cli/ui/handle_pull_docker_image.go index 21ab3124f77..6675e3aeb94 100644 --- a/cmd/syft/cli/ui/handle_pull_docker_image.go +++ b/cmd/syft/cli/ui/handle_pull_docker_image.go @@ -2,17 +2,18 @@ package ui import ( "fmt" + "strings" + + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" "github.com/dustin/go-humanize" "github.com/wagoodman/go-partybus" "github.com/wagoodman/go-progress" - "strings" "github.com/anchore/bubbly/bubbles/taskprogress" stereoscopeParsers "github.com/anchore/stereoscope/pkg/event/parsers" "github.com/anchore/stereoscope/pkg/image/docker" "github.com/anchore/syft/internal/log" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" ) var _ interface { @@ -21,7 +22,6 @@ var _ interface { } = (*dockerPullProgressAdapter)(nil) type dockerPullStatus interface { - Error() error Complete() bool Layers() []docker.LayerID Current(docker.LayerID) docker.LayerState @@ -92,25 +92,10 @@ func (d dockerPullProgressAdapter) Current() int64 { } func (d dockerPullProgressAdapter) Error() error { - err := d.status.Error() - if err != nil { - return err - } - if d.status.Complete() { return progress.ErrCompleted } - for _, l := range d.status.Layers() { - cur := d.status.Current(l) - phaseErr := cur.PhaseProgress.Error() - dlErr := cur.DownloadProgress.Error() - if phaseErr != nil && !progress.IsErrCompleted(phaseErr) { - return phaseErr - } - if dlErr != nil && !progress.IsErrCompleted(dlErr) { - return dlErr - } - } + // TODO: return intermediate error indications return nil } @@ -122,11 +107,6 @@ func (d dockerPullProgressAdapter) Stage() string { func (f dockerPullStatusFormatter) Render(pullStatus dockerPullStatus) string { var size, current uint64 - err := pullStatus.Error() - if err != nil && !progress.IsErrCompleted(err) { - return "NOPE" - } - layers := pullStatus.Layers() status := make(map[docker.LayerID]docker.LayerState) completed := make([]string, len(layers)) diff --git a/cmd/syft/internal/ui/ui.go b/cmd/syft/internal/ui/ui.go index 442fa1bacef..441470b7ce2 100644 --- a/cmd/syft/internal/ui/ui.go +++ b/cmd/syft/internal/ui/ui.go @@ -82,13 +82,15 @@ func (m *UI) Teardown(force bool) error { if !force { m.handler.Running.Wait() m.program.Quit() - //m.running.Wait() // TODO? + // typically in all cases we would want to wait for the UI to finish. However there are still error cases + // that are not accounted for, resulting in hangs. For now, we'll just wait for the UI to finish in the + // happy path only. There will always be an indication of the problem to the user via reporting the error + // string from the worker (outside of the UI after teardown). + m.running.Wait() } else { m.program.Kill() } - m.running.Wait() // TODO? - // TODO: allow for writing out the full log output to the screen (only a partial log is shown currently) // this needs coordination to know what the last frame event is to change the state accordingly (which isn't possible now) From e63587e57a43121fe5c97f1da329a844728141a0 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 27 Jul 2023 11:21:18 -0400 Subject: [PATCH 3/3] linter fix Signed-off-by: Alex Goodman --- cmd/syft/cli/packages/packages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/syft/cli/packages/packages.go b/cmd/syft/cli/packages/packages.go index c6ed8dacb6c..0f87720fb8a 100644 --- a/cmd/syft/cli/packages/packages.go +++ b/cmd/syft/cli/packages/packages.go @@ -3,7 +3,6 @@ package packages import ( "context" "fmt" - "github.com/anchore/syft/internal/log" "github.com/wagoodman/go-partybus" @@ -16,6 +15,7 @@ import ( "github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/file" + "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/version" "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/artifact"