Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete pack-interact workflow #1278

Merged
merged 2 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ func (b *Builder) Order() dist.Order {
return b.order
}

// BaseImageName returns the name of the builder base image
func (b *Builder) BaseImageName() string {
return b.baseImageName
}

// Name returns the name of the builder
func (b *Builder) Name() string {
return b.image.Name()
Expand Down
6 changes: 6 additions & 0 deletions internal/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,12 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) {
h.AssertEq(t, bldr.GID(), 4321)
})
})

when("#BaseImageName", func() {
it("return name of base image", func() {
h.AssertEq(t, bldr.BaseImageName(), "base/image")
})
})
})
})
}
Expand Down
143 changes: 143 additions & 0 deletions internal/termui/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package termui

import (
"fmt"

"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"

"github.com/buildpacks/pack/pkg/dist"
)

type Dashboard struct {
app app
appTree *tview.TreeView
builderTree *tview.TreeView
planList *tview.List
logsView *tview.TextView
logs string
}

func NewDashboard(app app, appName string, bldr buildr, runImageName string, buildpackInfo []dist.BuildpackInfo) *Dashboard {
appTree, builderTree := initTrees(appName, bldr, runImageName)

planList, logsView := initDashboard(buildpackInfo)

d := &Dashboard{
app: app,
appTree: appTree,
builderTree: builderTree,
planList: planList,
logsView: logsView,
}

imagesView := tview.NewFlex().
SetDirection(tview.FlexRow).
AddItem(appTree, 0, 1, false).
AddItem(builderTree, 0, 1, true)

imagesView.
SetBorder(true).
SetTitleAlign(tview.AlignLeft).
SetTitle("| [::b]images[::-] |").
SetBackgroundColor(backgroundColor)

leftPane := tview.NewFlex().
SetDirection(tview.FlexRow).
AddItem(imagesView, 11, 0, false).
AddItem(planList, 0, 1, true)

screen := tview.NewFlex().
SetDirection(tview.FlexColumn).
AddItem(leftPane, 0, 1, true).
AddItem(logsView, 0, 1, false)

d.app.SetRoot(screen, true)
return d
}

func (d *Dashboard) Handle(txt string) {
d.app.QueueUpdateDraw(func() {
d.logs = d.logs + txt + "\n"
d.logsView.SetText(tview.TranslateANSI(d.logs))
})
}

func (d *Dashboard) Stop() {
// no-op
}

func initDashboard(buildpackInfos []dist.BuildpackInfo) (*tview.List, *tview.TextView) {
planList := tview.NewList()
planList.SetMainTextColor(tcell.ColorMediumTurquoise).
SetSelectedTextColor(tcell.ColorMediumTurquoise).
SetSelectedBackgroundColor(tcell.ColorDarkSlateGray).
SetSecondaryTextColor(tcell.ColorDimGray).
SetBorder(true).
SetBorderPadding(1, 1, 1, 1).
SetTitle("| [::b]plan[::-] |").
SetTitleAlign(tview.AlignLeft).
SetBackgroundColor(backgroundColor)

for _, buildpackInfo := range buildpackInfos {
planList.AddItem(
buildpackInfo.FullName(),
info(buildpackInfo),
'✔',
func() {},
)
}

logsView := tview.NewTextView()
logsView.SetDynamicColors(true).
SetTextAlign(tview.AlignLeft).
SetBorderPadding(1, 1, 3, 1).
SetTitleAlign(tview.AlignLeft).
SetBackgroundColor(backgroundColor)

return planList, logsView
}

func initTrees(appName string, bldr buildr, runImageName string) (*tview.TreeView, *tview.TreeView) {
var (
appImage = tview.NewTreeNode(fmt.Sprintf("app: [white::b]%s", appName)).SetColor(tcell.ColorDimGray)
appRunImage = tview.NewTreeNode(fmt.Sprintf(" run: [white::b]%s", runImageName)).SetColor(tcell.ColorDimGray)
builderImage = tview.NewTreeNode(fmt.Sprintf("builder: [white::b]%s", bldr.BaseImageName())).SetColor(tcell.ColorDimGray)
lifecycle = tview.NewTreeNode(fmt.Sprintf(" lifecycle: [white::b]%s", bldr.LifecycleDescriptor().Info.Version.String())).SetColor(tcell.ColorDimGray)
runImage = tview.NewTreeNode(fmt.Sprintf(" run: [white::b]%s", bldr.Stack().RunImage.Image)).SetColor(tcell.ColorDimGray)
buildpacks = tview.NewTreeNode(" [mediumturquoise::b]buildpacks")
)

appImage.AddChild(appRunImage)
builderImage.AddChild(lifecycle)
builderImage.AddChild(runImage)
builderImage.AddChild(buildpacks)

appTree := tview.NewTreeView()
appTree.
SetRoot(appImage).
SetGraphics(true).
SetGraphicsColor(tcell.ColorMediumTurquoise).
SetTitleAlign(tview.AlignLeft).
SetBorderPadding(1, 0, 4, 0).
SetBackgroundColor(backgroundColor)

builderTree := tview.NewTreeView()
builderTree.
SetRoot(builderImage).
SetGraphics(true).
SetGraphicsColor(tcell.ColorMediumTurquoise).
SetTitleAlign(tview.AlignLeft).
SetBorderPadding(0, 0, 4, 0).
SetBackgroundColor(backgroundColor)

return appTree, builderTree
}

