diff options
author | Ryooooooga <eial5q265e5@gmail.com> | 2023-01-03 23:07:16 +0900 |
---|---|---|
committer | Ryooooooga <eial5q265e5@gmail.com> | 2023-01-06 10:51:09 +0900 |
commit | 00b922604adc50d5a3c952d2f6efa886a5bde186 (patch) | |
tree | eeae0e3293e03196e8a29490eced8f1557548ffa | |
parent | 1bb138c79c466e6207ae450a1bbd937c2713e449 (diff) |
fix: fix goroutine leaks
-rw-r--r-- | pkg/gui/confirmation_panel.go | 34 | ||||
-rw-r--r-- | pkg/gui/popup/popup_handler.go | 20 |
2 files changed, 37 insertions, 17 deletions
diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 4a7822076..30b21f124 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -1,6 +1,7 @@ package gui import ( + "context" "fmt" "strings" @@ -16,8 +17,10 @@ import ( // This file is for the rendering of confirmation panels along with setting and handling associated // keybindings. -func (gui *Gui) wrappedConfirmationFunction(function func() error) func() error { +func (gui *Gui) wrappedConfirmationFunction(cancel context.CancelFunc, function func() error) func() error { return func() error { + cancel() + if err := gui.c.PopContext(); err != nil { return err } @@ -32,8 +35,10 @@ func (gui *Gui) wrappedConfirmationFunction(function func() error) func() error } } -func (gui *Gui) wrappedPromptConfirmationFunction(function func(string) error, getResponse func() string) func() error { +func (gui *Gui) wrappedPromptConfirmationFunction(cancel context.CancelFunc, function func(string) error, getResponse func() string) func() error { return func() error { + cancel() + if err := gui.c.PopContext(); err != nil { return err } @@ -111,11 +116,12 @@ func (gui *Gui) getConfirmationPanelWidth() int { } func (gui *Gui) prepareConfirmationPanel( + ctx context.Context, opts types.ConfirmOpts, ) error { gui.Views.Confirmation.HasLoader = opts.HasLoader if opts.HasLoader { - gui.g.StartTicking() + gui.g.StartTicking(ctx) } gui.Views.Confirmation.Title = opts.Title // for now we do not support wrapping in our editor @@ -145,16 +151,19 @@ func runeForMask(mask bool) rune { return 0 } -func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { +func (gui *Gui) createPopupPanel(ctx context.Context, opts types.CreatePopupPanelOpts) error { gui.Mutexes.PopupMutex.Lock() defer gui.Mutexes.PopupMutex.Unlock() + ctx, cancel := context.WithCancel(ctx) + // we don't allow interruptions of non-loader popups in case we get stuck somehow // e.g. a credentials popup never gets its required user input so a process hangs // forever. // The proper solution is to have a queue of popup options if gui.State.CurrentPopupOpts != nil && !gui.State.CurrentPopupOpts.HasLoader { gui.Log.Error("ignoring create popup panel because a popup panel is already open") + cancel() return nil } @@ -162,6 +171,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { gui.clearConfirmationViewKeyBindings() err := gui.prepareConfirmationPanel( + ctx, types.ConfirmOpts{ Title: opts.Title, Prompt: opts.Prompt, @@ -171,6 +181,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { Mask: opts.Mask, }) if err != nil { + cancel() return err } confirmationView := gui.Views.Confirmation @@ -185,11 +196,13 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { confirmationView.RenderTextArea() } else { if err := gui.renderString(confirmationView, style.AttrBold.Sprint(opts.Prompt)); err != nil { + cancel() return err } } - if err := gui.setKeyBindings(opts); err != nil { + if err := gui.setKeyBindings(cancel, opts); err != nil { + cancel() return err } @@ -198,7 +211,7 @@ func (gui *Gui) createPopupPanel(opts types.CreatePopupPanelOpts) error { return gui.c.PushContext(gui.State.Contexts.Confirmation) } -func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { +func (gui *Gui) setKeyBindings(cancel context.CancelFunc, opts types.CreatePopupPanelOpts) error { actions := utils.ResolvePlaceholderString( gui.c.Tr.CloseConfirm, map[string]string{ @@ -210,13 +223,14 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { _ = gui.renderString(gui.Views.Options, actions) var onConfirm func() error if opts.HandleConfirmPrompt != nil { - onConfirm = gui.wrappedPromptConfirmationFunction(opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) + onConfirm = gui.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) } else { - onConfirm = gui.wrappedConfirmationFunction(opts.HandleConfirm) + onConfirm = gui.wrappedConfirmationFunction(cancel, opts.HandleConfirm) } keybindingConfig := gui.c.UserConfig.Keybinding onSuggestionConfirm := gui.wrappedPromptConfirmationFunction( + cancel, opts.HandleConfirmPrompt, gui.getSelectedSuggestionValue, ) @@ -235,7 +249,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { { ViewName: "confirmation", Key: keybindings.GetKey(keybindingConfig.Universal.Return), - Handler: gui.wrappedConfirmationFunction(opts.HandleClose), + Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose), }, { ViewName: "confirmation", @@ -260,7 +274,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { { ViewName: "suggestions", Key: keybindings.GetKey(keybindingConfig.Universal.Return), - Handler: gui.wrappedConfirmationFunction(opts.HandleClose), + Handler: gui.wrappedConfirmationFunction(cancel, opts.HandleClose), }, { ViewName: "suggestions", diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index 26b886fb7..4e50b6326 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -1,11 +1,12 @@ package popup import ( + "context" "strings" "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/common" - "github.com/jesseduffield/lazygit/pkg/gui/context" + gctx "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -16,7 +17,7 @@ type PopupHandler struct { *common.Common index int deadlock.Mutex - createPopupPanelFn func(types.CreatePopupPanelOpts) error + createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts) error onErrorFn func() error popContextFn func() error currentContextFn func() types.Context @@ -30,7 +31,7 @@ var _ types.IPopupHandler = &PopupHandler{} func NewPopupHandler( common *common.Common, - createPopupPanelFn func(types.CreatePopupPanelOpts) error, + createPopupPanelFn func(context.Context, types.CreatePopupPanelOpts) error, onErrorFn func() error, popContextFn func() error, currentContextFn func() types.Context, @@ -96,7 +97,7 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) error { self.index++ self.Unlock() - return self.createPopupPanelFn(types.CreatePopupPanelOpts{ + return self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{ Title: opts.Title, Prompt: opts.Prompt, HandleConfirm: opts.HandleConfirm, @@ -109,7 +110,7 @@ func (self *PopupHandler) Prompt(opts types.PromptOpts) error { self.index++ self.Unlock() - return self.createPopupPanelFn(types.CreatePopupPanelOpts{ + return self.createPopupPanelFn(context.Background(), types.CreatePopupPanelOpts{ Title: opts.Title, Prompt: opts.InitialContent, Editable: true, @@ -127,12 +128,15 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func() error) error index = self.index self.Unlock() - err := self.createPopupPanelFn(types.CreatePopupPanelOpts{ + ctx, cancel := context.WithCancel(context.Background()) + + err := self.createPopupPanelFn(ctx, types.CreatePopupPanelOpts{ Prompt: message, HasLoader: true, }) if err != nil { self.Log.Error(err) + cancel() return nil } @@ -141,8 +145,10 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func() error) error self.Log.Error(err) } + cancel() + self.Lock() - if index == self.index && self.currentContextFn().GetKey() == context.CONFIRMATION_CONTEXT_KEY { + if index == self.index && self.currentContextFn().GetKey() == gctx.CONFIRMATION_CONTEXT_KEY { _ = self.popContextFn() } self.Unlock() |