diff options
| author | Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com> | 2018-11-22 01:08:00 +0300 |
|---|---|---|
| committer | Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com> | 2018-11-22 01:08:00 +0300 |
| commit | 8252d2f2f19e1b2cad43b472bfdb4308cd3df649 (patch) | |
| tree | 5767e1d5ffa997284ca764c9f9cc5e4f531dfd09 | |
| parent | re-arrangement (diff) | |
| download | gitbatch-8252d2f2f19e1b2cad43b472bfdb4308cd3df649.tar.gz | |
refactoring and added initial implementation of fetc & pull mechanisms
| -rw-r--r-- | main.go | 1 | ||||
| -rw-r--r-- | pkg/app/app.go | 49 | ||||
| -rw-r--r-- | pkg/git/load.go | 41 | ||||
| -rw-r--r-- | pkg/git/model.go | 9 | ||||
| -rw-r--r-- | pkg/git/repository.go | 37 | ||||
| -rw-r--r-- | pkg/gui/gui-util.go | 16 | ||||
| -rw-r--r-- | pkg/gui/gui.go | 65 | ||||
| -rw-r--r-- | pkg/gui/keybindings.go | 2 | ||||
| -rw-r--r-- | pkg/gui/pullview.go | 29 | ||||
| -rw-r--r-- | pkg/gui/scheduleview.go | 2 |
10 files changed, 186 insertions, 65 deletions
@@ -24,6 +24,7 @@ func main() { if err != nil { log.Fatal(err) } + app.Gui.Run() defer app.Close() diff --git a/pkg/app/app.go b/pkg/app/app.go index f97d657..c3575a4 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -2,9 +2,7 @@ package app import ( "github.com/isacikgoz/gitbatch/pkg/gui" - "github.com/isacikgoz/gitbatch/pkg/git" "io" - "sync" ) // App struct @@ -19,12 +17,13 @@ func Setup(directories []string) (*App, error) { closers: []io.Closer{}, } - entities, err := createRepositoryEntities(directories) - if err != nil { - return app, err - } + var err error + // entities, err := createRepositoryEntities(directories) + // if err != nil { + // return app, err + // } - app.Gui, err = gui.NewGui(entities) + app.Gui, err = gui.NewGui(directories) if err != nil { return app, err } @@ -40,40 +39,4 @@ func (app *App) Close() error { } } return nil -} - -func createRepositoryEntities(directories []string) (entities []*git.RepoEntity, err error) { - entities = make([]*git.RepoEntity, 0) - - var wg sync.WaitGroup - var mu sync.Mutex - - for _, dir := range directories { - // increment wait counter by one because we run a single goroutine - // below - wg.Add(1) - - go func(d string) { - - // decrement the wait counter by one, we call it in a defer so it's - // called at the end of this goroutine - defer wg.Done() - entity, err := git.InitializeRepository(d) - if err != nil { - return - } - - // lock so we don't get a race if multiple go routines try to add - // to the same entities - mu.Lock() - entities = append(entities, entity) - mu.Unlock() - }(dir) - } - - // wait until the wait counter is zero, this happens if all goroutines have - // finished - wg.Wait() - - return entities, nil }
\ No newline at end of file diff --git a/pkg/git/load.go b/pkg/git/load.go new file mode 100644 index 0000000..5d62dcf --- /dev/null +++ b/pkg/git/load.go @@ -0,0 +1,41 @@ +package git + +import ( + "sync" +) + +func LoadRepositoryEntities(directories []string) (entities []*RepoEntity, err error) { + entities = make([]*RepoEntity, 0) + + var wg sync.WaitGroup + var mu sync.Mutex + + for _, dir := range directories { + // increment wait counter by one because we run a single goroutine + // below + wg.Add(1) + + go func(d string) { + + // decrement the wait counter by one, we call it in a defer so it's + // called at the end of this goroutine + defer wg.Done() + entity, err := InitializeRepository(d) + if err != nil { + return + } + + // lock so we don't get a race if multiple go routines try to add + // to the same entities + mu.Lock() + entities = append(entities, entity) + mu.Unlock() + }(dir) + } + + // wait until the wait counter is zero, this happens if all goroutines have + // finished + wg.Wait() + + return entities, nil +}
\ No newline at end of file diff --git a/pkg/git/model.go b/pkg/git/model.go index d5182c0..2c02eda 100644 --- a/pkg/git/model.go +++ b/pkg/git/model.go @@ -11,6 +11,15 @@ import ( func (entity *RepoEntity) GetRemotes() (remotes []string, err error) { r := entity.Repository + remotes, err = getRemotes(&r) + if err !=nil { + return nil ,err + } + return remotes, nil +} + +func getRemotes(r *git.Repository) (remotes []string, err error) { + if list, err := r.Remotes(); err != nil { return remotes, err } else { diff --git a/pkg/git/repository.go b/pkg/git/repository.go index a825830..93cdbc9 100644 --- a/pkg/git/repository.go +++ b/pkg/git/repository.go @@ -2,6 +2,7 @@ package git import ( "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/plumbing" "os" "time" ) @@ -13,6 +14,7 @@ type RepoEntity struct { Pushables string Pullables string Branch string + Remote string Marked bool Clean bool } @@ -32,8 +34,8 @@ func InitializeRepository(directory string) (entity *RepoEntity, err error) { } pushable, pullable := UpstreamDifferenceCount(directory) branch, err := CurrentBranchName(directory) - - entity = &RepoEntity{fileInfo.Name(), directory, *r, pushable, pullable, branch, false, isClean(r, fileInfo.Name())} + remotes, err := getRemotes(r) + entity = &RepoEntity{fileInfo.Name(), directory, *r, pushable, pullable, branch, remotes[0], false, isClean(r, fileInfo.Name())} return entity, nil } @@ -55,12 +57,41 @@ func (entity *RepoEntity) Mark() { entity.Marked = true } -func (entity *RepoEntity) UnMark() { +func (entity *RepoEntity) Unmark() { entity.Marked = false } func (entity *RepoEntity) Pull() error { + w, err := entity.Repository.Worktree() + if err != nil { + return err + } + ref := plumbing.NewBranchReferenceName(entity.Branch) + err = w.Pull(&git.PullOptions{ + RemoteName: entity.Remote, + ReferenceName: ref, + }) + if err != nil { + return err + } + + return nil +} + +func (entity *RepoEntity) PullTest() error { time.Sleep(5 * time.Second) + + return nil +} + +func (entity *RepoEntity) Fetch() error { + err := entity.Repository.Fetch(&git.FetchOptions{ + RemoteName: entity.Remote, + }) + if err != nil { + return err + } + return nil } diff --git a/pkg/gui/gui-util.go b/pkg/gui/gui-util.go index cb41430..d842eb8 100644 --- a/pkg/gui/gui-util.go +++ b/pkg/gui/gui-util.go @@ -34,7 +34,7 @@ func (gui *Gui) cursorDown(g *gocui.Gui, v *gocui.View) error { cx, cy := v.Cursor() ox, oy := v.Origin() - ly := len(gui.Repositories) -1 + ly := len(gui.State.Repositories) -1 // if we are at the end we just return if cy+oy == ly { @@ -83,7 +83,7 @@ func (gui *Gui) getSelectedRepository(g *gocui.Gui, v *gocui.View) (*git.RepoEnt return r, err } - for _, sr := range gui.Repositories { + for _, sr := range gui.State.Repositories { if l == sr.Name { return sr, nil } @@ -102,7 +102,7 @@ func (gui *Gui) markRepository(g *gocui.Gui, v *gocui.View) error { if r.Marked != true { r.Mark() } else { - r.UnMark() + r.Unmark() } gui.refreshMain(g) gui.updateSchedule(g) @@ -112,7 +112,7 @@ func (gui *Gui) markRepository(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) markAllRepositories(g *gocui.Gui, v *gocui.View) error { - for _, r := range gui.Repositories { + for _, r := range gui.State.Repositories { r.Mark() } if err := gui.refreshMain(g); err !=nil { @@ -123,8 +123,8 @@ func (gui *Gui) markAllRepositories(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) unMarkAllRepositories(g *gocui.Gui, v *gocui.View) error { - for _, r := range gui.Repositories { - r.UnMark() + for _, r := range gui.State.Repositories { + r.Unmark() } if err := gui.refreshMain(g); err !=nil { return err @@ -140,7 +140,7 @@ func (gui *Gui) refreshMain(g *gocui.Gui) error { return err } mainView.Clear() - for _, r := range gui.Repositories { + for _, r := range gui.State.Repositories { fmt.Fprintln(mainView, r.GetDisplayString()) } return nil @@ -170,7 +170,7 @@ func (gui *Gui) getMarkedEntities() (rs []*git.RepoEntity, err error) { var wg sync.WaitGroup var mu sync.Mutex - for _, r := range gui.Repositories { + for _, r := range gui.State.Repositories { wg.Add(1) go func(repo *git.RepoEntity){ defer wg.Done() diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1c29ce3..55c6c18 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -4,19 +4,44 @@ import ( "github.com/isacikgoz/gitbatch/pkg/git" "github.com/jroimartin/gocui" "fmt" + "time" + "os" + "os/exec" + "io/ioutil" + "log" ) +// SentinelErrors are the errors that have special meaning and need to be checked +// by calling functions. The less of these, the better +type SentinelErrors struct { + ErrSubProcess error +} + // Gui wraps the gocui Gui object which handles rendering and events type Gui struct { g *gocui.Gui - Repositories []*git.RepoEntity + SubProcess *exec.Cmd + State guiState + Errors SentinelErrors +} + +type guiState struct { + Repositories []*git.RepoEntity + Directories []string } // NewGui builds a new gui handler -func NewGui(entities []*git.RepoEntity) (*Gui, error) { +func NewGui(directoies []string) (*Gui, error) { + rs, err := git.LoadRepositoryEntities(directoies) + if err != nil { + return nil, err + } + initialState := guiState{ + Repositories: rs, + } gui := &Gui{ - Repositories: entities, + State: initialState, } return gui, nil @@ -43,6 +68,38 @@ func (gui *Gui) Run() error { return nil } +// RunWithSubprocesses loops, instantiating a new gocui.Gui with each iteration +// if the error returned from a run is a ErrSubProcess, it runs the subprocess +// otherwise it handles the error, possibly by quitting the application +func (gui *Gui) RunWithSubprocesses() { + for { + if err := gui.Run(); err != nil { + if err == gocui.ErrQuit { + break + } else if err == gui.Errors.ErrSubProcess { + gui.SubProcess.Stdin = os.Stdin + gui.SubProcess.Stdout = os.Stdout + gui.SubProcess.Stderr = os.Stderr + gui.SubProcess.Run() + gui.SubProcess.Stdout = ioutil.Discard + gui.SubProcess.Stderr = ioutil.Discard + gui.SubProcess.Stdin = nil + gui.SubProcess = nil + } else { + log.Fatal(err) + } + } + } +} + +func (gui *Gui) goEvery(g *gocui.Gui, interval time.Duration, function func(*gocui.Gui) error) { + go func() { + for range time.Tick(interval) { + function(g) + } + }() +} + func (gui *Gui) layout(g *gocui.Gui) error { maxX, maxY := g.Size() @@ -55,7 +112,7 @@ func (gui *Gui) layout(g *gocui.Gui) error { v.SelBgColor = gocui.ColorWhite v.SelFgColor = gocui.ColorBlack v.Overwrite = true - for _, r := range gui.Repositories { + for _, r := range gui.State.Repositories { fmt.Fprintln(v, r.GetDisplayString()) } diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 2b46138..5f2164e 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -8,7 +8,7 @@ func (gui *Gui) keybindings(g *gocui.Gui) error { if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, gui.quit); err != nil { return err } - if err := g.SetKeybinding("", 'q', gocui.ModNone, gui.quit); err != nil { + if err := g.SetKeybinding("main", 'q', gocui.ModNone, gui.quit); err != nil { return err } if err := g.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, gui.openPullView); err != nil { diff --git a/pkg/gui/pullview.go b/pkg/gui/pullview.go index 14e2a9c..90e3797 100644 --- a/pkg/gui/pullview.go +++ b/pkg/gui/pullview.go @@ -1,7 +1,6 @@ package gui import ( - // "github./com/isacikgoz/gitbatch/pkg/git" "github.com/jroimartin/gocui" "fmt" ) @@ -21,7 +20,6 @@ func (gui *Gui) openPullView(g *gocui.Gui, v *gocui.View) error { line := r.Name + " : " + r.GetActiveRemote() + "/" + r.Branch + " → " + r.GetActiveBranch() fmt.Fprintln(v, line) } - } gui.updateKeyBindingsViewForPullView(g) if _, err := g.SetCurrentView("pull"); err != nil { @@ -44,10 +42,17 @@ func (gui *Gui) closePullView(g *gocui.Gui, v *gocui.View) error { } func (gui *Gui) executePull(g *gocui.Gui, v *gocui.View) error { - go gui.updateKeyBindingsViewForExecution(g) - mrs, _ := gui.getMarkedEntities() + gui.updateKeyBindingsViewForExecution(g) + mrs, _ := gui.getMarkedEntities() + + gui.updateKeyBindingsViewForExecution(g) for _, mr := range mrs { + + go gui.counter(g) + + // here we will be waiting mr.Pull() + mr.Unmark() } gui.refreshMain(g) @@ -83,4 +88,18 @@ func (gui *Gui) updateKeyBindingsViewForExecution(g *gocui.Gui) error { v.Frame = false fmt.Fprintln(v, " PULLING REPOSITORIES") return nil -}
\ No newline at end of file +} + +func (gui *Gui) counter(g *gocui.Gui) { + + v, err := g.View("pull") + if err != nil { + return + } + + g.Update(func(g *gocui.Gui) error { + v.Clear() + fmt.Fprintln(v, "Pulling...") + return nil + }) +} diff --git a/pkg/gui/scheduleview.go b/pkg/gui/scheduleview.go index 7c7a1f2..7a8a1d3 100644 --- a/pkg/gui/scheduleview.go +++ b/pkg/gui/scheduleview.go @@ -15,7 +15,7 @@ func (gui *Gui) updateSchedule(g *gocui.Gui) error { } out.Clear() pullJobs := 0 - for _, r := range gui.Repositories { + for _, r := range gui.State.Repositories { if r.Marked { pullJobs++ } |