func info(buildpackInfo dist.BuildpackInfo) string {
if buildpackInfo.Description != "" {
return buildpackInfo.Description
}

return buildpackInfo.Homepage
}
53 changes: 42 additions & 11 deletions internal/termui/detect.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
package termui

import (
"regexp"
"time"

"github.com/rivo/tview"

"github.com/buildpacks/pack/pkg/dist"
)

type Detect struct {
app app
textView *tview.TextView
doneChan chan bool
app app
bldr buildr

textView *tview.TextView
buildpackRegex *regexp.Regexp
buildpackChan chan dist.BuildpackInfo
doneChan chan bool
}

func NewDetect(app app) *Detect {
func NewDetect(app app, buildpackChan chan dist.BuildpackInfo, bldr buildr) *Detect {
d := &Detect{
app: app,
textView: detectStatusTV(app),
doneChan: make(chan bool, 1),
app: app,
textView: detectStatusTV(),
buildpackRegex: regexp.MustCompile(`^(\S+)\s+([\d\.]+)$`),
buildpackChan: buildpackChan,
doneChan: make(chan bool, 1),
bldr: bldr,
}

go d.start()
Expand All @@ -25,6 +35,13 @@ func NewDetect(app app) *Detect {
return d
}

func (d *Detect) Handle(txt string) {
m := d.buildpackRegex.FindStringSubmatch(txt)
if len(m) == 3 {
d.buildpackChan <- d.find(m[1], m[2])
}
}

func (d *Detect) Stop() {
d.doneChan <- true
}
Expand All @@ -45,24 +62,38 @@ func (d *Detect) start() {
for {
select {
case <-ticker.C:
d.textView.SetText(texts[i])
d.app.QueueUpdateDraw(func() {
d.textView.SetText(texts[i])
})

i++
if i == len(texts) {
i = 0
}
case <-d.doneChan:
ticker.Stop()
d.textView.SetText(doneText)

d.app.QueueUpdateDraw(func() {
d.textView.SetText(doneText)
})
return
}
}
}

func detectStatusTV(app app) *tview.TextView {
func (d *Detect) find(buildpackID, buildpackVersion string) dist.BuildpackInfo {
for _, buildpack := range d.bldr.Buildpacks() {
if buildpack.ID == buildpackID && buildpack.Version == buildpackVersion {
return buildpack
}
}

return dist.BuildpackInfo{}
}

func detectStatusTV() *tview.TextView {
tv := tview.NewTextView()
tv.SetBackgroundColor(backgroundColor)
tv.SetChangedFunc(func() { app.Draw() })
return tv
}

Expand Down
10 changes: 10 additions & 0 deletions internal/termui/fakes/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ func (a *App) Draw() *tview.Application {
return nil
}

func (a *App) QueueUpdateDraw(f func()) *tview.Application {
f()
a.DrawCallCount++
return nil
}

func (a *App) Run() error {
<-a.doneChan
return nil
Expand All @@ -35,3 +41,7 @@ func (a *App) Run() error {
func (a *App) StopRunning() {
a.doneChan <- true
}

func (a *App) ResetDrawCount() {
a.DrawCallCount = 0
}
38 changes: 38 additions & 0 deletions internal/termui/fakes/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package fakes

import (
"github.com/buildpacks/pack/internal/builder"
"github.com/buildpacks/pack/pkg/dist"
)

type Builder struct {
baseImageName string
buildpacks []dist.BuildpackInfo
lifecycleDescriptor builder.LifecycleDescriptor
stack builder.StackMetadata
}

func NewBuilder(baseImageName string, buildpacks []dist.BuildpackInfo, lifecycleDescriptor builder.LifecycleDescriptor, stack builder.StackMetadata) *Builder {
return &Builder{
baseImageName: baseImageName,
buildpacks: buildpacks,
lifecycleDescriptor: lifecycleDescriptor,
stack: stack,
}
}

func (b *Builder) BaseImageName() string {
return b.baseImageName
}

func (b *Builder) Buildpacks() []dist.BuildpackInfo {
return b.buildpacks
}

func (b *Builder) LifecycleDescriptor() builder.LifecycleDescriptor {
return b.lifecycleDescriptor
}

func (b *Builder) Stack() builder.StackMetadata {
return b.stack
}
Loading