mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-06-17 00:18:05 +02:00
add some safe goroutines
WIP
This commit is contained in:
@ -9,6 +9,7 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/go-errors/errors"
|
"github.com/go-errors/errors"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
|
||||||
"github.com/creack/pty"
|
"github.com/creack/pty"
|
||||||
)
|
)
|
||||||
@ -31,14 +32,14 @@ func RunCommandWithOutputLiveWrapper(c *OSCommand, command string, output func(s
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
scanner := bufio.NewScanner(ptmx)
|
scanner := bufio.NewScanner(ptmx)
|
||||||
scanner.Split(scanWordsWithNewLines)
|
scanner.Split(scanWordsWithNewLines)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
toOutput := strings.Trim(scanner.Text(), " ")
|
toOutput := strings.Trim(scanner.Text(), " ")
|
||||||
_, _ = ptmx.WriteString(output(toOutput))
|
_, _ = ptmx.WriteString(output(toOutput))
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
err = cmd.Wait()
|
err = cmd.Wait()
|
||||||
ptmx.Close()
|
ptmx.Close()
|
||||||
|
@ -411,7 +411,7 @@ func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
|||||||
|
|
||||||
for _, cmd := range cmds {
|
for _, cmd := range cmds {
|
||||||
currentCmd := cmd
|
currentCmd := cmd
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
stderr, err := currentCmd.StderrPipe()
|
stderr, err := currentCmd.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Log.Error(err)
|
c.Log.Error(err)
|
||||||
@ -432,7 +432,7 @@ func (c *OSCommand) PipeCommands(commandStrings ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
@ -50,14 +50,14 @@ func (m *statusManager) getStatusString() string {
|
|||||||
|
|
||||||
// WithWaitingStatus wraps a function and shows a waiting status while the function is still executing
|
// WithWaitingStatus wraps a function and shows a waiting status while the function is still executing
|
||||||
func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
|
func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
gui.statusManager.addWaitingStatus(name)
|
gui.statusManager.addWaitingStatus(name)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
gui.statusManager.removeStatus(name)
|
gui.statusManager.removeStatus(name)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
ticker := time.NewTicker(time.Millisecond * 50)
|
ticker := time.NewTicker(time.Millisecond * 50)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
@ -67,14 +67,14 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
|
|||||||
}
|
}
|
||||||
gui.renderString("appStatus", appStatus)
|
gui.renderString("appStatus", appStatus)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
if err := f(); err != nil {
|
if err := f(); err != nil {
|
||||||
gui.g.Update(func(g *gocui.Gui) error {
|
gui.g.Update(func(g *gocui.Gui) error {
|
||||||
return gui.surfaceError(err)
|
return gui.surfaceError(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ func (gui *Gui) handleGitFetch(g *gocui.Gui, v *gocui.View) error {
|
|||||||
if err := gui.createLoaderPanel(v, gui.Tr.FetchWait); err != nil {
|
if err := gui.createLoaderPanel(v, gui.Tr.FetchWait); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
err := gui.fetch(true)
|
err := gui.fetch(true)
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
||||||
}()
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
|
|||||||
"to": branch.Name,
|
"to": branch.Name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
_ = gui.createLoaderPanel(v, message)
|
_ = gui.createLoaderPanel(v, message)
|
||||||
|
|
||||||
if gui.State.Panels.Branches.SelectedLineIdx == 0 {
|
if gui.State.Panels.Branches.SelectedLineIdx == 0 {
|
||||||
@ -395,7 +395,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
|
|||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}})
|
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC, scope: []int{BRANCHES}})
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,11 @@ func (gui *Gui) handleCommitSelect() error {
|
|||||||
state := gui.State.Panels.Commits
|
state := gui.State.Panels.Commits
|
||||||
if state.SelectedLineIdx > 290 && state.LimitCommits {
|
if state.SelectedLineIdx > 290 && state.LimitCommits {
|
||||||
state.LimitCommits = false
|
state.LimitCommits = false
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
if err := gui.refreshCommitsWithLimit(); err != nil {
|
if err := gui.refreshCommitsWithLimit(); err != nil {
|
||||||
_ = gui.surfaceError(err)
|
_ = gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.escapeLineByLinePanel()
|
gui.escapeLineByLinePanel()
|
||||||
@ -60,11 +60,11 @@ func (gui *Gui) handleCommitSelect() error {
|
|||||||
func (gui *Gui) refreshReflogCommitsConsideringStartup() {
|
func (gui *Gui) refreshReflogCommitsConsideringStartup() {
|
||||||
switch gui.State.StartupStage {
|
switch gui.State.StartupStage {
|
||||||
case INITIAL:
|
case INITIAL:
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
_ = gui.refreshReflogCommits()
|
_ = gui.refreshReflogCommits()
|
||||||
gui.refreshBranches()
|
gui.refreshBranches()
|
||||||
gui.State.StartupStage = COMPLETE
|
gui.State.StartupStage = COMPLETE
|
||||||
}()
|
})
|
||||||
|
|
||||||
case COMPLETE:
|
case COMPLETE:
|
||||||
_ = gui.refreshReflogCommits()
|
_ = gui.refreshReflogCommits()
|
||||||
@ -78,14 +78,14 @@ func (gui *Gui) refreshCommits() error {
|
|||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(2)
|
wg.Add(2)
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
gui.refreshReflogCommitsConsideringStartup()
|
gui.refreshReflogCommitsConsideringStartup()
|
||||||
|
|
||||||
gui.refreshBranches()
|
gui.refreshBranches()
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
})
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
_ = gui.refreshCommitsWithLimit()
|
_ = gui.refreshCommitsWithLimit()
|
||||||
context, ok := gui.Contexts.CommitFiles.Context.GetParentContext()
|
context, ok := gui.Contexts.CommitFiles.Context.GetParentContext()
|
||||||
if ok && context.GetKey() == BRANCH_COMMITS_CONTEXT_KEY {
|
if ok && context.GetKey() == BRANCH_COMMITS_CONTEXT_KEY {
|
||||||
@ -102,7 +102,7 @@ func (gui *Gui) refreshCommits() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
})
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
|
@ -189,14 +189,14 @@ func (gui *Gui) createPopupPanel(opts createPopupPanelOpts) error {
|
|||||||
}
|
}
|
||||||
confirmationView.Editable = opts.editable
|
confirmationView.Editable = opts.editable
|
||||||
if opts.editable {
|
if opts.editable {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
// TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work)
|
// TODO: remove this wait (right now if you remove it the EditGotoToEndOfLine method doesn't seem to work)
|
||||||
time.Sleep(time.Millisecond)
|
time.Sleep(time.Millisecond)
|
||||||
gui.g.Update(func(g *gocui.Gui) error {
|
gui.g.Update(func(g *gocui.Gui) error {
|
||||||
confirmationView.EditGotoToEndOfLine()
|
confirmationView.EditGotoToEndOfLine()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.renderString("confirmation", opts.prompt)
|
gui.renderString("confirmation", opts.prompt)
|
||||||
|
@ -727,7 +727,7 @@ func (gui *Gui) mustContextForContextKey(contextKey string) Context {
|
|||||||
context, ok := gui.contextForContextKey(contextKey)
|
context, ok := gui.contextForContextKey(contextKey)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("context now found for key %s", contextKey))
|
panic(fmt.Sprintf("context not found for key %s", contextKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ func (gui *Gui) watchFilesForChanges() {
|
|||||||
if gui.fileWatcher.Disabled {
|
if gui.fileWatcher.Disabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// watch for events
|
// watch for events
|
||||||
@ -141,5 +142,5 @@ func (gui *Gui) watchFilesForChanges() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,7 @@ func (gui *Gui) pullFiles(opts PullFilesOptions) error {
|
|||||||
|
|
||||||
mode := gui.Config.GetUserConfig().Git.Pull.Mode
|
mode := gui.Config.GetUserConfig().Git.Pull.Mode
|
||||||
|
|
||||||
go gui.pullWithMode(mode, opts)
|
go utils.Safe(func() { gui.pullWithMode(mode, opts) })
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -551,7 +551,7 @@ func (gui *Gui) pushWithForceFlag(v *gocui.View, force bool, upstream string, ar
|
|||||||
if err := gui.createLoaderPanel(v, gui.Tr.PushWait); err != nil {
|
if err := gui.createLoaderPanel(v, gui.Tr.PushWait); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
branchName := gui.getCheckedOutBranch().Name
|
branchName := gui.getCheckedOutBranch().Name
|
||||||
err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential)
|
err := gui.GitCommand.Push(branchName, force, upstream, args, gui.promptUserForCredential)
|
||||||
if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") {
|
if err != nil && !force && strings.Contains(err.Error(), "Updates were rejected") {
|
||||||
@ -571,7 +571,7 @@ func (gui *Gui) pushWithForceFlag(v *gocui.View, force bool, upstream string, ar
|
|||||||
}
|
}
|
||||||
gui.handleCredentialsPopup(err)
|
gui.handleCredentialsPopup(err)
|
||||||
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
_ = gui.refreshSidePanels(refreshOptions{mode: ASYNC})
|
||||||
}()
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +443,7 @@ func (gui *Gui) Run() error {
|
|||||||
defer g.Close()
|
defer g.Close()
|
||||||
|
|
||||||
if recordEvents {
|
if recordEvents {
|
||||||
go gui.recordEvents()
|
go utils.Safe(gui.recordEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
if gui.State.Modes.Filtering.Active() {
|
if gui.State.Modes.Filtering.Active() {
|
||||||
@ -481,10 +481,10 @@ func (gui *Gui) Run() error {
|
|||||||
|
|
||||||
gui.waitForIntro.Add(1)
|
gui.waitForIntro.Add(1)
|
||||||
if gui.Config.GetUserConfig().Git.AutoFetch {
|
if gui.Config.GetUserConfig().Git.AutoFetch {
|
||||||
go gui.startBackgroundFetch()
|
go utils.Safe(gui.startBackgroundFetch)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.goEvery(time.Second*10, gui.stopChan, gui.refreshFilesAndSubmodules)
|
gui.goEvery(time.Millisecond*50, gui.stopChan, gui.refreshFilesAndSubmodules)
|
||||||
|
|
||||||
g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout()))
|
g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout()))
|
||||||
|
|
||||||
@ -499,7 +499,7 @@ func (gui *Gui) Run() error {
|
|||||||
// otherwise it handles the error, possibly by quitting the application
|
// otherwise it handles the error, possibly by quitting the application
|
||||||
func (gui *Gui) RunWithSubprocesses() error {
|
func (gui *Gui) RunWithSubprocesses() error {
|
||||||
gui.StartTime = time.Now()
|
gui.StartTime = time.Now()
|
||||||
go gui.replayRecordedEvents()
|
go utils.Safe(gui.replayRecordedEvents)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
gui.stopChan = make(chan struct{})
|
gui.stopChan = make(chan struct{})
|
||||||
@ -584,18 +584,18 @@ func (gui *Gui) showInitialPopups(tasks []func(chan struct{}) error) {
|
|||||||
gui.waitForIntro.Add(len(tasks))
|
gui.waitForIntro.Add(len(tasks))
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
for _, task := range tasks {
|
for _, task := range tasks {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
if err := task(done); err != nil {
|
if err := task(done); err != nil {
|
||||||
_ = gui.surfaceError(err)
|
_ = gui.surfaceError(err)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
<-done
|
<-done
|
||||||
gui.waitForIntro.Done()
|
gui.waitForIntro.Done()
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
|
func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
|
||||||
@ -614,7 +614,7 @@ func (gui *Gui) showIntroPopupMessage(done chan struct{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
|
func (gui *Gui) goEvery(interval time.Duration, stop chan struct{}, function func() error) {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
ticker := time.NewTicker(interval)
|
ticker := time.NewTicker(interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
@ -625,7 +625,7 @@ func (gui *Gui) goEvery(interval time.Duration, stop chan struct{}, function fun
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) startBackgroundFetch() {
|
func (gui *Gui) startBackgroundFetch() {
|
||||||
@ -641,7 +641,7 @@ func (gui *Gui) startBackgroundFetch() {
|
|||||||
prompt: gui.Tr.NoAutomaticGitFetchBody,
|
prompt: gui.Tr.NoAutomaticGitFetchBody,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
gui.goEvery(time.Second*60, gui.stopChan, func() error {
|
gui.goEvery(time.Millisecond*50, gui.stopChan, func() error {
|
||||||
err := gui.fetch(false)
|
err := gui.fetch(false)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func recordingEvents() bool {
|
func recordingEvents() bool {
|
||||||
@ -28,10 +29,10 @@ func (gui *Gui) replayRecordedEvents() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
time.Sleep(time.Second * 20)
|
time.Sleep(time.Second * 20)
|
||||||
log.Fatal("20 seconds is up, lazygit recording took too long to complete")
|
log.Fatal("20 seconds is up, lazygit recording took too long to complete")
|
||||||
}()
|
})
|
||||||
|
|
||||||
events, err := gui.loadRecordedEvents()
|
events, err := gui.loadRecordedEvents()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -110,7 +110,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
func() {
|
func() {
|
||||||
if options.mode == ASYNC {
|
if options.mode == ASYNC {
|
||||||
go gui.refreshCommits()
|
go utils.Safe(func() { gui.refreshCommits() })
|
||||||
} else {
|
} else {
|
||||||
gui.refreshCommits()
|
gui.refreshCommits()
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
func() {
|
func() {
|
||||||
if options.mode == ASYNC {
|
if options.mode == ASYNC {
|
||||||
go gui.refreshFilesAndSubmodules()
|
go utils.Safe(func() { gui.refreshFilesAndSubmodules() })
|
||||||
} else {
|
} else {
|
||||||
gui.refreshFilesAndSubmodules()
|
gui.refreshFilesAndSubmodules()
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
func() {
|
func() {
|
||||||
if options.mode == ASYNC {
|
if options.mode == ASYNC {
|
||||||
go gui.refreshStashEntries()
|
go utils.Safe(func() { gui.refreshStashEntries() })
|
||||||
} else {
|
} else {
|
||||||
gui.refreshStashEntries()
|
gui.refreshStashEntries()
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
func() {
|
func() {
|
||||||
if options.mode == ASYNC {
|
if options.mode == ASYNC {
|
||||||
go gui.refreshTags()
|
go utils.Safe(func() { gui.refreshTags() })
|
||||||
} else {
|
} else {
|
||||||
gui.refreshTags()
|
gui.refreshTags()
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
func() {
|
func() {
|
||||||
if options.mode == ASYNC {
|
if options.mode == ASYNC {
|
||||||
go gui.refreshRemotes()
|
go utils.Safe(func() { gui.refreshRemotes() })
|
||||||
} else {
|
} else {
|
||||||
gui.refreshRemotes()
|
gui.refreshRemotes()
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,14 +42,14 @@ func NewViewBufferManager(log *logrus.Entry, writer io.Writer, beforeStart func(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *ViewBufferManager) ReadLines(n int) {
|
func (m *ViewBufferManager) ReadLines(n int) {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
m.readLines <- n
|
m.readLines <- n
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string, linesToRead int, onDone func()) func(chan struct{}) error {
|
||||||
return func(stop chan struct{}) error {
|
return func(stop chan struct{}) error {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
<-stop
|
<-stop
|
||||||
if err := oscommands.Kill(cmd); err != nil {
|
if err := oscommands.Kill(cmd); err != nil {
|
||||||
if !strings.Contains(err.Error(), "process already finished") {
|
if !strings.Contains(err.Error(), "process already finished") {
|
||||||
@ -58,7 +59,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
|||||||
if onDone != nil {
|
if onDone != nil {
|
||||||
onDone()
|
onDone()
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
loadingMutex := sync.Mutex{}
|
loadingMutex := sync.Mutex{}
|
||||||
|
|
||||||
@ -67,13 +68,13 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
|||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
scanner := bufio.NewScanner(r)
|
scanner := bufio.NewScanner(r)
|
||||||
scanner.Split(bufio.ScanLines)
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
loaded := false
|
loaded := false
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
ticker := time.NewTicker(time.Millisecond * 100)
|
ticker := time.NewTicker(time.Millisecond * 100)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
select {
|
select {
|
||||||
@ -88,7 +89,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
|||||||
case <-stop:
|
case <-stop:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
outer:
|
outer:
|
||||||
for {
|
for {
|
||||||
@ -139,7 +140,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, prefix string
|
|||||||
}
|
}
|
||||||
|
|
||||||
close(done)
|
close(done)
|
||||||
}()
|
})
|
||||||
|
|
||||||
m.readLines <- linesToRead
|
m.readLines <- linesToRead
|
||||||
|
|
||||||
@ -157,10 +158,10 @@ func (t *ViewBufferManager) Close() {
|
|||||||
|
|
||||||
c := make(chan struct{})
|
c := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
t.currentTask.Stop()
|
t.currentTask.Stop()
|
||||||
c <- struct{}{}
|
c <- struct{}{}
|
||||||
}()
|
})
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-c:
|
case <-c:
|
||||||
@ -175,7 +176,7 @@ func (t *ViewBufferManager) Close() {
|
|||||||
// 2) string based, where the manager can also be asked to read more lines
|
// 2) string based, where the manager can also be asked to read more lines
|
||||||
|
|
||||||
func (m *ViewBufferManager) NewTask(f func(stop chan struct{}) error) error {
|
func (m *ViewBufferManager) NewTask(f func(stop chan struct{}) error) error {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
m.taskIDMutex.Lock()
|
m.taskIDMutex.Lock()
|
||||||
m.newTaskId++
|
m.newTaskId++
|
||||||
taskID := m.newTaskId
|
taskID := m.newTaskId
|
||||||
@ -202,14 +203,14 @@ func (m *ViewBufferManager) NewTask(f func(stop chan struct{}) error) error {
|
|||||||
f: f,
|
f: f,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
if err := f(stop); err != nil {
|
if err := f(stop); err != nil {
|
||||||
m.Log.Error(err) // might need an onError callback
|
m.Log.Error(err) // might need an onError callback
|
||||||
}
|
}
|
||||||
|
|
||||||
close(notifyStopped)
|
close(notifyStopped)
|
||||||
}()
|
})
|
||||||
}()
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -145,12 +145,12 @@ func (u *Updater) CheckForNewUpdate(onFinish func(string, error) error, userRequ
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
newVersion, err := u.checkForNewUpdate()
|
newVersion, err := u.checkForNewUpdate()
|
||||||
if err = onFinish(newVersion, err); err != nil {
|
if err = onFinish(newVersion, err); err != nil {
|
||||||
u.Log.Error(err)
|
u.Log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Updater) skipUpdateCheck() bool {
|
func (u *Updater) skipUpdateCheck() bool {
|
||||||
@ -235,12 +235,12 @@ func (u *Updater) getBinaryUrl(newVersion string) (string, error) {
|
|||||||
|
|
||||||
// Update downloads the latest binary and replaces the current binary with it
|
// Update downloads the latest binary and replaces the current binary with it
|
||||||
func (u *Updater) Update(newVersion string, onFinish func(error) error) {
|
func (u *Updater) Update(newVersion string, onFinish func(error) error) {
|
||||||
go func() {
|
go utils.Safe(func() {
|
||||||
err := u.update(newVersion)
|
err := u.update(newVersion)
|
||||||
if err = onFinish(err); err != nil {
|
if err = onFinish(err); err != nil {
|
||||||
u.Log.Error(err)
|
u.Log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Updater) update(newVersion string) error {
|
func (u *Updater) update(newVersion string) error {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
|
"github.com/jesseduffield/termbox-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SplitLines takes a multiline string and splits it on newlines
|
// SplitLines takes a multiline string and splits it on newlines
|
||||||
@ -360,3 +361,18 @@ func ResolveTemplate(templateStr string, object interface{}) (string, error) {
|
|||||||
|
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safe will close termbox if a panic occurs so that we don't end up in a malformed
|
||||||
|
// terminal state
|
||||||
|
func Safe(f func()) {
|
||||||
|
panicking := true
|
||||||
|
defer func() {
|
||||||
|
if panicking {
|
||||||
|
termbox.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
f()
|
||||||
|
|
||||||
|
panicking = false
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user