stop swallowing errors & cleanup exit logic
This commit is contained in:
parent
26d37baabd
commit
d53d8926bc
@ -3,16 +3,15 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/wagoodman/dive/dive"
|
"github.com/wagoodman/dive/dive"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/wagoodman/dive/runtime"
|
"github.com/wagoodman/dive/runtime"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// doAnalyzeCmd takes a docker image tag, digest, or id and displays the
|
// doAnalyzeCmd takes a docker image tag, digest, or id and displays the
|
||||||
// image analysis to the screen
|
// image analysis to the screen
|
||||||
func doAnalyzeCmd(cmd *cobra.Command, args []string) {
|
func doAnalyzeCmd(cmd *cobra.Command, args []string) {
|
||||||
defer utils.Cleanup()
|
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
printVersionFlag, err := cmd.PersistentFlags().GetBool("version")
|
printVersionFlag, err := cmd.PersistentFlags().GetBool("version")
|
||||||
@ -22,13 +21,13 @@ func doAnalyzeCmd(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("No image argument given")
|
fmt.Println("No image argument given")
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
userImage := args[0]
|
userImage := args[0]
|
||||||
if userImage == "" {
|
if userImage == "" {
|
||||||
fmt.Println("No image argument given")
|
fmt.Println("No image argument given")
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
initLogging()
|
initLogging()
|
||||||
@ -37,13 +36,13 @@ func doAnalyzeCmd(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ci configuration error: %v\n", err)
|
fmt.Printf("ci configuration error: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
engine, err := cmd.PersistentFlags().GetString("engine")
|
engine, err := cmd.PersistentFlags().GetString("engine")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("unable to determine engine: %v\n", err)
|
fmt.Printf("unable to determine engine: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.Run(runtime.Options{
|
runtime.Run(runtime.Options{
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/wagoodman/dive/dive"
|
"github.com/wagoodman/dive/dive"
|
||||||
"github.com/wagoodman/dive/runtime"
|
"github.com/wagoodman/dive/runtime"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// buildCmd represents the build command
|
// buildCmd represents the build command
|
||||||
@ -22,8 +21,6 @@ func init() {
|
|||||||
|
|
||||||
// doBuildCmd implements the steps taken for the build command
|
// doBuildCmd implements the steps taken for the build command
|
||||||
func doBuildCmd(cmd *cobra.Command, args []string) {
|
func doBuildCmd(cmd *cobra.Command, args []string) {
|
||||||
defer utils.Cleanup()
|
|
||||||
|
|
||||||
initLogging()
|
initLogging()
|
||||||
|
|
||||||
// there is no cli options allowed, only config can be supplied
|
// there is no cli options allowed, only config can be supplied
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var cfgFile string
|
var cfgFile string
|
||||||
@ -36,9 +35,8 @@ the amount of wasted space and identifies the offending files from the image.`,
|
|||||||
func Execute() {
|
func Execute() {
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
utils.Cleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -160,7 +158,7 @@ func getCfgFile(fromFlag string) string {
|
|||||||
home, err := homedir.Dir()
|
home, err := homedir.Dir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
utils.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
xdgHome := os.Getenv("XDG_CONFIG_HOME")
|
xdgHome := os.Getenv("XDG_CONFIG_HOME")
|
||||||
|
@ -5,9 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/wagoodman/dive/dive/filetree"
|
"github.com/wagoodman/dive/dive/filetree"
|
||||||
"github.com/wagoodman/dive/dive/image"
|
"github.com/wagoodman/dive/dive/image"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ func NewImageArchive(tarFile io.ReadCloser) (*ImageArchive, error) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
name := header.Name
|
name := header.Name
|
||||||
@ -116,8 +116,7 @@ func getFileList(tarReader *tar.Reader) ([]filetree.FileInfo, error) {
|
|||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
fmt.Println(err)
|
return nil, err
|
||||||
utils.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name := header.Name
|
name := header.Name
|
||||||
|
@ -58,7 +58,7 @@ func NewImageDirectoryRef(img *podmanImage.Image) (*ImageDirectoryRef, error) {
|
|||||||
// record the tree and layer info
|
// record the tree and layer info
|
||||||
imgDirRef.treeMap[curImg.ID()] = tree
|
imgDirRef.treeMap[curImg.ID()] = tree
|
||||||
imgDirRef.layerMap[curImg.ID()] = curImg
|
imgDirRef.layerMap[curImg.ID()] = curImg
|
||||||
imgDirRef.layerOrder = append(imgDirRef.layerOrder, curImg.ID())
|
imgDirRef.layerOrder = append([]string{curImg.ID()}, imgDirRef.layerOrder...)
|
||||||
|
|
||||||
// continue to the next image
|
// continue to the next image
|
||||||
curImg, err = curImg.GetParent(ctx)
|
curImg, err = curImg.GetParent(ctx)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/wagoodman/dive/dive"
|
"github.com/wagoodman/dive/dive"
|
||||||
"github.com/wagoodman/dive/runtime/ci"
|
"github.com/wagoodman/dive/runtime/ci"
|
||||||
"github.com/wagoodman/dive/runtime/export"
|
"github.com/wagoodman/dive/runtime/export"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
@ -26,9 +27,9 @@ func runCi(analysis *image.AnalysisResult, options Options) {
|
|||||||
evaluator.Report()
|
evaluator.Report()
|
||||||
|
|
||||||
if pass {
|
if pass {
|
||||||
utils.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(options Options) {
|
func Run(options Options) {
|
||||||
@ -44,7 +45,7 @@ func Run(options Options) {
|
|||||||
imageResolver, err := dive.GetImageHandler(options.Engine)
|
imageResolver, err := dive.GetImageHandler(options.Engine)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot determine image provider: %v\n", err)
|
fmt.Printf("cannot determine image provider: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var img *image.Image
|
var img *image.Image
|
||||||
@ -54,13 +55,13 @@ func Run(options Options) {
|
|||||||
img, err = imageResolver.Build(options.BuildArgs)
|
img, err = imageResolver.Build(options.BuildArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot build image: %v\n", err)
|
fmt.Printf("cannot build image: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
img, err = imageResolver.Fetch(options.ImageId)
|
img, err = imageResolver.Fetch(options.ImageId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot fetch image: %v\n", err)
|
fmt.Printf("cannot fetch image: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,14 +77,14 @@ func Run(options Options) {
|
|||||||
result, err := img.Analyze()
|
result, err := img.Analyze()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot analyze image: %v\n", err)
|
fmt.Printf("cannot analyze image: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if doExport {
|
if doExport {
|
||||||
err = export.NewExport(result).ToFile(options.ExportFile)
|
err = export.NewExport(result).ToFile(options.ExportFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("cannot write export file: %v\n", err)
|
fmt.Printf("cannot write export file: %v\n", err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ func Run(options Options) {
|
|||||||
runCi(result, options)
|
runCi(result, options)
|
||||||
} else {
|
} else {
|
||||||
if doExport {
|
if doExport {
|
||||||
utils.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(utils.TitleFormat("Building cache..."))
|
fmt.Println(utils.TitleFormat("Building cache..."))
|
||||||
@ -99,7 +100,7 @@ func Run(options Options) {
|
|||||||
err := cache.Build()
|
err := cache.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// it appears there is a race condition where termbox.Init() will
|
// it appears there is a race condition where termbox.Init() will
|
||||||
@ -110,11 +111,10 @@ func Run(options Options) {
|
|||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
err = ui.Run(result, cache)
|
err = ui.Run(result, cache)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
utils.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
utils.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package ui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/wagoodman/dive/dive/filetree"
|
"github.com/wagoodman/dive/dive/filetree"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -121,22 +122,29 @@ func (controller *DetailsController) Render() error {
|
|||||||
layerHeaderStr := fmt.Sprintf("[Layer Details]%s", strings.Repeat("─", width-15))
|
layerHeaderStr := fmt.Sprintf("[Layer Details]%s", strings.Repeat("─", width-15))
|
||||||
imageHeaderStr := fmt.Sprintf("[Image Details]%s", strings.Repeat("─", width-15))
|
imageHeaderStr := fmt.Sprintf("[Image Details]%s", strings.Repeat("─", width-15))
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(controller.header, Formatting.Header(vtclean.Clean(layerHeaderStr, false)))
|
_, err := fmt.Fprintln(controller.header, Formatting.Header(vtclean.Clean(layerHeaderStr, false)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// update contents
|
// update contents
|
||||||
controller.view.Clear()
|
controller.view.Clear()
|
||||||
_, _ = fmt.Fprintln(controller.view, Formatting.Header("Digest: ")+currentLayer.Id())
|
|
||||||
_, _ = fmt.Fprintln(controller.view, Formatting.Header("Command:"))
|
|
||||||
_, _ = fmt.Fprintln(controller.view, currentLayer.Command())
|
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(controller.view, "\n"+Formatting.Header(vtclean.Clean(imageHeaderStr, false)))
|
var lines = make([]string, 0)
|
||||||
|
lines = append(lines, Formatting.Header("Digest: ")+currentLayer.Id())
|
||||||
|
lines = append(lines, Formatting.Header("Command:"))
|
||||||
|
lines = append(lines, currentLayer.Command())
|
||||||
|
lines = append(lines, "\n"+Formatting.Header(vtclean.Clean(imageHeaderStr, false)))
|
||||||
|
lines = append(lines, imageSizeStr)
|
||||||
|
lines = append(lines, wastedSpaceStr)
|
||||||
|
lines = append(lines, effStr+"\n")
|
||||||
|
lines = append(lines, inefficiencyReport)
|
||||||
|
|
||||||
_, _ = fmt.Fprintln(controller.view, imageSizeStr)
|
_, err = fmt.Fprintln(controller.view, strings.Join(lines, "\n"))
|
||||||
_, _ = fmt.Fprintln(controller.view, wastedSpaceStr)
|
if err != nil {
|
||||||
_, _ = fmt.Fprintln(controller.view, effStr+"\n")
|
logrus.Debug("unable to write to buffer: ", err)
|
||||||
|
}
|
||||||
_, _ = fmt.Fprintln(controller.view, inefficiencyReport)
|
return err
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -42,15 +42,17 @@ type FileTreeController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFileTreeController creates a new view object attached the the global [gocui] screen object.
|
// NewFileTreeController creates a new view object attached the the global [gocui] screen object.
|
||||||
func NewFileTreeController(name string, gui *gocui.Gui, tree *filetree.FileTree, refTrees []*filetree.FileTree, cache filetree.TreeCache) (controller *FileTreeController) {
|
func NewFileTreeController(name string, gui *gocui.Gui, tree *filetree.FileTree, refTrees []*filetree.FileTree, cache filetree.TreeCache) (controller *FileTreeController, err error) {
|
||||||
controller = new(FileTreeController)
|
controller = new(FileTreeController)
|
||||||
|
|
||||||
// populate main fields
|
// populate main fields
|
||||||
controller.Name = name
|
controller.Name = name
|
||||||
controller.gui = gui
|
controller.gui = gui
|
||||||
controller.vm = NewFileTreeViewModel(tree, refTrees, cache)
|
controller.vm, err = NewFileTreeViewModel(tree, refTrees, cache)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
controller.keybindingToggleCollapse, err = keybinding.ParseAll(viper.GetString("keybinding.toggle-collapse-dir"))
|
controller.keybindingToggleCollapse, err = keybinding.ParseAll(viper.GetString("keybinding.toggle-collapse-dir"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
@ -100,7 +102,7 @@ func NewFileTreeController(name string, gui *gocui.Gui, tree *filetree.FileTree,
|
|||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller
|
return controller, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
||||||
@ -302,19 +304,15 @@ func (controller *FileTreeController) toggleAttributes() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// we need to render the changes to the status pane as well
|
// we need to render the changes to the status pane as well (not just this contoller/view)
|
||||||
Update()
|
return UpdateAndRender()
|
||||||
Render()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggleShowDiffType will show/hide the selected DiffType in the filetree pane.
|
// toggleShowDiffType will show/hide the selected DiffType in the filetree pane.
|
||||||
func (controller *FileTreeController) toggleShowDiffType(diffType filetree.DiffType) error {
|
func (controller *FileTreeController) toggleShowDiffType(diffType filetree.DiffType) error {
|
||||||
controller.vm.toggleShowDiffType(diffType)
|
controller.vm.toggleShowDiffType(diffType)
|
||||||
// we need to render the changes to the status pane as well
|
// we need to render the changes to the status pane as well (not just this contoller/view)
|
||||||
Update()
|
return UpdateAndRender()
|
||||||
Render()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterRegex will return a regular expression object to match the user's filter input.
|
// filterRegex will return a regular expression object to match the user's filter input.
|
||||||
@ -383,10 +381,13 @@ func (controller *FileTreeController) Render() error {
|
|||||||
|
|
||||||
// update the contents
|
// update the contents
|
||||||
controller.view.Clear()
|
controller.view.Clear()
|
||||||
_ = controller.vm.Render()
|
err := controller.vm.Render()
|
||||||
_, _ = fmt.Fprint(controller.view, controller.vm.mainBuf.String())
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = fmt.Fprint(controller.view, controller.vm.mainBuf.String())
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,9 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/lunixbochs/vtclean"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
|
|
||||||
"github.com/lunixbochs/vtclean"
|
|
||||||
"github.com/wagoodman/dive/dive/filetree"
|
"github.com/wagoodman/dive/dive/filetree"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,7 +34,7 @@ type FileTreeViewModel struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFileTreeController creates a new view object attached the the global [gocui] screen object.
|
// NewFileTreeController creates a new view object attached the the global [gocui] screen object.
|
||||||
func NewFileTreeViewModel(tree *filetree.FileTree, refTrees []*filetree.FileTree, cache filetree.TreeCache) (treeViewModel *FileTreeViewModel) {
|
func NewFileTreeViewModel(tree *filetree.FileTree, refTrees []*filetree.FileTree, cache filetree.TreeCache) (treeViewModel *FileTreeViewModel, err error) {
|
||||||
treeViewModel = new(FileTreeViewModel)
|
treeViewModel = new(FileTreeViewModel)
|
||||||
|
|
||||||
// populate main fields
|
// populate main fields
|
||||||
@ -59,11 +57,11 @@ func NewFileTreeViewModel(tree *filetree.FileTree, refTrees []*filetree.FileTree
|
|||||||
case "unmodified":
|
case "unmodified":
|
||||||
treeViewModel.HiddenDiffTypes[filetree.Unmodified] = true
|
treeViewModel.HiddenDiffTypes[filetree.Unmodified] = true
|
||||||
default:
|
default:
|
||||||
utils.PrintAndExit(fmt.Sprintf("unknown diff.hide value: %s", t))
|
return nil, fmt.Errorf("unknown diff.hide value: %s", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return treeViewModel
|
return treeViewModel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
||||||
@ -420,9 +418,17 @@ func (vm *FileTreeViewModel) Render() error {
|
|||||||
vm.mainBuf.Reset()
|
vm.mainBuf.Reset()
|
||||||
for idx, line := range lines {
|
for idx, line := range lines {
|
||||||
if idx == vm.bufferIndex {
|
if idx == vm.bufferIndex {
|
||||||
fmt.Fprintln(&vm.mainBuf, Formatting.Selected(vtclean.Clean(line, false)))
|
_, err := fmt.Fprintln(&vm.mainBuf, Formatting.Selected(vtclean.Clean(line, false)))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("unable to write to buffer: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintln(&vm.mainBuf, line)
|
_, err := fmt.Fprintln(&vm.mainBuf, line)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("unable to write to buffer: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -3,6 +3,7 @@ package ui
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jroimartin/gocui"
|
"github.com/jroimartin/gocui"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FilterController holds the UI objects and data models for populating the bottom row. Specifically the pane that
|
// FilterController holds the UI objects and data models for populating the bottom row. Specifically the pane that
|
||||||
@ -99,9 +100,10 @@ func (controller *FilterController) Update() error {
|
|||||||
// Render flushes the state objects to the screen. Currently this is the users path filter input.
|
// Render flushes the state objects to the screen. Currently this is the users path filter input.
|
||||||
func (controller *FilterController) Render() error {
|
func (controller *FilterController) Render() error {
|
||||||
controller.gui.Update(func(g *gocui.Gui) error {
|
controller.gui.Update(func(g *gocui.Gui) error {
|
||||||
// render the header
|
|
||||||
_, err := fmt.Fprintln(controller.header, Formatting.Header(controller.headerStr))
|
_, err := fmt.Fprintln(controller.header, Formatting.Header(controller.headerStr))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("unable to write to buffer: ", err)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/lunixbochs/vtclean"
|
"github.com/lunixbochs/vtclean"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
"github.com/wagoodman/keybinding"
|
"github.com/wagoodman/keybinding"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,7 +32,7 @@ type LayerController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewLayerController creates a new view object attached the the global [gocui] screen object.
|
// NewLayerController creates a new view object attached the the global [gocui] screen object.
|
||||||
func NewLayerController(name string, gui *gocui.Gui, layers []image.Layer) (controller *LayerController) {
|
func NewLayerController(name string, gui *gocui.Gui, layers []image.Layer) (controller *LayerController, err error) {
|
||||||
controller = new(LayerController)
|
controller = new(LayerController)
|
||||||
|
|
||||||
// populate main fields
|
// populate main fields
|
||||||
@ -47,10 +46,9 @@ func NewLayerController(name string, gui *gocui.Gui, layers []image.Layer) (cont
|
|||||||
case false:
|
case false:
|
||||||
controller.CompareMode = CompareLayer
|
controller.CompareMode = CompareLayer
|
||||||
default:
|
default:
|
||||||
utils.PrintAndExit(fmt.Sprintf("unknown layer.show-aggregated-changes value: %v", mode))
|
return nil, fmt.Errorf("unknown layer.show-aggregated-changes value: %v", mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
controller.keybindingCompareAll, err = keybinding.ParseAll(viper.GetString("keybinding.compare-all"))
|
controller.keybindingCompareAll, err = keybinding.ParseAll(viper.GetString("keybinding.compare-all"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
@ -71,7 +69,7 @@ func NewLayerController(name string, gui *gocui.Gui, layers []image.Layer) (cont
|
|||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller
|
return controller, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
// Setup initializes the UI concerns within the context of a global [gocui] view object.
|
||||||
@ -218,8 +216,11 @@ func (controller *LayerController) currentLayer() image.Layer {
|
|||||||
// setCompareMode switches the layer comparison between a single-layer comparison to an aggregated comparison.
|
// setCompareMode switches the layer comparison between a single-layer comparison to an aggregated comparison.
|
||||||
func (controller *LayerController) setCompareMode(compareMode CompareType) error {
|
func (controller *LayerController) setCompareMode(compareMode CompareType) error {
|
||||||
controller.CompareMode = compareMode
|
controller.CompareMode = compareMode
|
||||||
Update()
|
err := UpdateAndRender()
|
||||||
Render()
|
if err != nil {
|
||||||
|
logrus.Errorf("unable to set compare mode: %+v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
return Controllers.Tree.setTreeByLayer(controller.getCompareIndexes())
|
return Controllers.Tree.setTreeByLayer(controller.getCompareIndexes())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +284,10 @@ func (controller *LayerController) Render() error {
|
|||||||
width, _ := g.Size()
|
width, _ := g.Size()
|
||||||
headerStr := fmt.Sprintf("[%s]%s\n", title, strings.Repeat("─", width*2))
|
headerStr := fmt.Sprintf("[%s]%s\n", title, strings.Repeat("─", width*2))
|
||||||
headerStr += fmt.Sprintf("Cmp"+image.LayerFormat, "Size", "Command")
|
headerStr += fmt.Sprintf("Cmp"+image.LayerFormat, "Size", "Command")
|
||||||
_, _ = fmt.Fprintln(controller.header, Formatting.Header(vtclean.Clean(headerStr, false)))
|
_, err := fmt.Fprintln(controller.header, Formatting.Header(vtclean.Clean(headerStr, false)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// update contents
|
// update contents
|
||||||
controller.view.Clear()
|
controller.view.Clear()
|
||||||
@ -295,9 +299,14 @@ func (controller *LayerController) Render() error {
|
|||||||
compareBar := controller.renderCompareBar(idx)
|
compareBar := controller.renderCompareBar(idx)
|
||||||
|
|
||||||
if idx == controller.LayerIndex {
|
if idx == controller.LayerIndex {
|
||||||
_, _ = fmt.Fprintln(controller.view, compareBar+" "+Formatting.Selected(layerStr))
|
_, err = fmt.Fprintln(controller.view, compareBar+" "+Formatting.Selected(layerStr))
|
||||||
} else {
|
} else {
|
||||||
_, _ = fmt.Fprintln(controller.view, compareBar+" "+layerStr)
|
_, err = fmt.Fprintln(controller.view, compareBar+" "+layerStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("unable to write to buffer: ", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package ui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -61,11 +62,13 @@ func (controller *StatusController) Update() error {
|
|||||||
func (controller *StatusController) Render() error {
|
func (controller *StatusController) Render() error {
|
||||||
controller.gui.Update(func(g *gocui.Gui) error {
|
controller.gui.Update(func(g *gocui.Gui) error {
|
||||||
controller.view.Clear()
|
controller.view.Clear()
|
||||||
_, _ = fmt.Fprintln(controller.view, controller.KeyHelp()+Controllers.lookup[controller.gui.CurrentView().Name()].KeyHelp()+Formatting.StatusNormal("▏"+strings.Repeat(" ", 1000)))
|
_, err := fmt.Fprintln(controller.view, controller.KeyHelp()+Controllers.lookup[controller.gui.CurrentView().Name()].KeyHelp()+Formatting.StatusNormal("▏"+strings.Repeat(" ", 1000)))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("unable to write to buffer: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return err
|
||||||
})
|
})
|
||||||
// todo: blerg
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/wagoodman/dive/dive/filetree"
|
"github.com/wagoodman/dive/dive/filetree"
|
||||||
"github.com/wagoodman/dive/utils"
|
|
||||||
"github.com/wagoodman/keybinding"
|
"github.com/wagoodman/keybinding"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -72,6 +71,22 @@ type View interface {
|
|||||||
IsVisible() bool
|
IsVisible() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateAndRender() error {
|
||||||
|
err := Update()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("failed update: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Render()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debug("failed render: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// toggleView switches between the file view and the layer view and re-renders the screen.
|
// toggleView switches between the file view and the layer view and re-renders the screen.
|
||||||
func toggleView(g *gocui.Gui, v *gocui.View) (err error) {
|
func toggleView(g *gocui.Gui, v *gocui.View) (err error) {
|
||||||
if v == nil || v.Name() == Controllers.Layer.Name {
|
if v == nil || v.Name() == Controllers.Layer.Name {
|
||||||
@ -79,11 +94,15 @@ func toggleView(g *gocui.Gui, v *gocui.View) (err error) {
|
|||||||
} else {
|
} else {
|
||||||
_, err = g.SetCurrentView(Controllers.Layer.Name)
|
_, err = g.SetCurrentView(Controllers.Layer.Name)
|
||||||
}
|
}
|
||||||
Update()
|
|
||||||
Render()
|
if err != nil {
|
||||||
|
logrus.Error("unable to toggle view: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return UpdateAndRender()
|
||||||
|
}
|
||||||
|
|
||||||
// toggleFilterView shows/hides the file tree filter pane.
|
// toggleFilterView shows/hides the file tree filter pane.
|
||||||
func toggleFilterView(g *gocui.Gui, v *gocui.View) error {
|
func toggleFilterView(g *gocui.Gui, v *gocui.View) error {
|
||||||
// delete all user input from the tree view
|
// delete all user input from the tree view
|
||||||
@ -95,13 +114,15 @@ func toggleFilterView(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if !Controllers.Filter.hidden {
|
if !Controllers.Filter.hidden {
|
||||||
_, err := g.SetCurrentView(Controllers.Filter.Name)
|
_, err := g.SetCurrentView(Controllers.Filter.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Error("unable to toggle filter view: ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Update()
|
return UpdateAndRender()
|
||||||
Render()
|
}
|
||||||
} else {
|
|
||||||
err := toggleView(g, v)
|
err := toggleView(g, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Error("unable to toggle filter view (back): ", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +130,7 @@ func toggleFilterView(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -325,9 +346,10 @@ func layout(g *gocui.Gui) error {
|
|||||||
|
|
||||||
// Update refreshes the state objects for future rendering.
|
// Update refreshes the state objects for future rendering.
|
||||||
func Update() error {
|
func Update() error {
|
||||||
for _, view := range Controllers.lookup {
|
for _, controller := range Controllers.lookup {
|
||||||
err := view.Update()
|
err := controller.Update()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logrus.Debug("unable to update controller: ")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,9 +358,9 @@ func Update() error {
|
|||||||
|
|
||||||
// Render flushes the state objects to the screen.
|
// Render flushes the state objects to the screen.
|
||||||
func Render() error {
|
func Render() error {
|
||||||
for _, view := range Controllers.lookup {
|
for _, controller := range Controllers.lookup {
|
||||||
if view.IsVisible() {
|
if controller.IsVisible() {
|
||||||
err := view.Render()
|
err := controller.Render()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -386,19 +408,24 @@ func Run(analysis *image.AnalysisResult, cache filetree.TreeCache) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
utils.SetUi(g)
|
|
||||||
defer g.Close()
|
defer g.Close()
|
||||||
|
|
||||||
Controllers.lookup = make(map[string]View)
|
Controllers.lookup = make(map[string]View)
|
||||||
|
|
||||||
Controllers.Layer = NewLayerController("side", g, analysis.Layers)
|
Controllers.Layer, err = NewLayerController("side", g, analysis.Layers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
Controllers.lookup[Controllers.Layer.Name] = Controllers.Layer
|
Controllers.lookup[Controllers.Layer.Name] = Controllers.Layer
|
||||||
|
|
||||||
treeStack, err := filetree.StackTreeRange(analysis.RefTrees, 0, 0)
|
treeStack, err := filetree.StackTreeRange(analysis.RefTrees, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Controllers.Tree = NewFileTreeController("main", g, treeStack, analysis.RefTrees, cache)
|
Controllers.Tree, err = NewFileTreeController("main", g, treeStack, analysis.RefTrees, cache)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
Controllers.lookup[Controllers.Tree.Name] = Controllers.Tree
|
Controllers.lookup[Controllers.Tree.Name] = Controllers.Tree
|
||||||
|
|
||||||
Controllers.Status = NewStatusController("status", g)
|
Controllers.Status = NewStatusController("status", g)
|
||||||
@ -421,12 +448,7 @@ func Run(analysis *image.AnalysisResult, cache filetree.TreeCache) error {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// perform the first update and render now that all resources have been loaded
|
// perform the first update and render now that all resources have been loaded
|
||||||
err = Update()
|
err = UpdateAndRender()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = Render()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/jroimartin/gocui"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ui *gocui.Gui
|
|
||||||
|
|
||||||
func SetUi(g *gocui.Gui) {
|
|
||||||
ui = g
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrintAndExit(args ...interface{}) {
|
|
||||||
logrus.Println(args...)
|
|
||||||
Cleanup()
|
|
||||||
fmt.Println(args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: this should only be used when exiting from non-gocui code
|
|
||||||
func Exit(rc int) {
|
|
||||||
Cleanup()
|
|
||||||
os.Exit(rc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Cleanup() {
|
|
||||||
if ui != nil {
|
|
||||||
ui.Close()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user