Skip to content

Commit

Permalink
Merge pull request #54 from isacikgoz/develop
Browse files Browse the repository at this point in the history
Develop (0.3.0)
  • Loading branch information
isacikgoz authored Jan 4, 2019
2 parents 5447243 + 68be727 commit 8a7a258
Show file tree
Hide file tree
Showing 52 changed files with 1,502 additions and 1,140 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[![Build Status](https://travis-ci.com/isacikgoz/gitbatch.svg?branch=master)](https://travis-ci.com/isacikgoz/gitbatch) [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/isacikgoz/gitbatch)](https://goreportcard.com/report/github.com/isacikgoz/gitbatch)

## gitbatch
This tool is being built to make your local repositories synchronized with remotes easily. Although the focus is batch jobs, you can still do de facto micro management of your git repositories (e.g *add/reset, stash, commit etc.*)
I like to use polyrepos. I (*was*) often end up walking on many directories and manually pulling updates etc. To make this routine faster, I created a simple tool to handle this job. Although the focus is batch jobs, you can still do de facto micro management of your git repositories (e.g *add/reset, stash, commit etc.*)

Here is the screencast of the app:
[![asciicast](https://asciinema.org/a/QQPVDWVxUR3bvJhIZY3c4PTuG.svg)](https://asciinema.org/a/QQPVDWVxUR3bvJhIZY3c4PTuG)
[![asciicast](https://asciinema.org/a/AiH2y2gwr8sLce40epnIQxRAH.svg)](https://asciinema.org/a/AiH2y2gwr8sLce40epnIQxRAH)

## Installation
To install with go, run the following command;
Expand All @@ -19,7 +19,7 @@ run the `gitbatch` command from the parent of your git repositories. For start-u
For more information see the [wiki pages](https://github.com/isacikgoz/gitbatch/wiki)

## Further goals
- add testing
- **add testing**
- add push
- full src-d/go-git integration (*having some performance issues in such cases*)
- fetch, config, add, reset, commit, status and diff commands are supported but not fully utilized, still using git sometimes
Expand All @@ -34,7 +34,6 @@ Please refer to [Known issues page](https://github.com/isacikgoz/gitbatch/wiki/K
- [logrus](https://github.com/sirupsen/logrus) for logging
- [viper](https://github.com/spf13/viper) for configuration management
- [color](https://github.com/fatih/color) for colored text
- [lazygit](https://github.com/jesseduffield/lazygit) as app template and reference
- [lazygit](https://github.com/jesseduffield/lazygit) for inspiration
- [kingpin](https://github.com/alecthomas/kingpin) for command-line flag&options

I love [lazygit](https://github.com/jesseduffield/lazygit), with that inspiration, decided to build this project to be even more lazy. The rationale was; my daily work is tied to many repositories and I often end up walking on many directories and manually pulling updates etc. To make this routine faster, I created a simple tool to handle this job. I really enjoy working on this project and I hope it will be a useful tool.
12 changes: 6 additions & 6 deletions pkg/app/app.go → app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package app
import (
"os"

"github.com/isacikgoz/gitbatch/pkg/gui"
"github.com/isacikgoz/gitbatch/gui"
log "github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -45,18 +45,18 @@ func Setup(setupConfig *SetupConfig) (*App, error) {
x := appConfig.Mode == "fetch"
y := appConfig.Mode == "pull"
if x == y {
log.Fatal("Unrecognized quick mode: " + appConfig.Mode)
log.Error("Unrecognized quick mode: " + appConfig.Mode)
os.Exit(1)
}
quick(directories, appConfig.Depth, appConfig.Mode)
log.Fatal("Finished")
os.Exit(0)
}

// create a gui.Gui struct and set it as App's gui
app.Gui, err = gui.NewGui(appConfig.Mode, directories)
if err != nil {
// the error types and handling is not considered yer
log.Error(err)
return app, err
// the error types and handling is not considered yet
return nil, err
}
// hopefull everything went smooth as butter
log.Trace("App configuration completed")
Expand Down
File renamed without changes.
47 changes: 18 additions & 29 deletions pkg/app/files.go → app/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"

log "github.com/sirupsen/logrus"
)

// generateDirectories returns poosible git repositories to pipe into git pkg's
// load function
func generateDirectories(directories []string, depth int) (gitDirectories []string) {
func generateDirectories(dirs []string, depth int) []string {
gitDirs := make([]string, 0)
for i := 0; i <= depth; i++ {
nonrepos, repos := walkRecursive(directories, gitDirectories)
directories = nonrepos
gitDirectories = repos
nonrepos, repos := walkRecursive(dirs, gitDirs)
dirs = nonrepos
gitDirs = repos
}
return gitDirectories
return gitDirs
}

// returns given values, first search directories and second stands for possible
Expand All @@ -33,7 +33,7 @@ func walkRecursive(search, appendant []string) ([]string, []string) {
if err != nil {
log.WithFields(log.Fields{
"directory": search[i],
}).Trace("Can't read directory")
}).WithError(err).Trace("Can't read directory")
continue
}
// since we started to search let's get rid of it and remove from search
Expand All @@ -49,14 +49,16 @@ func walkRecursive(search, appendant []string) ([]string, []string) {

// seperateDirectories is to find all the files in given path. This method
// does not check if the given file is a valid git repositories
func seperateDirectories(directory string) (directories, gitDirectories []string, err error) {
func seperateDirectories(directory string) ([]string, []string, error) {
dirs := make([]string, 0)
gitDirs := make([]string, 0)
files, err := ioutil.ReadDir(directory)
// can we read the directory?
if err != nil {
log.WithFields(log.Fields{
"directory": directory,
}).Trace("Can't read directory")
return directories, gitDirectories, nil
return nil, nil, nil
}
for _, f := range files {
repo := directory + string(os.PathSeparator) + f.Name()
Expand All @@ -66,38 +68,25 @@ func seperateDirectories(directory string) (directories, gitDirectories []string
log.WithFields(log.Fields{
"file": file,
"directory": repo,
}).Trace("Failed to open file in the directory")
}).WithError(err).Trace("Failed to open file in the directory")
file.Close()
continue
}
dir, err := filepath.Abs(file.Name())
if err != nil {
return nil, nil, err
file.Close()
continue
}
// with this approach, we ignore submodule or sub repositoreis in a git repository
ff, err := os.Open(dir + string(os.PathSeparator) + ".git")
if err != nil {
directories = append(directories, dir)
dirs = append(dirs, dir)
} else {
gitDirectories = append(gitDirectories, dir)
gitDirs = append(gitDirs, dir)
}
ff.Close()
file.Close()

}
return directories, gitDirectories, nil
}

// takes a fileInfo slice and returns it with the ones matches with the
// pattern string
func filterDirectories(files []os.FileInfo, pattern string) []os.FileInfo {
var filteredRepos []os.FileInfo
for _, f := range files {
// it is just a simple filter
if strings.Contains(f.Name(), pattern) && f.Name() != ".git" {
filteredRepos = append(filteredRepos, f)
} else {
continue
}
}
return filteredRepos
return dirs, gitDirs, nil
}
9 changes: 6 additions & 3 deletions pkg/app/quick.go → app/quick.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
"sync"
"time"

"github.com/isacikgoz/gitbatch/pkg/git"
"github.com/isacikgoz/gitbatch/core/command"
"github.com/isacikgoz/gitbatch/core/git"
)

func quick(directories []string, depth int, mode string) {
Expand Down Expand Up @@ -35,12 +36,14 @@ func operate(directory, mode string) error {
}
switch mode {
case "fetch":
return git.Fetch(r, git.FetchOptions{
return command.Fetch(r, command.FetchOptions{
RemoteName: "origin",
Progress: true,
})
case "pull":
return git.Pull(r, git.PullOptions{
return command.Pull(r, command.PullOptions{
RemoteName: "origin",
Progress: true,
})
}
return nil
Expand Down
21 changes: 11 additions & 10 deletions pkg/git/cmd-add.go → core/command/add.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package git
package command

import (
"errors"

"github.com/isacikgoz/gitbatch/core/git"
log "github.com/sirupsen/logrus"
)

Expand All @@ -25,39 +26,39 @@ type AddOptions struct {
}

// Add is a wrapper function for "git add" command
func Add(e *RepoEntity, file *File, option AddOptions) error {
func Add(r *git.Repository, file *File, option AddOptions) error {
addCmdMode = addCmdModeNative
if option.Update || option.Force || option.DryRun {
addCmdMode = addCmdModeLegacy
}
switch addCmdMode {
case addCmdModeLegacy:
err := addWithGit(e, file, option)
err := addWithGit(r, file, option)
return err
case addCmdModeNative:
err := addWithGoGit(e, file)
err := addWithGoGit(r, file)
return err
}
return errors.New("Unhandled add operation")
}

// AddAll function is the wrapper of "git add ." command
func AddAll(e *RepoEntity, option AddOptions) error {
func AddAll(r *git.Repository, option AddOptions) error {
args := make([]string, 0)
args = append(args, addCommand)
if option.DryRun {
args = append(args, "--dry-run")
}
args = append(args, ".")
out, err := GenericGitCommandWithOutput(e.AbsPath, args)
out, err := GenericGitCommandWithOutput(r.AbsPath, args)
if err != nil {
log.Warn("Error while add command")
return errors.New(out + "\n" + err.Error())
}
return nil
}

func addWithGit(e *RepoEntity, file *File, option AddOptions) error {
func addWithGit(r *git.Repository, file *File, option AddOptions) error {
args := make([]string, 0)
args = append(args, addCommand)
args = append(args, file.Name)
Expand All @@ -70,16 +71,16 @@ func addWithGit(e *RepoEntity, file *File, option AddOptions) error {
if option.DryRun {
args = append(args, "--dry-run")
}
out, err := GenericGitCommandWithOutput(e.AbsPath, args)
out, err := GenericGitCommandWithOutput(r.AbsPath, args)
if err != nil {
log.Warn("Error while add command")
return errors.New(out + "\n" + err.Error())
}
return nil
}

func addWithGoGit(e *RepoEntity, file *File) error {
w, err := e.Repository.Worktree()
func addWithGoGit(r *git.Repository, file *File) error {
w, err := r.Repo.Worktree()
if err != nil {
return err
}
Expand Down
51 changes: 49 additions & 2 deletions pkg/helpers/command.go → core/command/cmd.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package helpers
package command

import (
"log"
"os/exec"
"strings"
"syscall"
)

Expand All @@ -14,7 +15,7 @@ func RunCommandWithOutput(dir string, command string, args []string) (string, er
if dir != "" {
cmd.Dir = dir
}
output, err := cmd.Output()
output, err := cmd.CombinedOutput()
return string(output), err
}

Expand Down Expand Up @@ -49,3 +50,49 @@ func GetCommandStatus(dir string, command string, args []string) (int, error) {
}
return -1, err
}

// TrimTrailingNewline removes the trailing new line form a string. this method
// is used mostly on outputs of a command
func TrimTrailingNewline(str string) string {
if strings.HasSuffix(str, "\n") {
return str[:len(str)-1]
}
return str
}

// GenericGitCommand runs any git command without expecting output
func GenericGitCommand(repoPath string, args []string) error {
_, err := RunCommandWithOutput(repoPath, "git", args)
if err != nil {
return err
}
return nil
}

// GenericGitCommandWithOutput runs any git command with returning output
func GenericGitCommandWithOutput(repoPath string, args []string) (string, error) {
out, err := RunCommandWithOutput(repoPath, "git", args)
if err != nil {
return out, err
}
return TrimTrailingNewline(out), nil
}

// GenericGitCommandWithErrorOutput runs any git command with returning output
func GenericGitCommandWithErrorOutput(repoPath string, args []string) (string, error) {
out, err := RunCommandWithOutput(repoPath, "git", args)
if err != nil {
return TrimTrailingNewline(out), err
}
return TrimTrailingNewline(out), nil
}

// GitShow is conventional git show command without any argument
func GitShow(repoPath, hash string) string {
args := []string{"show", hash}
diff, err := RunCommandWithOutput(repoPath, "git", args)
if err != nil {
return "?"
}
return diff
}
Loading

0 comments on commit 8a7a258

Please sign in to comment.