From 24ec0e12105c3e4683beea08053e26c2e3811dd8 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 13:58:07 -0400 Subject: [PATCH 01/30] Use logrus for tui logging --- pkg/app/master/tui/tui.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/app/master/tui/tui.go b/pkg/app/master/tui/tui.go index ab53a915..005999b0 100644 --- a/pkg/app/master/tui/tui.go +++ b/pkg/app/master/tui/tui.go @@ -3,7 +3,7 @@ package tui import ( "os" - "log" + log "github.com/sirupsen/logrus" tea "github.com/charmbracelet/bubbletea" "github.com/mintoolkit/mint/pkg/app/master/tui/common" @@ -17,6 +17,9 @@ func RunTUI(model tea.Model, standalone bool) { os.Exit(1) } defer f.Close() + + log.SetOutput(f) + log.SetLevel(log.DebugLevel) // TODO - should derive log level from `FlagLogLevel` // We are running the tui via `mint tui` if !standalone { common.TUIsInstance.Home = model From 60e0c9995d8072cbbf2a3f10421e366d3dd9ad85 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 13:13:18 -0400 Subject: [PATCH 02/30] Rename model -> tui Signed-off-by: Evan Harris --- pkg/app/master/command/images/{model.go => tui.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/app/master/command/images/{model.go => tui.go} (100%) diff --git a/pkg/app/master/command/images/model.go b/pkg/app/master/command/images/tui.go similarity index 100% rename from pkg/app/master/command/images/model.go rename to pkg/app/master/command/images/tui.go From 567a27ae114be38bde0515f2b2eecaaf60195bac Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 13:14:06 -0400 Subject: [PATCH 03/30] Rename model -> tui Signed-off-by: Evan Harris --- pkg/app/master/tui/home/{model.go => tui.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pkg/app/master/tui/home/{model.go => tui.go} (100%) diff --git a/pkg/app/master/tui/home/model.go b/pkg/app/master/tui/home/tui.go similarity index 100% rename from pkg/app/master/tui/home/model.go rename to pkg/app/master/tui/home/tui.go From aac6e08b21181f088d7a6d2b63ade6dfba35a7c4 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 14:37:15 -0400 Subject: [PATCH 04/30] Add attempt to connect to socket before selecting it as runtime Signed-off-by: Evan Harris --- pkg/crt/runtimes.go | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pkg/crt/runtimes.go b/pkg/crt/runtimes.go index 8c74021d..caa056cd 100644 --- a/pkg/crt/runtimes.go +++ b/pkg/crt/runtimes.go @@ -1,6 +1,11 @@ package crt import ( + "net" + "time" + + log "github.com/sirupsen/logrus" + "os" "strings" @@ -81,7 +86,9 @@ func AvailableRuntimes() []string { if strings.HasPrefix(info.Socket, "/") { if HasSocket(info.Socket) { - usable[info.Name] = struct{}{} + if CanConnect(info.Socket) { + usable[info.Name] = struct{}{} + } } } else { //adding remote paths (for podman and others; without checking, for now) @@ -106,11 +113,12 @@ func AvailableRuntimes() []string { func AutoSelectRuntime() string { available := AvailableRuntimes() + log.Debugf("Available runtimes: %v", available) if len(available) > 0 { return available[0] } - return DockerRuntime + return DockerRuntime // Question -> This runtime may not necessarily be available? } func HasSocket(name string) bool { @@ -121,3 +129,18 @@ func HasSocket(name string) bool { return false } + +func CanConnect(socket string) bool { + timeout := 5 * time.Second + conn, err := net.DialTimeout("unix", socket, timeout) + + if err != nil { + // If there are permission issues, this line will be tripped + // when trying to connect to the socket. + log.Debugf("Error connecting to socket: %s: %v", socket, err) + return false + } + defer conn.Close() + + return true +} From 4418ec7de8451d09b1f7b227074907a59feeee36 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 15:17:28 -0400 Subject: [PATCH 05/30] Add skeleton for selecting runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 116 ++++++++++++++++++++++++++-- pkg/app/master/tui/keys/keys.go | 5 ++ 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 09dc93d5..6e9a38f9 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -1,6 +1,7 @@ package debug import ( + "fmt" "strconv" "github.com/charmbracelet/bubbles/key" @@ -24,8 +25,13 @@ type TUI struct { table table.Table showDebuggableContainers bool + showRuntimeSelectorView bool gcvalues *command.GenericParams + + // runtime selection controls + choice int + chosen bool } // Styles - move to `common` @@ -46,6 +52,8 @@ var ( EvenRowStyle = CellStyle.Foreground(lightGray) // BorderStyle is the lipgloss style used for the table border. BorderStyle = lipgloss.NewStyle().Foreground(white) + // CheckboxStyle is the lipgloss style used for the runtime selector + CheckboxStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("212")) ) // End Styles - move to common - block @@ -183,6 +191,37 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.showDebuggableContainers = !m.showDebuggableContainers return m, nil + case key.Matches(msg, keys.Debug.ChangeRuntime): + m.showRuntimeSelectorView = !m.showRuntimeSelectorView + return m, nil + } + } + // If the user has not made a choice, handle choice updates + if !m.chosen { + return updateChoices(msg, m) + } + // Otherwise... + // TODO - loading state after a user has selected a choice + return m, nil +} + +func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "j", "down": + m.choice++ + if m.choice > 4 { + m.choice = 4 + } + case "k", "up": + m.choice-- + if m.choice < 0 { + m.choice = 0 + } + case "enter": + m.chosen = true + return m, nil } } return m, nil @@ -218,6 +257,55 @@ func generateTable(debuggableContainers []DebuggableContainer) table.Table { return *t } +func choicesView(m TUI) string { + choice := m.choice + + template := "Choose runtime for debug\n\n" + template += "%s\n\n" + choices := fmt.Sprintf( + "%s\n%s\n%s\n%s", + checkbox("Docker", choice == 0), + checkbox("Containerd", choice == 1), + checkbox("Podman", choice == 2), + checkbox("Kubernetes", choice == 3), + ) + return fmt.Sprintf(template, choices) +} + +func checkbox(label string, checked bool) string { + if checked { + return CheckboxStyle.Render("[x] " + label) + } + return fmt.Sprintf("[ ] %s", label) +} + +// NOTE -> the chocies we display here should only be runtiems we can +// establish a connection to. +// Otherwise, we set the user up for failure. +const ( + dockerRuntime = "docker" + containerdRuntime = "containerd" + podmanRuntime = "podman" + kubernetesRuntime = "k8s" +) + +func chosenView(m TUI) string { + var runtime string + + switch m.choice { + case 0: + runtime = dockerRuntime + case 1: + runtime = containerdRuntime + case 2: + runtime = podmanRuntime + case 3: + runtime = kubernetesRuntime + } + + return fmt.Sprintf("You picked - %s :)", runtime) +} + // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -238,6 +326,16 @@ func (m TUI) View() string { components = append(components, header, m.table.String()) } + if m.showRuntimeSelectorView { + var runtimeSelectorContent string + if !m.chosen { + runtimeSelectorContent = choicesView(m) + } else { + runtimeSelectorContent = chosenView(m) + } + components = append(components, runtimeSelectorContent) + } + components = append(components, m.help()) return lipgloss.JoinVertical(lipgloss.Left, @@ -246,17 +344,25 @@ func (m TUI) View() string { } func (m TUI) help() string { - var listOrHide string + var debuggableContainersHelp string if m.showDebuggableContainers { - listOrHide = "hide" + debuggableContainersHelp = "hide" + } else { + debuggableContainersHelp = "list" + } + + var runtimeSelectorHelp string + + if m.showRuntimeSelectorView { + runtimeSelectorHelp = "cancel" } else { - listOrHide = "list" + runtimeSelectorHelp = "change runtime" } if m.standalone { - return common.HelpStyle("• l: " + listOrHide + " debuggable containers • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • q: quit") } - return common.HelpStyle("• l: " + listOrHide + " debuggable containers • esc: back • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") } diff --git a/pkg/app/master/tui/keys/keys.go b/pkg/app/master/tui/keys/keys.go index 9bf9fba4..b5220d7f 100644 --- a/pkg/app/master/tui/keys/keys.go +++ b/pkg/app/master/tui/keys/keys.go @@ -33,6 +33,7 @@ type home struct { type debug struct { LoadDebuggableContainers key.Binding + ChangeRuntime key.Binding } var Home = home{ @@ -51,4 +52,8 @@ var Debug = debug{ key.WithKeys("l"), key.WithHelp("l", "Load debuggable containers"), ), + ChangeRuntime: key.NewBinding( + key.WithKeys("r"), + key.WithHelp("r", "Change runtime"), + ), } From 47e2afc5246d10765690e54698381ca93cedcce8 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 17:58:33 -0400 Subject: [PATCH 06/30] Support state subscription Signed-off-by: Evan Harris --- pkg/app/execontext.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/app/execontext.go b/pkg/app/execontext.go index b390daa9..74ab84fb 100644 --- a/pkg/app/execontext.go +++ b/pkg/app/execontext.go @@ -143,6 +143,7 @@ func NewOutput(cmdName string, quiet bool, outputFormat string, channels map[str // And dump it onto the appropriate DataChannels go func() { for data := range ref.internalDataCh { + log.Debugf("execontext internal data: %v\n", data) if data != nil { for _, ch := range ref.DataChannels { ch <- data @@ -297,7 +298,7 @@ func (ref *Output) Data(channelKey string, data interface{}) { } func (ref *Output) State(state string, params ...OutVars) { - if ref.Quiet { + if ref.Quiet && ref.OutputFormat != ofSubscription { return } @@ -355,6 +356,8 @@ func (ref *Output) State(state string, params ...OutVars) { defer color.Unset() fmt.Printf("cmd=%s state=%s%s%s%s\n", ref.CmdName, state, exitInfo, sep, info) + case ofSubscription: + ref.internalDataCh <- msg // Send data to the internal channel default: log.Fatalf("Unknown console output flag: %s\n. It should be either 'text' or 'json", ref.OutputFormat) From 82a1f704c346ea62bbbbf8d5c6ebd28051317e22 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 17:59:21 -0400 Subject: [PATCH 07/30] Add initial runtime swap support for debug Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 103 ++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6e9a38f9..35b1ab22 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -7,11 +7,13 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" + log "github.com/sirupsen/logrus" "github.com/mintoolkit/mint/pkg/app" "github.com/mintoolkit/mint/pkg/app/master/command" "github.com/mintoolkit/mint/pkg/app/master/tui/common" "github.com/mintoolkit/mint/pkg/app/master/tui/keys" + "github.com/mintoolkit/mint/pkg/crt" tea "github.com/charmbracelet/bubbletea" ) @@ -32,6 +34,8 @@ type TUI struct { // runtime selection controls choice int chosen bool + + runtime string } // Styles - move to `common` @@ -62,7 +66,7 @@ func LoadTUI() *TUI { m := &TUI{ width: 20, height: 15, - loading: true, + runtime: crt.AutoSelectRuntime(), } return m } @@ -74,6 +78,7 @@ func InitialTUI(standalone bool, gcvalues *command.GenericParams) *TUI { width: 20, height: 15, gcvalues: gcvalues, + runtime: crt.AutoSelectRuntime(), } return m @@ -93,6 +98,7 @@ type DebuggableContainer struct { func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case common.Event: + log.Println("==================== UPDATE DEBUG TUI ==========================") debuggableContainersCh := make(chan interface{}) // NOTE -> the names of both the channel map and the channel are misleading // as more than just the debuggable container information is dumped on it @@ -113,10 +119,11 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ) cparams := &CommandParams{ - // NOTE -> should not always pass docker here. - Runtime: "docker", + Runtime: m.runtime, // Note -> we should not pass this by default, and instead pass it when a user asks. ActionListDebuggableContainers: true, + // Passing this all the time does not make sense. + Kubeconfig: crt.KubeconfigDefault, // How to pass the target ref: // TargetRef: "my-nginx" } @@ -139,16 +146,34 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if !ok || channelResponse == nil { continue } + + log.Printf("Channel response in tui: %v", channelResponse) + stateValue, stateExists := channelResponse["state"] + log.Printf("State value: %s", stateValue) + log.Printf("State exists: %s", stateValue) + if stateExists { + if stateValue == "kubernetes.runtime.handler.started" { + log.Println("Got k8s state value") + // break + } else if stateValue == "completed" { + // we get 'completed' then we get 'done' + log.Println("Exiting channel listening loop in update. State is complete.") + break + } + } + infoValue, infoExists := channelResponse["info"] if infoExists { - // Set total debuggable container counter ceiling if infoValue == "debuggable.containers" && counterCeiling == 0 { + // Start docker runtime driven debuggable container handling + // Set total debuggable container counter ceiling countInt, err := strconv.Atoi(channelResponse["count"]) if err != nil { continue } counterCeiling = countInt } else if infoValue == "debuggable.container" { + log.Println("-----------------------Got debuggable container-----------------------") debuggableContainers = append(debuggableContainers, DebuggableContainer{ Name: channelResponse["name"], Image: channelResponse["image"], @@ -157,9 +182,11 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } + // The notion of a count[er] does not exist for the k8s if counterCeiling > 0 && counter == counterCeiling { break } + // End debuggable container handling } m.table = generateTable(debuggableContainers) close(doneCh) @@ -200,6 +227,13 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if !m.chosen { return updateChoices(msg, m) } + // if m.chosen { + + // } + // NEXT UP -> + // After a user has pressed enter: + // Reset the showRuntimeSelectorView -> we no longer want to see `cancel` + // Actually use the new runtime (for what?) // Otherwise... // TODO - loading state after a user has selected a choice return m, nil @@ -211,16 +245,23 @@ func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { switch msg.String() { case "j", "down": m.choice++ - if m.choice > 4 { - m.choice = 4 + if m.choice > 3 { + m.choice = 0 } case "k", "up": m.choice-- if m.choice < 0 { - m.choice = 0 + m.choice = 3 } case "enter": + m.runtime = setNewRuntime(m.choice) m.chosen = true + m.showRuntimeSelectorView = false + // loadDebuggableContainers := common.Event{ + // Type: common.LaunchDebugEvent, + // Data: m.gcvalues, + // } + // m, _ := m.Update(loadDebuggableContainers) return m, nil } } @@ -282,30 +323,33 @@ func checkbox(label string, checked bool) string { // NOTE -> the chocies we display here should only be runtiems we can // establish a connection to. // Otherwise, we set the user up for failure. -const ( - dockerRuntime = "docker" - containerdRuntime = "containerd" - podmanRuntime = "podman" - kubernetesRuntime = "k8s" -) - -func chosenView(m TUI) string { - var runtime string - - switch m.choice { +// const ( +// dockerRuntime = "docker" +// containerdRuntime = "containerd" +// podmanRuntime = "podman" +// kubernetesRuntime = "k8s" +// ) + +func setNewRuntime(choice int) string { + switch choice { case 0: - runtime = dockerRuntime + return crt.DockerRuntime case 1: - runtime = containerdRuntime + return crt.ContainerdRuntime case 2: - runtime = podmanRuntime + return crt.PodmanRuntime case 3: - runtime = kubernetesRuntime + return crt.KubernetesRuntime + default: + return crt.AutoRuntime } - - return fmt.Sprintf("You picked - %s :)", runtime) } +// func chosenView(m TUI) string { + +// return fmt.Sprintf("Loading %s runtime...", m.runtime) +// } + // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -317,9 +361,11 @@ func (m TUI) View() string { // 4. Connect to a debug session // 5. Start a new debug session - content := "Debug Dashboard\n" + header := "Debug Dashboard\n" + + currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) // TODO - map to human readable - components = append(components, content) + components = append(components, header, currentRuntime) if m.showDebuggableContainers { header := "Debuggable Containers\n" @@ -330,9 +376,10 @@ func (m TUI) View() string { var runtimeSelectorContent string if !m.chosen { runtimeSelectorContent = choicesView(m) - } else { - runtimeSelectorContent = chosenView(m) } + // else { + // runtimeSelectorContent = chosenView(m) + // } components = append(components, runtimeSelectorContent) } From b155c90e45051b2fcbe7adf1f09a7c72328d4527 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:44:10 -0400 Subject: [PATCH 08/30] Only display runtime picker controls when select is displayed Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 35b1ab22..2808b007 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -402,13 +402,14 @@ func (m TUI) help() string { var runtimeSelectorHelp string if m.showRuntimeSelectorView { - runtimeSelectorHelp = "cancel" + // Only display the navigation controls if the using is changing their runtime + runtimeSelectorHelp = "cancel • j/k, up/down: select • enter: choose" } else { runtimeSelectorHelp = "change runtime" } if m.standalone { - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • q: quit") } return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") From 631d2aaeea3ab44ae6f87caa30e83ce639663527 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:48:42 -0400 Subject: [PATCH 09/30] Do not return Home model in standalone mode Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 2808b007..b168adfd 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -202,6 +202,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // NOTE -> We should only support this back navigation, // if the tui is not in standalone mode. case key.Matches(msg, keys.Global.Back): + if m.standalone { + return m, nil + } return common.TUIsInstance.Home, nil case key.Matches(msg, keys.Debug.LoadDebuggableContainers): // Kickoff loading of debuggable containers in standalone mode. From dc36c5803701597b7266e19057ce230c50146069 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:48:59 -0400 Subject: [PATCH 10/30] Rm dead wood comment Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index b168adfd..2a8e37a3 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -199,8 +199,6 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch { case key.Matches(msg, keys.Global.Quit): return m, tea.Quit - // NOTE -> We should only support this back navigation, - // if the tui is not in standalone mode. case key.Matches(msg, keys.Global.Back): if m.standalone { return m, nil From 6329a56cd694ae51dda79bec8aeb4c38421a9c4b Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:54:24 -0400 Subject: [PATCH 11/30] Remove the notion of 'chosen' Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 34 ++--------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 2a8e37a3..e0a4f6c0 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -33,7 +33,6 @@ type TUI struct { // runtime selection controls choice int - chosen bool runtime string } @@ -224,20 +223,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } } - // If the user has not made a choice, handle choice updates - if !m.chosen { - return updateChoices(msg, m) - } - // if m.chosen { - - // } - // NEXT UP -> - // After a user has pressed enter: - // Reset the showRuntimeSelectorView -> we no longer want to see `cancel` - // Actually use the new runtime (for what?) - // Otherwise... - // TODO - loading state after a user has selected a choice - return m, nil + return updateChoices(msg, m) } func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { @@ -256,13 +242,7 @@ func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { } case "enter": m.runtime = setNewRuntime(m.choice) - m.chosen = true m.showRuntimeSelectorView = false - // loadDebuggableContainers := common.Event{ - // Type: common.LaunchDebugEvent, - // Data: m.gcvalues, - // } - // m, _ := m.Update(loadDebuggableContainers) return m, nil } } @@ -346,11 +326,6 @@ func setNewRuntime(choice int) string { } } -// func chosenView(m TUI) string { - -// return fmt.Sprintf("Loading %s runtime...", m.runtime) -// } - // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -375,12 +350,7 @@ func (m TUI) View() string { if m.showRuntimeSelectorView { var runtimeSelectorContent string - if !m.chosen { - runtimeSelectorContent = choicesView(m) - } - // else { - // runtimeSelectorContent = chosenView(m) - // } + runtimeSelectorContent = choicesView(m) components = append(components, runtimeSelectorContent) } From b928d52cbb18e9a11b77a6b941ff5360d1e7c778 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 16:00:04 -0400 Subject: [PATCH 12/30] Hide debuggable containers when changing runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index e0a4f6c0..6c08435b 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -219,6 +219,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case key.Matches(msg, keys.Debug.ChangeRuntime): + m.showDebuggableContainers = false m.showRuntimeSelectorView = !m.showRuntimeSelectorView return m, nil } @@ -362,26 +363,26 @@ func (m TUI) View() string { } func (m TUI) help() string { - var debuggableContainersHelp string - - if m.showDebuggableContainers { - debuggableContainersHelp = "hide" - } else { - debuggableContainersHelp = "list" - } - - var runtimeSelectorHelp string + var debuggableContainersHelp, runtimeSelectorHelp string if m.showRuntimeSelectorView { // Only display the navigation controls if the using is changing their runtime runtimeSelectorHelp = "cancel • j/k, up/down: select • enter: choose" } else { runtimeSelectorHelp = "change runtime" + + // Hide debuggable container help when selecting runtime + if m.showDebuggableContainers { + debuggableContainersHelp = "• l: hide debuggable containers" + } else { + debuggableContainersHelp = "• l: list debuggable containers" + } + } if m.standalone { - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • q: quit") } - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") } From 7690c68f3fce171db6250181bb7d597157cc7997 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 16:04:53 -0400 Subject: [PATCH 13/30] Swallow l keypress while selecting runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6c08435b..ee48ae5d 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -204,6 +204,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } return common.TUIsInstance.Home, nil case key.Matches(msg, keys.Debug.LoadDebuggableContainers): + if m.showRuntimeSelectorView { + return m, nil + } // Kickoff loading of debuggable containers in standalone mode. if m.standalone { loadDebuggableContainers := common.Event{ From f0b7904bbce6e34f4b656735c629b1c41d3bbe6d Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:15:02 -0400 Subject: [PATCH 14/30] Cleanup comments, logging and variable naming Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 50 ++++++++++++----------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index ee48ae5d..6dee9216 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -97,24 +97,21 @@ type DebuggableContainer struct { func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case common.Event: - log.Println("==================== UPDATE DEBUG TUI ==========================") - debuggableContainersCh := make(chan interface{}) + subscriptionChannel := make(chan interface{}) // NOTE -> the names of both the channel map and the channel are misleading // as more than just the debuggable container information is dumped on it // at the moment. - debuggableContainersChannelMap := map[string]chan interface{}{ - "debuggableContainers": debuggableContainersCh, + subscriptionChannels := map[string]chan interface{}{ + "debuggableContainers": subscriptionChannel, } // In addition to passing the channel(s) we will use to transport data // we should pass: // the outputs we want to subscribe to: State | Info | Error xc := app.NewExecutionContext( "tui", - // Quiet -> when set to true, returns on the first line for each - // Execution context method true, "subscription", - debuggableContainersChannelMap, + subscriptionChannels, ) cparams := &CommandParams{ @@ -140,23 +137,22 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { doneCh := make(chan struct{}) go func() { - for debuggableContainersData := range debuggableContainersCh { - channelResponse, ok := debuggableContainersData.(map[string]string) + for subscriptionData := range subscriptionChannel { + channelResponse, ok := subscriptionData.(map[string]string) if !ok || channelResponse == nil { continue } - log.Printf("Channel response in tui: %v", channelResponse) + log.Debugf("Channel response in tui: %v", channelResponse) stateValue, stateExists := channelResponse["state"] - log.Printf("State value: %s", stateValue) - log.Printf("State exists: %s", stateValue) if stateExists { + log.Debugf("State value: %s", stateValue) if stateValue == "kubernetes.runtime.handler.started" { - log.Println("Got k8s state value") - // break + // TODO - what would we like to do with this information? + // && we likely will want to add similar handling for the other runtimes. } else if stateValue == "completed" { - // we get 'completed' then we get 'done' - log.Println("Exiting channel listening loop in update. State is complete.") + // We get 'completed' then we get 'done' + log.Debug("Exiting channel listening loop in update. State is complete.") break } } @@ -172,7 +168,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } counterCeiling = countInt } else if infoValue == "debuggable.container" { - log.Println("-----------------------Got debuggable container-----------------------") + log.Debugln("-----------------------Got debuggable container-----------------------") debuggableContainers = append(debuggableContainers, DebuggableContainer{ Name: channelResponse["name"], Image: channelResponse["image"], @@ -182,6 +178,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // The notion of a count[er] does not exist for the k8s + // But it does for podman & docker. if counterCeiling > 0 && counter == counterCeiling { break } @@ -286,8 +283,13 @@ func generateTable(debuggableContainers []DebuggableContainer) table.Table { func choicesView(m TUI) string { choice := m.choice - template := "Choose runtime for debug\n\n" + template := "Choose runtime for debug mode\n\n" template += "%s\n\n" + + // NOTE -> the chocies we display here should only be runtiems we can + // establish a connection to. + // Otherwise, we set the user up for failure. + choices := fmt.Sprintf( "%s\n%s\n%s\n%s", checkbox("Docker", choice == 0), @@ -305,16 +307,6 @@ func checkbox(label string, checked bool) string { return fmt.Sprintf("[ ] %s", label) } -// NOTE -> the chocies we display here should only be runtiems we can -// establish a connection to. -// Otherwise, we set the user up for failure. -// const ( -// dockerRuntime = "docker" -// containerdRuntime = "containerd" -// podmanRuntime = "podman" -// kubernetesRuntime = "k8s" -// ) - func setNewRuntime(choice int) string { switch choice { case 0: @@ -343,7 +335,7 @@ func (m TUI) View() string { header := "Debug Dashboard\n" - currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) // TODO - map to human readable + currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) components = append(components, header, currentRuntime) From 89b3487dc63b39ce4b50a8093e3d16b5b78f0b22 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:35:10 -0400 Subject: [PATCH 15/30] Use default namespace Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6dee9216..81dce5d4 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -116,12 +116,10 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cparams := &CommandParams{ Runtime: m.runtime, - // Note -> we should not pass this by default, and instead pass it when a user asks. + // Passing these three fields all the time does not make sense. ActionListDebuggableContainers: true, - // Passing this all the time does not make sense. - Kubeconfig: crt.KubeconfigDefault, - // How to pass the target ref: - // TargetRef: "my-nginx" + Kubeconfig: crt.KubeconfigDefault, + TargetNamespace: "default", } gcValue, ok := msg.Data.(*command.GenericParams) From 4fb097fad8a998367ea812013bdfed834b419012 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:36:25 -0400 Subject: [PATCH 16/30] Add state output to the start of the kubenetes runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/handle_kubernetes_runtime.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/app/master/command/debug/handle_kubernetes_runtime.go b/pkg/app/master/command/debug/handle_kubernetes_runtime.go index 72f729a8..8689066f 100644 --- a/pkg/app/master/command/debug/handle_kubernetes_runtime.go +++ b/pkg/app/master/command/debug/handle_kubernetes_runtime.go @@ -44,6 +44,7 @@ func HandleKubernetesRuntime( log.Fields{ "op": "debug.HandleKubernetesRuntime", }) + xc.Out.State("kubernetes.runtime.handler.started") cpJson, _ := json.Marshal(commandParams) logger.WithField("cparams", string(cpJson)).Trace("call") From 875a028b600bfb876fb09316f1346618d2e1504f Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 20:00:03 -0400 Subject: [PATCH 17/30] Support tui -> d entrypoint Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 27 +++++---------------------- pkg/app/master/tui/home/tui.go | 6 +++--- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 81dce5d4..f8df56d9 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -61,15 +61,6 @@ var ( // End Styles - move to common - block -func LoadTUI() *TUI { - m := &TUI{ - width: 20, - height: 15, - runtime: crt.AutoSelectRuntime(), - } - return m -} - // InitialTUI returns the initial state of the model. func InitialTUI(standalone bool, gcvalues *command.GenericParams) *TUI { m := &TUI{ @@ -202,20 +193,12 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.showRuntimeSelectorView { return m, nil } - // Kickoff loading of debuggable containers in standalone mode. - if m.standalone { - loadDebuggableContainers := common.Event{ - Type: common.LaunchDebugEvent, - Data: m.gcvalues, - } - m, _ := m.Update(loadDebuggableContainers) - return m, nil + loadDebuggableContainers := common.Event{ + Type: common.LaunchDebugEvent, + Data: m.gcvalues, } - - // When used via `tui -> debug` - m.showDebuggableContainers = !m.showDebuggableContainers + m, _ := m.Update(loadDebuggableContainers) return m, nil - case key.Matches(msg, keys.Debug.ChangeRuntime): m.showDebuggableContainers = false m.showRuntimeSelectorView = !m.showRuntimeSelectorView @@ -377,5 +360,5 @@ func (m TUI) help() string { return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • q: quit") } - return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • esc: back • q: quit") } diff --git a/pkg/app/master/tui/home/tui.go b/pkg/app/master/tui/home/tui.go index ee898c07..0d0cd5b4 100644 --- a/pkg/app/master/tui/home/tui.go +++ b/pkg/app/master/tui/home/tui.go @@ -51,9 +51,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { Data: m.Gcvalues, } - LoadTUI := debug.LoadTUI() - common.TUIsInstance.Debug = LoadTUI - return LoadTUI.Update(launchDebugEvent) + initialTUI := debug.InitialTUI(false, m.Gcvalues) + common.TUIsInstance.Debug = initialTUI + return initialTUI.Update(launchDebugEvent) } } return m, nil From 6427a59556b02c8279b75678846966d1085923bd Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 15:17:28 -0400 Subject: [PATCH 18/30] Add skeleton for selecting runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 116 ++++++++++++++++++++++++++-- pkg/app/master/tui/keys/keys.go | 5 ++ 2 files changed, 116 insertions(+), 5 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 09dc93d5..6e9a38f9 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -1,6 +1,7 @@ package debug import ( + "fmt" "strconv" "github.com/charmbracelet/bubbles/key" @@ -24,8 +25,13 @@ type TUI struct { table table.Table showDebuggableContainers bool + showRuntimeSelectorView bool gcvalues *command.GenericParams + + // runtime selection controls + choice int + chosen bool } // Styles - move to `common` @@ -46,6 +52,8 @@ var ( EvenRowStyle = CellStyle.Foreground(lightGray) // BorderStyle is the lipgloss style used for the table border. BorderStyle = lipgloss.NewStyle().Foreground(white) + // CheckboxStyle is the lipgloss style used for the runtime selector + CheckboxStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("212")) ) // End Styles - move to common - block @@ -183,6 +191,37 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.showDebuggableContainers = !m.showDebuggableContainers return m, nil + case key.Matches(msg, keys.Debug.ChangeRuntime): + m.showRuntimeSelectorView = !m.showRuntimeSelectorView + return m, nil + } + } + // If the user has not made a choice, handle choice updates + if !m.chosen { + return updateChoices(msg, m) + } + // Otherwise... + // TODO - loading state after a user has selected a choice + return m, nil +} + +func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "j", "down": + m.choice++ + if m.choice > 4 { + m.choice = 4 + } + case "k", "up": + m.choice-- + if m.choice < 0 { + m.choice = 0 + } + case "enter": + m.chosen = true + return m, nil } } return m, nil @@ -218,6 +257,55 @@ func generateTable(debuggableContainers []DebuggableContainer) table.Table { return *t } +func choicesView(m TUI) string { + choice := m.choice + + template := "Choose runtime for debug\n\n" + template += "%s\n\n" + choices := fmt.Sprintf( + "%s\n%s\n%s\n%s", + checkbox("Docker", choice == 0), + checkbox("Containerd", choice == 1), + checkbox("Podman", choice == 2), + checkbox("Kubernetes", choice == 3), + ) + return fmt.Sprintf(template, choices) +} + +func checkbox(label string, checked bool) string { + if checked { + return CheckboxStyle.Render("[x] " + label) + } + return fmt.Sprintf("[ ] %s", label) +} + +// NOTE -> the chocies we display here should only be runtiems we can +// establish a connection to. +// Otherwise, we set the user up for failure. +const ( + dockerRuntime = "docker" + containerdRuntime = "containerd" + podmanRuntime = "podman" + kubernetesRuntime = "k8s" +) + +func chosenView(m TUI) string { + var runtime string + + switch m.choice { + case 0: + runtime = dockerRuntime + case 1: + runtime = containerdRuntime + case 2: + runtime = podmanRuntime + case 3: + runtime = kubernetesRuntime + } + + return fmt.Sprintf("You picked - %s :)", runtime) +} + // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -238,6 +326,16 @@ func (m TUI) View() string { components = append(components, header, m.table.String()) } + if m.showRuntimeSelectorView { + var runtimeSelectorContent string + if !m.chosen { + runtimeSelectorContent = choicesView(m) + } else { + runtimeSelectorContent = chosenView(m) + } + components = append(components, runtimeSelectorContent) + } + components = append(components, m.help()) return lipgloss.JoinVertical(lipgloss.Left, @@ -246,17 +344,25 @@ func (m TUI) View() string { } func (m TUI) help() string { - var listOrHide string + var debuggableContainersHelp string if m.showDebuggableContainers { - listOrHide = "hide" + debuggableContainersHelp = "hide" + } else { + debuggableContainersHelp = "list" + } + + var runtimeSelectorHelp string + + if m.showRuntimeSelectorView { + runtimeSelectorHelp = "cancel" } else { - listOrHide = "list" + runtimeSelectorHelp = "change runtime" } if m.standalone { - return common.HelpStyle("• l: " + listOrHide + " debuggable containers • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • q: quit") } - return common.HelpStyle("• l: " + listOrHide + " debuggable containers • esc: back • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") } diff --git a/pkg/app/master/tui/keys/keys.go b/pkg/app/master/tui/keys/keys.go index 9bf9fba4..b5220d7f 100644 --- a/pkg/app/master/tui/keys/keys.go +++ b/pkg/app/master/tui/keys/keys.go @@ -33,6 +33,7 @@ type home struct { type debug struct { LoadDebuggableContainers key.Binding + ChangeRuntime key.Binding } var Home = home{ @@ -51,4 +52,8 @@ var Debug = debug{ key.WithKeys("l"), key.WithHelp("l", "Load debuggable containers"), ), + ChangeRuntime: key.NewBinding( + key.WithKeys("r"), + key.WithHelp("r", "Change runtime"), + ), } From 800556d90fea8429f376eb78fa75ca4c21b1789a Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 17:58:33 -0400 Subject: [PATCH 19/30] Support state subscription Signed-off-by: Evan Harris --- pkg/app/execontext.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/app/execontext.go b/pkg/app/execontext.go index b390daa9..74ab84fb 100644 --- a/pkg/app/execontext.go +++ b/pkg/app/execontext.go @@ -143,6 +143,7 @@ func NewOutput(cmdName string, quiet bool, outputFormat string, channels map[str // And dump it onto the appropriate DataChannels go func() { for data := range ref.internalDataCh { + log.Debugf("execontext internal data: %v\n", data) if data != nil { for _, ch := range ref.DataChannels { ch <- data @@ -297,7 +298,7 @@ func (ref *Output) Data(channelKey string, data interface{}) { } func (ref *Output) State(state string, params ...OutVars) { - if ref.Quiet { + if ref.Quiet && ref.OutputFormat != ofSubscription { return } @@ -355,6 +356,8 @@ func (ref *Output) State(state string, params ...OutVars) { defer color.Unset() fmt.Printf("cmd=%s state=%s%s%s%s\n", ref.CmdName, state, exitInfo, sep, info) + case ofSubscription: + ref.internalDataCh <- msg // Send data to the internal channel default: log.Fatalf("Unknown console output flag: %s\n. It should be either 'text' or 'json", ref.OutputFormat) From 00bb416fd05e10b8e9870059551b466e893cf73b Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Mon, 28 Oct 2024 17:59:21 -0400 Subject: [PATCH 20/30] Add initial runtime swap support for debug Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 103 ++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6e9a38f9..35b1ab22 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -7,11 +7,13 @@ import ( "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss/table" + log "github.com/sirupsen/logrus" "github.com/mintoolkit/mint/pkg/app" "github.com/mintoolkit/mint/pkg/app/master/command" "github.com/mintoolkit/mint/pkg/app/master/tui/common" "github.com/mintoolkit/mint/pkg/app/master/tui/keys" + "github.com/mintoolkit/mint/pkg/crt" tea "github.com/charmbracelet/bubbletea" ) @@ -32,6 +34,8 @@ type TUI struct { // runtime selection controls choice int chosen bool + + runtime string } // Styles - move to `common` @@ -62,7 +66,7 @@ func LoadTUI() *TUI { m := &TUI{ width: 20, height: 15, - loading: true, + runtime: crt.AutoSelectRuntime(), } return m } @@ -74,6 +78,7 @@ func InitialTUI(standalone bool, gcvalues *command.GenericParams) *TUI { width: 20, height: 15, gcvalues: gcvalues, + runtime: crt.AutoSelectRuntime(), } return m @@ -93,6 +98,7 @@ type DebuggableContainer struct { func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case common.Event: + log.Println("==================== UPDATE DEBUG TUI ==========================") debuggableContainersCh := make(chan interface{}) // NOTE -> the names of both the channel map and the channel are misleading // as more than just the debuggable container information is dumped on it @@ -113,10 +119,11 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ) cparams := &CommandParams{ - // NOTE -> should not always pass docker here. - Runtime: "docker", + Runtime: m.runtime, // Note -> we should not pass this by default, and instead pass it when a user asks. ActionListDebuggableContainers: true, + // Passing this all the time does not make sense. + Kubeconfig: crt.KubeconfigDefault, // How to pass the target ref: // TargetRef: "my-nginx" } @@ -139,16 +146,34 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if !ok || channelResponse == nil { continue } + + log.Printf("Channel response in tui: %v", channelResponse) + stateValue, stateExists := channelResponse["state"] + log.Printf("State value: %s", stateValue) + log.Printf("State exists: %s", stateValue) + if stateExists { + if stateValue == "kubernetes.runtime.handler.started" { + log.Println("Got k8s state value") + // break + } else if stateValue == "completed" { + // we get 'completed' then we get 'done' + log.Println("Exiting channel listening loop in update. State is complete.") + break + } + } + infoValue, infoExists := channelResponse["info"] if infoExists { - // Set total debuggable container counter ceiling if infoValue == "debuggable.containers" && counterCeiling == 0 { + // Start docker runtime driven debuggable container handling + // Set total debuggable container counter ceiling countInt, err := strconv.Atoi(channelResponse["count"]) if err != nil { continue } counterCeiling = countInt } else if infoValue == "debuggable.container" { + log.Println("-----------------------Got debuggable container-----------------------") debuggableContainers = append(debuggableContainers, DebuggableContainer{ Name: channelResponse["name"], Image: channelResponse["image"], @@ -157,9 +182,11 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } } + // The notion of a count[er] does not exist for the k8s if counterCeiling > 0 && counter == counterCeiling { break } + // End debuggable container handling } m.table = generateTable(debuggableContainers) close(doneCh) @@ -200,6 +227,13 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if !m.chosen { return updateChoices(msg, m) } + // if m.chosen { + + // } + // NEXT UP -> + // After a user has pressed enter: + // Reset the showRuntimeSelectorView -> we no longer want to see `cancel` + // Actually use the new runtime (for what?) // Otherwise... // TODO - loading state after a user has selected a choice return m, nil @@ -211,16 +245,23 @@ func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { switch msg.String() { case "j", "down": m.choice++ - if m.choice > 4 { - m.choice = 4 + if m.choice > 3 { + m.choice = 0 } case "k", "up": m.choice-- if m.choice < 0 { - m.choice = 0 + m.choice = 3 } case "enter": + m.runtime = setNewRuntime(m.choice) m.chosen = true + m.showRuntimeSelectorView = false + // loadDebuggableContainers := common.Event{ + // Type: common.LaunchDebugEvent, + // Data: m.gcvalues, + // } + // m, _ := m.Update(loadDebuggableContainers) return m, nil } } @@ -282,30 +323,33 @@ func checkbox(label string, checked bool) string { // NOTE -> the chocies we display here should only be runtiems we can // establish a connection to. // Otherwise, we set the user up for failure. -const ( - dockerRuntime = "docker" - containerdRuntime = "containerd" - podmanRuntime = "podman" - kubernetesRuntime = "k8s" -) - -func chosenView(m TUI) string { - var runtime string - - switch m.choice { +// const ( +// dockerRuntime = "docker" +// containerdRuntime = "containerd" +// podmanRuntime = "podman" +// kubernetesRuntime = "k8s" +// ) + +func setNewRuntime(choice int) string { + switch choice { case 0: - runtime = dockerRuntime + return crt.DockerRuntime case 1: - runtime = containerdRuntime + return crt.ContainerdRuntime case 2: - runtime = podmanRuntime + return crt.PodmanRuntime case 3: - runtime = kubernetesRuntime + return crt.KubernetesRuntime + default: + return crt.AutoRuntime } - - return fmt.Sprintf("You picked - %s :)", runtime) } +// func chosenView(m TUI) string { + +// return fmt.Sprintf("Loading %s runtime...", m.runtime) +// } + // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -317,9 +361,11 @@ func (m TUI) View() string { // 4. Connect to a debug session // 5. Start a new debug session - content := "Debug Dashboard\n" + header := "Debug Dashboard\n" + + currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) // TODO - map to human readable - components = append(components, content) + components = append(components, header, currentRuntime) if m.showDebuggableContainers { header := "Debuggable Containers\n" @@ -330,9 +376,10 @@ func (m TUI) View() string { var runtimeSelectorContent string if !m.chosen { runtimeSelectorContent = choicesView(m) - } else { - runtimeSelectorContent = chosenView(m) } + // else { + // runtimeSelectorContent = chosenView(m) + // } components = append(components, runtimeSelectorContent) } From 6ad93fabfc2c2e84a20cb8f64357192b23175ef7 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:44:10 -0400 Subject: [PATCH 21/30] Only display runtime picker controls when select is displayed Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 35b1ab22..2808b007 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -402,13 +402,14 @@ func (m TUI) help() string { var runtimeSelectorHelp string if m.showRuntimeSelectorView { - runtimeSelectorHelp = "cancel" + // Only display the navigation controls if the using is changing their runtime + runtimeSelectorHelp = "cancel • j/k, up/down: select • enter: choose" } else { runtimeSelectorHelp = "change runtime" } if m.standalone { - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • q: quit") + return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • q: quit") } return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") From 355b8acbe8aac577209864993ef84c291948b7da Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:48:42 -0400 Subject: [PATCH 22/30] Do not return Home model in standalone mode Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 2808b007..b168adfd 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -202,6 +202,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // NOTE -> We should only support this back navigation, // if the tui is not in standalone mode. case key.Matches(msg, keys.Global.Back): + if m.standalone { + return m, nil + } return common.TUIsInstance.Home, nil case key.Matches(msg, keys.Debug.LoadDebuggableContainers): // Kickoff loading of debuggable containers in standalone mode. From 385aa41b99b5657d55c9fe288f4a3d6049b7f25b Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:48:59 -0400 Subject: [PATCH 23/30] Rm dead wood comment Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index b168adfd..2a8e37a3 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -199,8 +199,6 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch { case key.Matches(msg, keys.Global.Quit): return m, tea.Quit - // NOTE -> We should only support this back navigation, - // if the tui is not in standalone mode. case key.Matches(msg, keys.Global.Back): if m.standalone { return m, nil From f7752217f19c7f8c54aa8501e62ef7d714dac6ac Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 15:54:24 -0400 Subject: [PATCH 24/30] Remove the notion of 'chosen' Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 34 ++--------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 2a8e37a3..e0a4f6c0 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -33,7 +33,6 @@ type TUI struct { // runtime selection controls choice int - chosen bool runtime string } @@ -224,20 +223,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } } - // If the user has not made a choice, handle choice updates - if !m.chosen { - return updateChoices(msg, m) - } - // if m.chosen { - - // } - // NEXT UP -> - // After a user has pressed enter: - // Reset the showRuntimeSelectorView -> we no longer want to see `cancel` - // Actually use the new runtime (for what?) - // Otherwise... - // TODO - loading state after a user has selected a choice - return m, nil + return updateChoices(msg, m) } func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { @@ -256,13 +242,7 @@ func updateChoices(msg tea.Msg, m TUI) (tea.Model, tea.Cmd) { } case "enter": m.runtime = setNewRuntime(m.choice) - m.chosen = true m.showRuntimeSelectorView = false - // loadDebuggableContainers := common.Event{ - // Type: common.LaunchDebugEvent, - // Data: m.gcvalues, - // } - // m, _ := m.Update(loadDebuggableContainers) return m, nil } } @@ -346,11 +326,6 @@ func setNewRuntime(choice int) string { } } -// func chosenView(m TUI) string { - -// return fmt.Sprintf("Loading %s runtime...", m.runtime) -// } - // View returns the view that should be displayed. func (m TUI) View() string { var components []string @@ -375,12 +350,7 @@ func (m TUI) View() string { if m.showRuntimeSelectorView { var runtimeSelectorContent string - if !m.chosen { - runtimeSelectorContent = choicesView(m) - } - // else { - // runtimeSelectorContent = chosenView(m) - // } + runtimeSelectorContent = choicesView(m) components = append(components, runtimeSelectorContent) } From 87e76b57bfce1aaa8a97dd44e56871d37ad7401a Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 16:00:04 -0400 Subject: [PATCH 25/30] Hide debuggable containers when changing runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index e0a4f6c0..6c08435b 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -219,6 +219,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case key.Matches(msg, keys.Debug.ChangeRuntime): + m.showDebuggableContainers = false m.showRuntimeSelectorView = !m.showRuntimeSelectorView return m, nil } @@ -362,26 +363,26 @@ func (m TUI) View() string { } func (m TUI) help() string { - var debuggableContainersHelp string - - if m.showDebuggableContainers { - debuggableContainersHelp = "hide" - } else { - debuggableContainersHelp = "list" - } - - var runtimeSelectorHelp string + var debuggableContainersHelp, runtimeSelectorHelp string if m.showRuntimeSelectorView { // Only display the navigation controls if the using is changing their runtime runtimeSelectorHelp = "cancel • j/k, up/down: select • enter: choose" } else { runtimeSelectorHelp = "change runtime" + + // Hide debuggable container help when selecting runtime + if m.showDebuggableContainers { + debuggableContainersHelp = "• l: hide debuggable containers" + } else { + debuggableContainersHelp = "• l: list debuggable containers" + } + } if m.standalone { - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • q: quit") } - return common.HelpStyle("• l: " + debuggableContainersHelp + " debuggable containers • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") } From e7a08b7b43979167e1c04ce340cb899f92401e4c Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 16:04:53 -0400 Subject: [PATCH 26/30] Swallow l keypress while selecting runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6c08435b..ee48ae5d 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -204,6 +204,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } return common.TUIsInstance.Home, nil case key.Matches(msg, keys.Debug.LoadDebuggableContainers): + if m.showRuntimeSelectorView { + return m, nil + } // Kickoff loading of debuggable containers in standalone mode. if m.standalone { loadDebuggableContainers := common.Event{ From 19b52ca3749e171214e7a78bd7b23171378b26d3 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:15:02 -0400 Subject: [PATCH 27/30] Cleanup comments, logging and variable naming Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 50 ++++++++++++----------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index ee48ae5d..6dee9216 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -97,24 +97,21 @@ type DebuggableContainer struct { func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case common.Event: - log.Println("==================== UPDATE DEBUG TUI ==========================") - debuggableContainersCh := make(chan interface{}) + subscriptionChannel := make(chan interface{}) // NOTE -> the names of both the channel map and the channel are misleading // as more than just the debuggable container information is dumped on it // at the moment. - debuggableContainersChannelMap := map[string]chan interface{}{ - "debuggableContainers": debuggableContainersCh, + subscriptionChannels := map[string]chan interface{}{ + "debuggableContainers": subscriptionChannel, } // In addition to passing the channel(s) we will use to transport data // we should pass: // the outputs we want to subscribe to: State | Info | Error xc := app.NewExecutionContext( "tui", - // Quiet -> when set to true, returns on the first line for each - // Execution context method true, "subscription", - debuggableContainersChannelMap, + subscriptionChannels, ) cparams := &CommandParams{ @@ -140,23 +137,22 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { doneCh := make(chan struct{}) go func() { - for debuggableContainersData := range debuggableContainersCh { - channelResponse, ok := debuggableContainersData.(map[string]string) + for subscriptionData := range subscriptionChannel { + channelResponse, ok := subscriptionData.(map[string]string) if !ok || channelResponse == nil { continue } - log.Printf("Channel response in tui: %v", channelResponse) + log.Debugf("Channel response in tui: %v", channelResponse) stateValue, stateExists := channelResponse["state"] - log.Printf("State value: %s", stateValue) - log.Printf("State exists: %s", stateValue) if stateExists { + log.Debugf("State value: %s", stateValue) if stateValue == "kubernetes.runtime.handler.started" { - log.Println("Got k8s state value") - // break + // TODO - what would we like to do with this information? + // && we likely will want to add similar handling for the other runtimes. } else if stateValue == "completed" { - // we get 'completed' then we get 'done' - log.Println("Exiting channel listening loop in update. State is complete.") + // We get 'completed' then we get 'done' + log.Debug("Exiting channel listening loop in update. State is complete.") break } } @@ -172,7 +168,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } counterCeiling = countInt } else if infoValue == "debuggable.container" { - log.Println("-----------------------Got debuggable container-----------------------") + log.Debugln("-----------------------Got debuggable container-----------------------") debuggableContainers = append(debuggableContainers, DebuggableContainer{ Name: channelResponse["name"], Image: channelResponse["image"], @@ -182,6 +178,7 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } // The notion of a count[er] does not exist for the k8s + // But it does for podman & docker. if counterCeiling > 0 && counter == counterCeiling { break } @@ -286,8 +283,13 @@ func generateTable(debuggableContainers []DebuggableContainer) table.Table { func choicesView(m TUI) string { choice := m.choice - template := "Choose runtime for debug\n\n" + template := "Choose runtime for debug mode\n\n" template += "%s\n\n" + + // NOTE -> the chocies we display here should only be runtiems we can + // establish a connection to. + // Otherwise, we set the user up for failure. + choices := fmt.Sprintf( "%s\n%s\n%s\n%s", checkbox("Docker", choice == 0), @@ -305,16 +307,6 @@ func checkbox(label string, checked bool) string { return fmt.Sprintf("[ ] %s", label) } -// NOTE -> the chocies we display here should only be runtiems we can -// establish a connection to. -// Otherwise, we set the user up for failure. -// const ( -// dockerRuntime = "docker" -// containerdRuntime = "containerd" -// podmanRuntime = "podman" -// kubernetesRuntime = "k8s" -// ) - func setNewRuntime(choice int) string { switch choice { case 0: @@ -343,7 +335,7 @@ func (m TUI) View() string { header := "Debug Dashboard\n" - currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) // TODO - map to human readable + currentRuntime := fmt.Sprintf("Current Runtime: %s.\n", m.runtime) components = append(components, header, currentRuntime) From fdb133eeff85d65167ae3b6bc9647f5f47f509ca Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:35:10 -0400 Subject: [PATCH 28/30] Use default namespace Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 6dee9216..81dce5d4 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -116,12 +116,10 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cparams := &CommandParams{ Runtime: m.runtime, - // Note -> we should not pass this by default, and instead pass it when a user asks. + // Passing these three fields all the time does not make sense. ActionListDebuggableContainers: true, - // Passing this all the time does not make sense. - Kubeconfig: crt.KubeconfigDefault, - // How to pass the target ref: - // TargetRef: "my-nginx" + Kubeconfig: crt.KubeconfigDefault, + TargetNamespace: "default", } gcValue, ok := msg.Data.(*command.GenericParams) From a2c353a08b912e5a7cf312236abc5655ed0de814 Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 19:36:25 -0400 Subject: [PATCH 29/30] Add state output to the start of the kubenetes runtime Signed-off-by: Evan Harris --- pkg/app/master/command/debug/handle_kubernetes_runtime.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/app/master/command/debug/handle_kubernetes_runtime.go b/pkg/app/master/command/debug/handle_kubernetes_runtime.go index 72f729a8..8689066f 100644 --- a/pkg/app/master/command/debug/handle_kubernetes_runtime.go +++ b/pkg/app/master/command/debug/handle_kubernetes_runtime.go @@ -44,6 +44,7 @@ func HandleKubernetesRuntime( log.Fields{ "op": "debug.HandleKubernetesRuntime", }) + xc.Out.State("kubernetes.runtime.handler.started") cpJson, _ := json.Marshal(commandParams) logger.WithField("cparams", string(cpJson)).Trace("call") From b8e9feaa89ffc6d7ee0f9f1c878a3704cf2d0def Mon Sep 17 00:00:00 2001 From: Evan Harris Date: Tue, 29 Oct 2024 20:00:03 -0400 Subject: [PATCH 30/30] Support tui -> d entrypoint Signed-off-by: Evan Harris --- pkg/app/master/command/debug/tui.go | 27 +++++---------------------- pkg/app/master/tui/home/tui.go | 6 +++--- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/pkg/app/master/command/debug/tui.go b/pkg/app/master/command/debug/tui.go index 81dce5d4..f8df56d9 100644 --- a/pkg/app/master/command/debug/tui.go +++ b/pkg/app/master/command/debug/tui.go @@ -61,15 +61,6 @@ var ( // End Styles - move to common - block -func LoadTUI() *TUI { - m := &TUI{ - width: 20, - height: 15, - runtime: crt.AutoSelectRuntime(), - } - return m -} - // InitialTUI returns the initial state of the model. func InitialTUI(standalone bool, gcvalues *command.GenericParams) *TUI { m := &TUI{ @@ -202,20 +193,12 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.showRuntimeSelectorView { return m, nil } - // Kickoff loading of debuggable containers in standalone mode. - if m.standalone { - loadDebuggableContainers := common.Event{ - Type: common.LaunchDebugEvent, - Data: m.gcvalues, - } - m, _ := m.Update(loadDebuggableContainers) - return m, nil + loadDebuggableContainers := common.Event{ + Type: common.LaunchDebugEvent, + Data: m.gcvalues, } - - // When used via `tui -> debug` - m.showDebuggableContainers = !m.showDebuggableContainers + m, _ := m.Update(loadDebuggableContainers) return m, nil - case key.Matches(msg, keys.Debug.ChangeRuntime): m.showDebuggableContainers = false m.showRuntimeSelectorView = !m.showRuntimeSelectorView @@ -377,5 +360,5 @@ func (m TUI) help() string { return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • q: quit") } - return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • j/k, up/down: select • enter: choose • esc: back • q: quit") + return common.HelpStyle(debuggableContainersHelp + " • r: " + runtimeSelectorHelp + " • esc: back • q: quit") } diff --git a/pkg/app/master/tui/home/tui.go b/pkg/app/master/tui/home/tui.go index ee898c07..0d0cd5b4 100644 --- a/pkg/app/master/tui/home/tui.go +++ b/pkg/app/master/tui/home/tui.go @@ -51,9 +51,9 @@ func (m TUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) { Data: m.Gcvalues, } - LoadTUI := debug.LoadTUI() - common.TUIsInstance.Debug = LoadTUI - return LoadTUI.Update(launchDebugEvent) + initialTUI := debug.InitialTUI(false, m.Gcvalues) + common.TUIsInstance.Debug = initialTUI + return initialTUI.Update(launchDebugEvent) } } return m, nil