From 5123680dcee84beed8b1d98735a1ec7135c60949 Mon Sep 17 00:00:00 2001 From: Ibrahim Serdar Acikgoz Date: Thu, 3 Jan 2019 00:44:23 +0300 Subject: superfast job handling and failover for auth added --- pkg/git/job-queue.go | 28 +++++++++++++++++++++++++--- pkg/gui/authenticationview.go | 11 +---------- pkg/gui/gui.go | 16 +++++++++------- pkg/gui/keybindings.go | 8 ++++++++ pkg/gui/mainview.go | 40 ++++++++++++++++++++++------------------ pkg/gui/util-textstyle.go | 9 ++++----- 6 files changed, 69 insertions(+), 43 deletions(-) diff --git a/pkg/git/job-queue.go b/pkg/git/job-queue.go index 3eee605..e6e6f0c 100644 --- a/pkg/git/job-queue.go +++ b/pkg/git/job-queue.go @@ -2,6 +2,7 @@ package git import ( "errors" + "sync" ) // JobQueue holds the slice of Jobs @@ -66,13 +67,34 @@ func (jq *JobQueue) RemoveFromQueue(entity *RepoEntity) error { // IsInTheQueue function; since the job and entity is not tied with its own // struct, this function returns true if that entity is in the queue along with // the jobs type -func (jq *JobQueue) IsInTheQueue(entity *RepoEntity) (inTheQueue bool, jt JobType) { +func (jq *JobQueue) IsInTheQueue(entity *RepoEntity) (inTheQueue bool, j *Job) { inTheQueue = false for _, job := range jq.series { if job.Entity.RepoID == entity.RepoID { inTheQueue = true - jt = job.JobType + j = job } } - return inTheQueue, jt + return inTheQueue, j +} + +// StartJobsAsync start he jobs in the queue asynchronously +func (jq *JobQueue) StartJobsAsync() map[*Job]error { + fails := make(map[*Job]error) + var wg sync.WaitGroup + var mx sync.Mutex + for range jq.series { + wg.Add(1) + go func() { + defer wg.Done() + j, _, err := jq.StartNext() + if err != nil { + mx.Lock() + fails[j] = err + mx.Unlock() + } + }() + } + wg.Wait() + return fails } diff --git a/pkg/gui/authenticationview.go b/pkg/gui/authenticationview.go index a274425..7d4861f 100644 --- a/pkg/gui/authenticationview.go +++ b/pkg/gui/authenticationview.go @@ -125,16 +125,7 @@ func (gui *Gui) submitAuthenticationView(g *gocui.Gui, v *gocui.View) error { return err } - if err := gui.closeAuthenticationView(g, v); err != nil { - return err // should return?? - } - - vReturn, err := g.View(authenticationReturnView) - if err != nil { - return err // should return?? - } - - return gui.startQueue(g, vReturn) + return gui.closeAuthenticationView(g, v) } // open an error view to inform user with a message and a useful note diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index b19772b..6d5de19 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -21,10 +21,11 @@ type Gui struct { // guiState struct holds the repositories, directiories, mode and queue of the // gui object. These values are not static type guiState struct { - Repositories []*git.RepoEntity - Directories []string - Mode mode - Queue *git.JobQueue + Repositories []*git.RepoEntity + Directories []string + Mode mode + Queue *git.JobQueue + FailoverQueue *git.JobQueue } // this struct encapsulates the name and title of a view. the name of a view is @@ -77,9 +78,10 @@ var ( // NewGui creates a Gui opject and fill it's state related entites func NewGui(mode string, directoies []string) (*Gui, error) { initialState := guiState{ - Directories: directoies, - Mode: fetchMode, - Queue: git.CreateJobQueue(), + Directories: directoies, + Mode: fetchMode, + Queue: git.CreateJobQueue(), + FailoverQueue: git.CreateJobQueue(), } gui := &Gui{ State: initialState, diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 7aaee56..668fe90 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -309,6 +309,14 @@ func (gui *Gui) generateKeybindings() error { }, // Main view controls { + View: mainViewFeature.Name, + Key: 'u', + Modifier: gocui.ModNone, + Handler: gui.submitCredentials, + Display: "u", + Description: "Submit Credentials", + Vital: false, + }, { View: mainViewFeature.Name, Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, diff --git a/pkg/gui/mainview.go b/pkg/gui/mainview.go index 6cd43bb..8ee31ba 100644 --- a/pkg/gui/mainview.go +++ b/pkg/gui/mainview.go @@ -231,29 +231,33 @@ func (gui *Gui) removeFromQueue(entity *git.RepoEntity) error { // this function starts the queue and updates the gui with the result of an // operation func (gui *Gui) startQueue(g *gocui.Gui, v *gocui.View) error { - go func(gui_go *Gui, g_go *gocui.Gui) { - for { - job, finished, err := gui_go.State.Queue.StartNext() + go func(gui_go *Gui) { + fails := gui_go.State.Queue.StartJobsAsync() + gui_go.State.Queue = git.CreateJobQueue() + for j, err := range fails { + if err == git.ErrAuthenticationRequired { + j.Entity.SetState(git.Paused) + gui_go.State.FailoverQueue.AddJob(j) + } + } + }(gui) + return nil +} +func (gui *Gui) submitCredentials(g *gocui.Gui, v *gocui.View) error { + if is, j := gui.State.FailoverQueue.IsInTheQueue(gui.getSelectedRepository()); is { + if j.Entity.State() == git.Paused { + gui.State.FailoverQueue.RemoveFromQueue(j.Entity) + err := gui.openAuthenticationView(g, gui.State.Queue, j, v.Name()) if err != nil { - if err == git.ErrAuthenticationRequired { - // pause the job, so it will be indicated to being blocking - job.Entity.SetState(git.Paused) - err := gui_go.openAuthenticationView(g, gui_go.State.Queue, job, v.Name()) - if err != nil { - log.Warn(err.Error()) - return - } - } - return - // with not returning here, we simply ignore and continue + log.Warn(err.Error()) + return err } - // if queue is finished simply return from this goroutine - if finished { - return + if isnt, _ := gui.State.Queue.IsInTheQueue(j.Entity); !isnt { + gui.State.FailoverQueue.AddJob(j) } } - }(gui, g) + } return nil } diff --git a/pkg/gui/util-textstyle.go b/pkg/gui/util-textstyle.go index 95c8de7..1bb3635 100644 --- a/pkg/gui/util-textstyle.go +++ b/pkg/gui/util-textstyle.go @@ -84,8 +84,8 @@ func (gui *Gui) repositoryLabel(e *git.RepoEntity) string { var suffix string // rendering the satus according to repository's state if e.State() == git.Queued { - if inQueue, ty := gui.State.Queue.IsInTheQueue(e); inQueue { - switch mode := ty; mode { + if inQueue, j := gui.State.Queue.IsInTheQueue(e); inQueue { + switch mode := j.JobType; mode { case git.FetchJob: suffix = blue.Sprint(queuedSymbol) case git.PullJob: @@ -103,12 +103,11 @@ func (gui *Gui) repositoryLabel(e *git.RepoEntity) string { } else if e.State() == git.Success { return prefix + repoName + ws + green.Sprint(successSymbol) } else if e.State() == git.Paused { - return prefix + repoName + ws + yellow.Sprint(pauseSymbol) + return prefix + repoName + ws + yellow.Sprint("auth required (u)") } else if e.State() == git.Fail { return prefix + repoName + ws + red.Sprint(failSymbol) - } else { - return prefix + repoName } + return prefix + repoName } func commitLabel(c *git.Commit) string { -- cgit v1.2.3