fix: address Plan 2 final-review findings
- tui/doc.go: remove teatest blank import (test harness in prod binary) - cmd: honor wizard HaltOnError toggle in addition to --halt-on-error flag - cmd: wire SIGINT/SIGTERM to root context via signal.NotifyContext - dashboard/run: derive engine context and cancel on tea.Program exit so the engine goroutine does not outlive Run
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -41,7 +43,13 @@ func main() {
|
|||||||
Version: version,
|
Version: version,
|
||||||
}
|
}
|
||||||
root.AddCommand(newInstallCmd())
|
root.AddCommand(newInstallCmd())
|
||||||
if err := root.Execute(); err != nil {
|
|
||||||
|
// Wire SIGINT/SIGTERM to a cancellable context so long-running phases
|
||||||
|
// (engine.Run, sudo keepalive) observe the cancellation promptly.
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
if err := root.ExecuteContext(ctx); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "error:", err)
|
fmt.Fprintln(os.Stderr, "error:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@@ -140,7 +148,8 @@ func newInstallCmd() *cobra.Command {
|
|||||||
fmt.Fprintln(os.Stdout, "installation cancelled")
|
fmt.Fprintln(os.Stdout, "installation cancelled")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sum, runErr = dashboard.Run(ctx, Registry, finalState, halt)
|
// Either the CLI flag or the wizard toggle can force halt-on-error.
|
||||||
|
sum, runErr = dashboard.Run(ctx, Registry, finalState, halt || finalState.HaltOnError)
|
||||||
}
|
}
|
||||||
|
|
||||||
ended := time.Now().UTC()
|
ended := time.Now().UTC()
|
||||||
|
|||||||
@@ -23,10 +23,18 @@ func Run(ctx context.Context, reg *module.Registry, state tui.WizardState, halt
|
|||||||
m := NewModel(selected, nameByID)
|
m := NewModel(selected, nameByID)
|
||||||
p := tea.NewProgram(m, tea.WithContext(ctx))
|
p := tea.NewProgram(m, tea.WithContext(ctx))
|
||||||
|
|
||||||
|
// Derived context so that when p.Run() returns (user pressed q, tea
|
||||||
|
// errored, parent ctx cancelled) the engine goroutine is cancelled
|
||||||
|
// too. Deferred cancel ensures no orphan goroutine outlives Run.
|
||||||
|
engineCtx, cancelEngine := context.WithCancel(ctx)
|
||||||
|
defer cancelEngine()
|
||||||
|
|
||||||
reporter := tui.NewTeaReporter(p)
|
reporter := tui.NewTeaReporter(p)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
summary, err := engine.Run(ctx, reg, engine.RunOptions{
|
// TODO(plan-3): forward state.Parallelism once engine.RunOptions
|
||||||
|
// gains a Parallelism field and the engine supports concurrent Apply.
|
||||||
|
summary, err := engine.Run(engineCtx, reg, engine.RunOptions{
|
||||||
Selected: selected,
|
Selected: selected,
|
||||||
HaltOnError: halt,
|
HaltOnError: halt,
|
||||||
Reporter: reporter,
|
Reporter: reporter,
|
||||||
|
|||||||
@@ -2,10 +2,3 @@
|
|||||||
// that collects user choices and the Bubble Tea dashboard that renders
|
// that collects user choices and the Bubble Tea dashboard that renders
|
||||||
// live module status during engine.Run.
|
// live module status during engine.Run.
|
||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
|
||||||
_ "github.com/charmbracelet/bubbletea"
|
|
||||||
_ "github.com/charmbracelet/huh"
|
|
||||||
_ "github.com/charmbracelet/lipgloss"
|
|
||||||
_ "github.com/charmbracelet/x/exp/teatest"
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user