mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 06:56:40 +01:00
Export UI handlers for reuse in other tools (#113)
* export UI handlers for reuse in other tools * bump jotframe to fix cursor issues at frame close
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
stereoEventParsers "github.com/anchore/stereoscope/pkg/event/parsers"
|
||||
"github.com/anchore/syft/internal/ui/common"
|
||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
||||
"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"
|
||||
)
|
||||
|
||||
const maxBarWidth = 50
|
||||
const statusSet = common.SpinnerDotSet // SpinnerCircleOutlineSet
|
||||
const completedStatus = "✔" // "●"
|
||||
const tileFormat = color.Bold
|
||||
const statusTitleTemplate = " %s %-28s "
|
||||
|
||||
var auxInfoFormat = color.HEX("#777777")
|
||||
|
||||
func startProcess() (format.Simple, *common.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 := common.NewSpinner(statusSet)
|
||||
|
||||
return formatter, &spinner
|
||||
}
|
||||
|
||||
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 FetchImage event: %w", err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
formatter, spinner := startProcess()
|
||||
stream := progress.Stream(ctx, prog, 150*time.Millisecond)
|
||||
title := tileFormat.Sprint("Fetching image...")
|
||||
|
||||
for p := range stream {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Fetched image")
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
||||
}()
|
||||
return err
|
||||
}
|
||||
|
||||
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 ReadImage event: %w", err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
formatter, spinner := startProcess()
|
||||
stream := progress.Stream(ctx, prog, 150*time.Millisecond)
|
||||
title := tileFormat.Sprint("Reading image...")
|
||||
|
||||
for p := range stream {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Read image")
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate, spin, title))
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
monitor, err := syftEventParsers.ParseCatalogerStarted(event)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad CatalogerStarted event: %w", err)
|
||||
}
|
||||
|
||||
line, err := fr.Append()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_, spinner := startProcess()
|
||||
stream := progress.StreamMonitors(ctx, []progress.Monitorable{monitor.FilesProcessed, monitor.PackagesDiscovered}, 50*time.Millisecond)
|
||||
title := tileFormat.Sprint("Cataloging image...")
|
||||
|
||||
for p := range stream {
|
||||
spin := color.Magenta.Sprint(spinner.Next())
|
||||
auxInfo := auxInfoFormat.Sprintf("[packages %d]", p[1])
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
||||
}
|
||||
|
||||
spin := color.Green.Sprint(completedStatus)
|
||||
title = tileFormat.Sprint("Cataloged image")
|
||||
auxInfo := auxInfoFormat.Sprintf("[%d packages]", monitor.PackagesDiscovered.Current())
|
||||
_, _ = io.WriteString(line, fmt.Sprintf(statusTitleTemplate+"%s", spin, title, auxInfo))
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
stereoscopeEvent "github.com/anchore/stereoscope/pkg/event"
|
||||
syftEvent "github.com/anchore/syft/syft/event"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/jotframe/pkg/frame"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
}
|
||||
|
||||
func NewHandler() *Handler {
|
||||
return &Handler{}
|
||||
}
|
||||
|
||||
func (r *Handler) RespondsTo(event partybus.Event) bool {
|
||||
switch event.Type {
|
||||
case stereoscopeEvent.ReadImage, stereoscopeEvent.FetchImage, syftEvent.CatalogerStarted:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Handler) Handle(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error {
|
||||
switch event.Type {
|
||||
case stereoscopeEvent.ReadImage:
|
||||
return ReadImageHandler(ctx, fr, event, wg)
|
||||
|
||||
case stereoscopeEvent.FetchImage:
|
||||
return FetchImageHandler(ctx, fr, event, wg)
|
||||
|
||||
case syftEvent.CatalogerStarted:
|
||||
return CatalogerStartedHandler(ctx, fr, event, wg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user