mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
remove jotframe UI (#1932)
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
2e7fd031d4
commit
35699f6fdc
1
go.mod
1
go.mod
@ -40,7 +40,6 @@ require (
|
|||||||
github.com/vifraa/gopom v0.2.1
|
github.com/vifraa/gopom v0.2.1
|
||||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
|
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
|
||||||
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5
|
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5
|
||||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb
|
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
golang.org/x/mod v0.12.0
|
golang.org/x/mod v0.12.0
|
||||||
golang.org/x/net v0.12.0
|
golang.org/x/net v0.12.0
|
||||||
|
|||||||
6
go.sum
6
go.sum
@ -419,7 +419,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
|||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
@ -466,7 +465,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb
|
|||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
@ -681,8 +679,6 @@ github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIq
|
|||||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20=
|
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20=
|
||||||
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5 h1:lwgTsTy18nYqASnH58qyfRW/ldj7Gt2zzBvgYPzdA4s=
|
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5 h1:lwgTsTy18nYqASnH58qyfRW/ldj7Gt2zzBvgYPzdA4s=
|
||||||
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
github.com/wagoodman/go-progress v0.0.0-20230301185719-21920a456ad5/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
|
||||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb h1:Yz6VVOcLuWLAHYlJzTw7JKnWxdV/WXpug2X0quEzRnY=
|
|
||||||
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb/go.mod h1:nDi3BAC5nEbVbg+WSJDHLbjHv0ZToq8nMPA97XMxF3E=
|
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
@ -722,7 +718,6 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
|
|||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -949,7 +944,6 @@ golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
|||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
|||||||
783
ui/deprecated.go
783
ui/deprecated.go
@ -1,783 +0,0 @@
|
|||||||
/*
|
|
||||||
Package ui provides all public UI elements intended to be repurposed in other applications. Specifically, a single
|
|
||||||
Handler object is provided to allow consuming applications (such as grype) to check if there are UI elements the handler
|
|
||||||
can respond to (given a specific event type) and handle the event in context of the given screen frame object.
|
|
||||||
*/
|
|
||||||
package ui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"container/list"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
|
||||||
"github.com/gookit/color"
|
|
||||||
"github.com/wagoodman/go-partybus"
|
|
||||||
"github.com/wagoodman/go-progress"
|
|
||||||
"github.com/wagoodman/go-progress/format"
|
|
||||||
"github.com/wagoodman/jotframe/pkg/frame"
|
|
||||||
|
|
||||||
stereoscopeEvent "github.com/anchore/stereoscope/pkg/event"
|
|
||||||
stereoEventParsers "github.com/anchore/stereoscope/pkg/event/parsers"
|
|
||||||
"github.com/anchore/stereoscope/pkg/image/docker"
|
|
||||||
"github.com/anchore/syft/internal"
|
|
||||||
syftEvent "github.com/anchore/syft/syft/event"
|
|
||||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
|
||||||
)
|
|
||||||
|
|
||||||
const maxBarWidth = 50
|
|
||||||
const statusSet = SpinnerDotSet
|
|
||||||
const completedStatus = "✔"
|
|
||||||
const failedStatus = "✘"
|
|
||||||
const titleFormat = color.Bold
|
|
||||||
const subTitleFormat = color.Normal
|
|
||||||
const interval = 150 * time.Millisecond
|
|
||||||
|
|
||||||
// StatusTitleColumn is the column index in a given row where status text will be displayed.
|
|
||||||
const StatusTitleColumn = 31
|
|
||||||
|
|
||||||
var (
|
|
||||||
auxInfoFormat = color.HEX("#777777")
|
|
||||||
dockerPullCompletedColor = color.HEX("#fcba03")
|
|
||||||
dockerPullDownloadColor = color.HEX("#777777")
|
|
||||||
dockerPullExtractColor = color.White
|
|
||||||
dockerPullStageChars = strings.Split("▁▃▄▅▆▇█", "")
|
|
||||||
statusTitleTemplate = fmt.Sprintf(" %%s %%-%ds ", StatusTitleColumn)
|
|
||||||
subStatusTitleTemplate = fmt.Sprintf(" └── %%-%ds ", StatusTitleColumn-3)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handler is an aggregated event handler for the set of supported events (PullDockerImage, ReadImage, FetchImage, PackageCatalogerStarted)
|
|
||||||
// Deprecated: use the bubbletea event handler in cmd/syft/ui/handler.go instead.
|
|
||||||
type Handler struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHandler returns an empty Handler
|
|
||||||
// Deprecated: use the bubbletea event handler in cmd/syft/ui/handler.go instead.
|
|
||||||
func NewHandler() *Handler {
|
|
||||||
return &Handler{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RespondsTo indicates if the handler is capable of handling the given event.
|
|
||||||
// Deprecated: use the bubbletea event handler in cmd/syft/ui/handler.go instead.
|
|
||||||
func (r *Handler) RespondsTo(event partybus.Event) bool {
|
|
||||||
switch event.Type {
|
|
||||||
case stereoscopeEvent.PullDockerImage,
|
|
||||||
stereoscopeEvent.ReadImage,
|
|
||||||
stereoscopeEvent.FetchImage,
|
|
||||||
syftEvent.PackageCatalogerStarted,
|
|
||||||
syftEvent.SecretsCatalogerStarted,
|
|
||||||
syftEvent.FileDigestsCatalogerStarted,
|
|
||||||
syftEvent.FileMetadataCatalogerStarted,
|
|
||||||
syftEvent.FileIndexingStarted,
|
|
||||||
syftEvent.AttestationStarted,
|
|
||||||
syftEvent.CatalogerTaskStarted:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle calls the specific event handler for the given event within the context of the screen frame.
|
|
||||||
// Deprecated: use the bubbletea event handler in cmd/syft/ui/handler.go instead.
|
|
||||||
func (r *Handler) Handle(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
switch event.Type {
|
|
||||||
case stereoscopeEvent.PullDockerImage:
|
|
||||||
return PullDockerImageHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case stereoscopeEvent.ReadImage:
|
|
||||||
return ReadImageHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case stereoscopeEvent.FetchImage:
|
|
||||||
return FetchImageHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.PackageCatalogerStarted:
|
|
||||||
return PackageCatalogerStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.SecretsCatalogerStarted:
|
|
||||||
return SecretsCatalogerStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.FileDigestsCatalogerStarted:
|
|
||||||
return FileDigestsCatalogerStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.FileMetadataCatalogerStarted:
|
|
||||||
return FileMetadataCatalogerStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.FileIndexingStarted:
|
|
||||||
return FileIndexingStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.AttestationStarted:
|
|
||||||
return AttestationStartedHandler(ctx, fr, event, wg)
|
|
||||||
|
|
||||||
case syftEvent.CatalogerTaskStarted:
|
|
||||||
return CatalogerTaskStartedHandler(ctx, fr, event, wg)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
SpinnerDotSet = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
||||||
)
|
|
||||||
|
|
||||||
type spinner struct {
|
|
||||||
index int
|
|
||||||
charset []string
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSpinner(charset string) spinner {
|
|
||||||
return spinner{
|
|
||||||
charset: strings.Split(charset, ""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *spinner) Current() string {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
|
|
||||||
return s.charset[s.index]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *spinner) Next() string {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
c := s.charset[s.index]
|
|
||||||
s.index++
|
|
||||||
if s.index >= len(s.charset) {
|
|
||||||
s.index = 0
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// startProcess is a helper function for providing common elements for long-running UI elements (such as a
|
|
||||||
// progress bar formatter and status spinner)
|
|
||||||
func startProcess() (format.Simple, *spinner) {
|
|
||||||
width, _ := frame.GetTerminalSize()
|
|
||||||
barWidth := int(0.25 * float64(width))
|
|
||||||
if barWidth > maxBarWidth {
|
|
||||||
barWidth = maxBarWidth
|
|
||||||
}
|
|
||||||
formatter := format.NewSimpleWithTheme(barWidth, format.HeavyNoBarTheme, format.ColorCompleted, format.ColorTodo)
|
|
||||||
spinner := newSpinner(statusSet)
|
|
||||||
|
|
||||||
return formatter, &spinner
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatDockerPullPhase returns a single character that represents the status of a layer pull.
|
|
||||||
func formatDockerPullPhase(phase docker.PullPhase, inputStr string) string {
|
|
||||||
switch phase {
|
|
||||||
case docker.WaitingPhase:
|
|
||||||
// ignore any progress related to waiting
|
|
||||||
return " "
|
|
||||||
case docker.PullingFsPhase, docker.DownloadingPhase:
|
|
||||||
return dockerPullDownloadColor.Sprint(inputStr)
|
|
||||||
case docker.DownloadCompletePhase:
|
|
||||||
return dockerPullDownloadColor.Sprint(dockerPullStageChars[len(dockerPullStageChars)-1])
|
|
||||||
case docker.ExtractingPhase:
|
|
||||||
return dockerPullExtractColor.Sprint(inputStr)
|
|
||||||
case docker.VerifyingChecksumPhase, docker.PullCompletePhase:
|
|
||||||
return dockerPullCompletedColor.Sprint(inputStr)
|
|
||||||
case docker.AlreadyExistsPhase:
|
|
||||||
return dockerPullCompletedColor.Sprint(dockerPullStageChars[len(dockerPullStageChars)-1])
|
|
||||||
default:
|
|
||||||
return inputStr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatDockerImagePullStatus writes the docker image pull status summarized into a single line for the given state.
|
|
||||||
func formatDockerImagePullStatus(pullStatus *docker.PullStatus, spinner *spinner, line *frame.Line) {
|
|
||||||
var size, current uint64
|
|
||||||
|
|
||||||
title := titleFormat.Sprint("Pulling image")
|
|
||||||
|
|
||||||
layers := pullStatus.Layers()
|
|
||||||
status := make(map[docker.LayerID]docker.LayerState)
|
|
||||||
completed := make([]string, len(layers))
|
|
||||||
|
|
||||||
// fetch the current state
|
|
||||||
for idx, layer := range layers {
|
|
||||||
completed[idx] = " "
|
|
||||||
status[layer] = pullStatus.Current(layer)
|
|
||||||
}
|
|
||||||
|
|
||||||
numCompleted := 0
|
|
||||||
for idx, layer := range layers {
|
|
||||||
prog := status[layer].PhaseProgress
|
|
||||||
current := prog.Current()
|
|
||||||
size := prog.Size()
|
|
||||||
|
|
||||||
if progress.IsCompleted(prog) {
|
|
||||||
input := dockerPullStageChars[len(dockerPullStageChars)-1]
|
|
||||||
completed[idx] = formatDockerPullPhase(status[layer].Phase, input)
|
|
||||||
} else if current != 0 {
|
|
||||||
var ratio float64
|
|
||||||
switch {
|
|
||||||
case current == 0 || size < 0:
|
|
||||||
ratio = 0
|
|
||||||
case current >= size:
|
|
||||||
ratio = 1
|
|
||||||
default:
|
|
||||||
ratio = float64(current) / float64(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
i := int(ratio * float64(len(dockerPullStageChars)-1))
|
|
||||||
input := dockerPullStageChars[i]
|
|
||||||
completed[idx] = formatDockerPullPhase(status[layer].Phase, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
if progress.IsErrCompleted(status[layer].DownloadProgress.Error()) {
|
|
||||||
numCompleted++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, layer := range layers {
|
|
||||||
prog := status[layer].DownloadProgress
|
|
||||||
size += uint64(prog.Size())
|
|
||||||
current += uint64(prog.Current())
|
|
||||||
}
|
|
||||||
|
|
||||||
var progStr, auxInfo string
|
|
||||||
if len(layers) > 0 {
|
|
||||||
render := strings.Join(completed, "")
|
|
||||||
prefix := dockerPullCompletedColor.Sprintf("%d Layers", len(layers))
|
|
||||||
auxInfo = auxInfoFormat.Sprintf("[%s / %s]", humanize.Bytes(current), humanize.Bytes(size))
|
|
||||||
if len(layers) == numCompleted {
|
|
||||||
auxInfo = auxInfoFormat.Sprintf("[%s] Extracting...", humanize.Bytes(size))
|
|
||||||
}
|
|
||||||
|
|
||||||
progStr = fmt.Sprintf("%s▕%s▏", prefix, render)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s%s", spin, title, progStr, auxInfo))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PullDockerImageHandler periodically writes a formatted line widget representing a docker image pull event.
|
|
||||||
func PullDockerImageHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
_, pullStatus, err := stereoEventParsers.ParsePullDockerImage(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
_, spinner := startProcess()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
break loop
|
|
||||||
case <-time.After(interval):
|
|
||||||
formatDockerImagePullStatus(pullStatus, spinner, line)
|
|
||||||
if pullStatus.Complete() {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if pullStatus.Complete() {
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title := titleFormat.Sprint("Pulled image")
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchImageHandler periodically writes a the image save and write-to-disk process in the form of a progress bar.
|
|
||||||
func FetchImageHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
_, prog, err := stereoEventParsers.ParseFetchImage(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
formatter, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprint("Loading image")
|
|
||||||
|
|
||||||
formatFn := func(p progress.Progress) {
|
|
||||||
progStr, err := formatter.Format(p)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%s]", prog.Stage())
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s %s", spin, title, progStr, auxInfo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Loaded image")
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadImageHandler periodically writes a the image read/parse/build-tree status in the form of a progress bar.
|
|
||||||
func ReadImageHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
_, prog, err := stereoEventParsers.ParseReadImage(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
formatter, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprint("Parsing image")
|
|
||||||
|
|
||||||
formatFn := func(p progress.Progress) {
|
|
||||||
progStr, err := formatter.Format(p)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, progStr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Parsed image")
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PackageCatalogerStartedHandler periodically writes catalog statistics to a single line.
|
|
||||||
func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
monitor, err := syftEventParsers.ParsePackageCatalogerStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
_, spinner := startProcess()
|
|
||||||
stream := progress.StreamMonitors(ctx, []progress.Monitorable{monitor.FilesProcessed, monitor.PackagesDiscovered}, interval)
|
|
||||||
title := titleFormat.Sprint("Cataloging packages")
|
|
||||||
|
|
||||||
formatFn := func(p int64) {
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[packages %d]", p)
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(0)
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Cataloged packages")
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%d packages]", monitor.PackagesDiscovered.Current())
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SecretsCatalogerStartedHandler shows the intermittent secrets searching progress.
|
|
||||||
func SecretsCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
prog, err := syftEventParsers.ParseSecretsCatalogingStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
formatter, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprint("Cataloging secrets")
|
|
||||||
|
|
||||||
formatFn := func(p progress.Progress) {
|
|
||||||
progStr, err := formatter.Format(p)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%d secrets]", prog.SecretsDiscovered.Current())
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s %s", spin, title, progStr, auxInfo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Cataloged secrets")
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%d secrets]", prog.SecretsDiscovered.Current())
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileMetadataCatalogerStartedHandler shows the intermittent secrets searching progress.
|
|
||||||
//
|
|
||||||
//nolint:dupl
|
|
||||||
func FileMetadataCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
prog, err := syftEventParsers.ParseFileMetadataCatalogingStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
formatter, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprint("Cataloging file metadata")
|
|
||||||
|
|
||||||
formatFn := func(p progress.Progress) {
|
|
||||||
progStr, err := formatter.Format(p)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, progStr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Cataloged file metadata")
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileIndexingStartedHandler shows the intermittent indexing progress from a directory resolver.
|
|
||||||
func FileIndexingStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
path, prog, err := syftEventParsers.ParseFileIndexingStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
_, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprintf("Indexing %s", path)
|
|
||||||
|
|
||||||
formatFn := func(_ progress.Progress) {
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[file: %s]", internal.TruncateMiddleEllipsis(prog.Stage(), 100))
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprintf("Indexed %s", path)
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileMetadataCatalogerStartedHandler shows the intermittent secrets searching progress.
|
|
||||||
//
|
|
||||||
//nolint:dupl
|
|
||||||
func FileDigestsCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
prog, err := syftEventParsers.ParseFileDigestsCatalogingStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
formatter, spinner := startProcess()
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
title := titleFormat.Sprint("Cataloging file digests")
|
|
||||||
|
|
||||||
formatFn := func(p progress.Progress) {
|
|
||||||
progStr, err := formatter.Format(p)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, progStr))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn(progress.Progress{})
|
|
||||||
for p := range stream {
|
|
||||||
formatFn(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
title = titleFormat.Sprint("Cataloged file digests")
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttestationStartedHandler takes bytes from a event.ShellOutput and publishes them to the frame.
|
|
||||||
//
|
|
||||||
//nolint:funlen,gocognit
|
|
||||||
func AttestationStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
reader, prog, taskInfo, err := syftEventParsers.ParseAttestationStartedEvent(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
titleLine, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(2)
|
|
||||||
|
|
||||||
_, spinner := startProcess()
|
|
||||||
|
|
||||||
title := titleFormat.Sprintf(taskInfo.Title.WhileRunning)
|
|
||||||
|
|
||||||
s := bufio.NewScanner(reader)
|
|
||||||
l := list.New()
|
|
||||||
|
|
||||||
formatFn := func() {
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[running %s]", taskInfo.Context)
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
_, _ = io.WriteString(titleLine, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}
|
|
||||||
|
|
||||||
formatFn()
|
|
||||||
var failed bool
|
|
||||||
formatComplete := func(aux string) {
|
|
||||||
spin := color.Green.Sprint(completedStatus)
|
|
||||||
if failed {
|
|
||||||
spin = color.Red.Sprint(failedStatus)
|
|
||||||
aux = prog.Error().Error()
|
|
||||||
} else {
|
|
||||||
title = titleFormat.Sprintf(taskInfo.Title.OnSuccess)
|
|
||||||
}
|
|
||||||
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%s]", aux)
|
|
||||||
|
|
||||||
_, _ = io.WriteString(titleLine, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
|
||||||
}
|
|
||||||
|
|
||||||
endWg := &sync.WaitGroup{}
|
|
||||||
endWg.Add(1)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
defer endWg.Done()
|
|
||||||
|
|
||||||
stream := progress.Stream(ctx, prog, interval)
|
|
||||||
for range stream {
|
|
||||||
formatFn()
|
|
||||||
}
|
|
||||||
err := prog.Error()
|
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
|
||||||
failed = true
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
var tlogEntry string
|
|
||||||
|
|
||||||
// only show the last 5 lines of the shell output
|
|
||||||
for s.Scan() {
|
|
||||||
line, _ := fr.Append()
|
|
||||||
if l.Len() > 5 {
|
|
||||||
elem := l.Front()
|
|
||||||
line, ok := elem.Value.(*frame.Line)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = line.Remove()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
l.Remove(elem)
|
|
||||||
}
|
|
||||||
l.PushBack(line)
|
|
||||||
text := s.Text()
|
|
||||||
if strings.Contains(text, "tlog entry created with index") {
|
|
||||||
tlogEntry = text
|
|
||||||
} else {
|
|
||||||
// no tlog entry create so user used personal PKI
|
|
||||||
tlogEntry = "signed attestation using provided key"
|
|
||||||
}
|
|
||||||
_, err = line.Write([]byte(fmt.Sprintf(" %s %s", auxInfoFormat.Sprintf("░░"), text)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
endWg.Wait()
|
|
||||||
|
|
||||||
if !failed {
|
|
||||||
// roll up logs into completed status (only if successful)
|
|
||||||
for e := l.Back(); e != nil; e = e.Prev() {
|
|
||||||
line, ok := e.Value.(*frame.Line)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err = line.Remove()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formatComplete(tlogEntry)
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CatalogerTaskStartedHandler shows the intermittent progress for a cataloger subprocess messages
|
|
||||||
func CatalogerTaskStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
|
||||||
prog, err := syftEventParsers.ParseCatalogerTaskStarted(event)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad %s event: %w", event.Type, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
line, err := fr.Append()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
stream := progress.Stream(ctx, prog.GetMonitor(), interval)
|
|
||||||
|
|
||||||
_, spinner := startProcess()
|
|
||||||
|
|
||||||
formatLine := func(complete bool, auxInfo string) string {
|
|
||||||
title := prog.Title
|
|
||||||
if complete && prog.TitleOnCompletion != "" {
|
|
||||||
title = prog.TitleOnCompletion
|
|
||||||
}
|
|
||||||
if prog.SubStatus {
|
|
||||||
title = subTitleFormat.Sprintf("%s", title)
|
|
||||||
if auxInfo == "" {
|
|
||||||
return fmt.Sprintf(subStatusTitleTemplate, title)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(subStatusTitleTemplate+"%s", title, auxInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
spin := color.Magenta.Sprint(spinner.Next())
|
|
||||||
if complete {
|
|
||||||
spin = color.Green.Sprint(completedStatus)
|
|
||||||
}
|
|
||||||
title = titleFormat.Sprintf("%s", title)
|
|
||||||
if auxInfo == "" {
|
|
||||||
return fmt.Sprintf(statusTitleTemplate, spin, title)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
formatFn := func() {
|
|
||||||
if err != nil {
|
|
||||||
_, _ = io.WriteString(line, fmt.Sprintf("Error: %+v", err))
|
|
||||||
} else {
|
|
||||||
auxInfo := auxInfoFormat.Sprintf("[%s]", internal.TruncateMiddleEllipsis(prog.GetValue(), 100))
|
|
||||||
_, _ = io.WriteString(line, formatLine(false, auxInfo))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
formatFn()
|
|
||||||
for range stream {
|
|
||||||
formatFn()
|
|
||||||
}
|
|
||||||
|
|
||||||
if prog.RemoveOnCompletion {
|
|
||||||
_ = fr.Remove(line)
|
|
||||||
} else {
|
|
||||||
_, _ = io.WriteString(line, formatLine(true, ""))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user