summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorİbrahim Serdar Açıkgöz <serdaracikgoz86@gmail.com>2018-12-13 18:33:19 +0300
committerİbrahim Serdar Açıkgöz <serdaracikgoz86@gmail.com>2018-12-13 18:33:19 +0300
commitaf7b9a486062d85223a16af1e08660aab8c4b260 (patch)
treed21c1a5a1ff747b5774235561ecb6e4fd9c57e98
parentlogin implementation stablized, some renaming, some refactoring and updated r... (diff)
downloadgitbatch-af7b9a486062d85223a16af1e08660aab8c4b260.tar.gz
migrating commands to go-git
-rw-r--r--pkg/git/cmd-add.go63
-rw-r--r--pkg/git/cmd-commit.go93
-rw-r--r--pkg/git/cmd-config.go107
-rw-r--r--pkg/git/cmd-reset.go113
-rw-r--r--pkg/git/cmd-status.go44
-rw-r--r--pkg/gui/stagedview.go17
-rw-r--r--pkg/gui/statusview.go18
-rw-r--r--pkg/gui/unstagedview.go4
8 files changed, 410 insertions, 49 deletions
diff --git a/pkg/git/cmd-add.go b/pkg/git/cmd-add.go
index 61fd587..649bad2 100644
--- a/pkg/git/cmd-add.go
+++ b/pkg/git/cmd-add.go
@@ -2,35 +2,54 @@ package git
import (
"errors"
- "strings"
log "github.com/sirupsen/logrus"
)
-var addCommand = "add"
+var (
+ addCmdMode string
+
+ addCommand = "add"
+ addCmdModeLegacy = "git"
+ addCmdModeNative = "go-git"
+)
// AddOptions defines the rules for "git add" command
type AddOptions struct {
+ // Update
Update bool
- Force bool
+ // Force
+ Force bool
+ // DryRun
DryRun bool
}
// Add is a wrapper function for "git add" command
-func (file *File) Add(option AddOptions) error {
- args := make([]string, 0)
- args = append(args, addCommand)
- args = append(args, file.Name)
- if option.Update {
- args = append(args, "--update")
+func Add(entity *RepoEntity, file *File, option AddOptions) error {
+ addCmdMode = addCmdModeNative
+ if option.Update || option.Force || option.DryRun {
+ addCmdMode = addCmdModeLegacy
}
- if option.Force {
- args = append(args, "--force")
+ switch addCmdMode {
+ case addCmdModeLegacy:
+ err := addWithGit(entity, file, option)
+ return err
+ case addCmdModeNative:
+ err := addWithGoGit(entity, file)
+ return err
}
+ return errors.New("Unhandled add operation")
+}
+
+// AddAll function is the wrapper of "git add ." command
+func AddAll(entity *RepoEntity, option AddOptions) error {
+ args := make([]string, 0)
+ args = append(args, addCommand)
if option.DryRun {
args = append(args, "--dry-run")
}
- out, err := GenericGitCommandWithOutput(strings.TrimSuffix(file.AbsPath, file.Name), args)
+ args = append(args, ".")
+ out, err := GenericGitCommandWithOutput(entity.AbsPath, args)
if err != nil {
log.Warn("Error while add command")
return errors.New(out + "\n" + err.Error())
@@ -38,14 +57,19 @@ func (file *File) Add(option AddOptions) error {
return nil
}
-// AddAll function is the wrapper of "git add ." command
-func (entity *RepoEntity) AddAll(option AddOptions) error {
+func addWithGit(entity *RepoEntity, file *File, option AddOptions) error {
args := make([]string, 0)
args = append(args, addCommand)
+ args = append(args, file.Name)
+ if option.Update {
+ args = append(args, "--update")
+ }
+ if option.Force {
+ args = append(args, "--force")
+ }
if option.DryRun {
args = append(args, "--dry-run")
}
- args = append(args, ".")
out, err := GenericGitCommandWithOutput(entity.AbsPath, args)
if err != nil {
log.Warn("Error while add command")
@@ -53,3 +77,12 @@ func (entity *RepoEntity) AddAll(option AddOptions) error {
}
return nil
}
+
+func addWithGoGit(entity *RepoEntity, file *File) error {
+ w, err := entity.Repository.Worktree()
+ if err != nil {
+ return err
+ }
+ _, err = w.Add(file.Name)
+ return nil
+}
diff --git a/pkg/git/cmd-commit.go b/pkg/git/cmd-commit.go
new file mode 100644
index 0000000..8ea5bfe
--- /dev/null
+++ b/pkg/git/cmd-commit.go
@@ -0,0 +1,93 @@
+package git
+
+import (
+ "errors"
+ "time"
+
+ log "github.com/sirupsen/logrus"
+ "gopkg.in/src-d/go-git.v4"
+ "gopkg.in/src-d/go-git.v4/plumbing/object"
+)
+
+var (
+ commitCmdMode string
+
+ commitCommand = "commit"
+ commitCmdModeLegacy = "git"
+ commitCmdModeNative = "go-git"
+)
+
+// CommitOptions defines the rules for commit operation
+type CommitOptions struct {
+ // CommitMsg
+ CommitMsg string
+ // User
+ User string
+ // Email
+ Email string
+}
+
+// CommitCommand
+func CommitCommand(entity *RepoEntity, options CommitOptions) (err error) {
+ // here we configure commit operation
+ // default mode is go-git (this may be configured)
+ commitCmdMode = commitCmdModeNative
+
+ switch commitCmdMode {
+ case commitCmdModeLegacy:
+ err = commitWithGit(entity, options)
+ return err
+ case commitCmdModeNative:
+ err = commitWithGoGit(entity, options)
+ return err
+ }
+ return errors.New("Unhandled commit operation")
+}
+
+// commitWithGit is simply a bare git commit -m <msg> command which is flexible
+func commitWithGit(entity *RepoEntity, options CommitOptions) (err error) {
+ args := make([]string, 0)
+ args = append(args, commitCommand)
+ args = append(args, "-m")
+ // parse options to command line arguments
+ if len(options.CommitMsg) > 0 {
+ args = append(args, options.CommitMsg)
+ }
+ if err := GenericGitCommand(entity.AbsPath, args); err != nil {
+ log.Warn("Error at git command (commit)")
+ return err
+ }
+ // till this step everything should be ok
+ err = entity.Refresh()
+ return err
+}
+
+// commitWithGoGit is the primary commit method
+func commitWithGoGit(entity *RepoEntity, options CommitOptions) (err error) {
+ config, err := entity.Repository.Config()
+ if err != nil {
+ return err
+ }
+ name := config.Raw.Section("user").Option("name")
+ email := config.Raw.Section("user").Option("email")
+ opt := &git.CommitOptions{
+ Author: &object.Signature{
+ Name: name,
+ Email: email,
+ When: time.Now(),
+ },
+ }
+
+ w, err := entity.Repository.Worktree()
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Commit(options.CommitMsg, opt)
+ if err != nil {
+ return err
+ }
+ // till this step everything should be ok
+ err = entity.Refresh()
+ return err
+}
diff --git a/pkg/git/cmd-config.go b/pkg/git/cmd-config.go
new file mode 100644
index 0000000..94efe33
--- /dev/null
+++ b/pkg/git/cmd-config.go
@@ -0,0 +1,107 @@
+package git
+
+import (
+ "errors"
+
+ log "github.com/sirupsen/logrus"
+)
+
+var (
+ configCmdMode string
+
+ configCommand = "config"
+ configCmdModeLegacy = "git"
+ configCmdModeNative = "go-git"
+)
+
+// CommitOptions defines the rules for commit operation
+type ConfigOptions struct {
+ // Section
+ Section string
+ // Option
+ Option string
+ // Site should be Global or Local
+ Site ConfigSite
+}
+
+type ConfigSite string
+
+const (
+ // ConfigStieLocal
+ ConfigStieLocal ConfigSite = "local"
+ // ConfgiSiteGlobal
+ ConfgiSiteGlobal ConfigSite = "global"
+)
+
+// Config
+func Config(entity *RepoEntity, options ConfigOptions) (value string, err error) {
+ // here we configure config operation
+ // default mode is go-git (this may be configured)
+ configCmdMode = configCmdModeNative
+
+ switch configCmdMode {
+ case configCmdModeLegacy:
+ value, err = configWithGit(entity, options)
+ return value, err
+ case configCmdModeNative:
+ value, err = configWithGoGit(entity, options)
+ return value, err
+ }
+ return value, errors.New("Unhandled config operation")
+}
+
+// configWithGit is simply a bare git commit -m <msg> command which is flexible
+func configWithGit(entity *RepoEntity, options ConfigOptions) (value string, err error) {
+ args := make([]string, 0)
+ args = append(args, commitCommand)
+ if len(string(options.Site)) > 0 {
+ args = append(args, "--"+string(options.Site))
+ }
+ args = append(args, "--get")
+ args = append(args, options.Section+"."+options.Option)
+ // parse options to command line arguments
+ out, err := GenericGitCommandWithOutput(entity.AbsPath, args)
+ if err != nil {
+ log.Warn("Error at git command (commit)")
+ return out, err
+ }
+ // till this step everything should be ok
+ return out, entity.Refresh()
+}
+
+// commitWithGoGit is the primary commit method
+func configWithGoGit(entity *RepoEntity, options ConfigOptions) (value string, err error) {
+ config, err := entity.Repository.Config()
+ if err != nil {
+ return value, err
+ }
+ value = config.Raw.Section(options.Section).Option(options.Option)
+ return value, entity.Refresh()
+}
+
+// AddConfig
+func AddConfig(entity *RepoEntity, options ConfigOptions, value string) (err error) {
+ err = addConfigWithGit(entity, options, value)
+ return err
+
+}
+
+// addConfigWithGit is simply a bare git commit -m <msg> command which is flexible
+func addConfigWithGit(entity *RepoEntity, options ConfigOptions, value string) (err error) {
+ args := make([]string, 0)
+ args = append(args, commitCommand)
+ if len(string(options.Site)) > 0 {
+ args = append(args, "--"+string(options.Site))
+ }
+ args = append(args, "--add")
+ args = append(args, options.Section+"."+options.Option)
+ if len(value) > 0 {
+ args = append(args, value)
+ }
+ if err := GenericGitCommand(entity.AbsPath, args); err != nil {
+ log.Warn("Error at git command (commit)")
+ return err
+ }
+ // till this step everything should be ok
+ return entity.Refresh()
+}
diff --git a/pkg/git/cmd-reset.go b/pkg/git/cmd-reset.go
index f93225c..2e6ed91 100644
--- a/pkg/git/cmd-reset.go
+++ b/pkg/git/cmd-reset.go
@@ -2,49 +2,101 @@ package git
import (
"errors"
- "strings"
log "github.com/sirupsen/logrus"
+ "gopkg.in/src-d/go-git.v4"
+ "gopkg.in/src-d/go-git.v4/plumbing"
)
-var resetCommand = "reset"
+var (
+ resetCmdMode string
+
+ resetCommand = "reset"
+ resetCmdModeLegacy = "git"
+ resetCmdModeNative = "go-git"
+)
// ResetOptions defines the rules of git reset command
type ResetOptions struct {
- Hard bool
- Merge bool
- Keep bool
+ // Hash is the reference to be resetted
+ Hash string
+ // Type is the mode of a reset operation
+ Rtype ResetType
}
+type ResetType string
+
+const (
+ // ResetHard Resets the index and working tree. Any changes to tracked
+ // files in the working tree since <commit> are discarded.
+ ResetHard ResetType = "hard"
+ // ResetMixed Resets the index but not the working tree (i.e., the changed
+ // files are preserved but not marked for commit) and reports what has not
+ // been updated. This is the default action.
+ ResetMixed ResetType = "mixed"
+ // ResetMerge Resets the index and updates the files in the working tree
+ // that are different between <commit> and HEAD, but keeps those which are
+ // different between the index and working tree
+ ResetMerge ResetType = "merge"
+ // ResetSoft Does not touch the index file or the working tree at all
+ // (but resets the head to <commit>
+ ResetSoft ResetType = "soft"
+ // ResetKeep Resets index entries and updates files in the working tree
+ // that are different between <commit> and HEAD
+ ResetKeep ResetType = "keep"
+)
+
// Reset is the wrapper of "git reset" command
-func (file *File) Reset(option ResetOptions) error {
+func Reset(entity *RepoEntity, file *File, option ResetOptions) error {
+ resetCmdMode = addCmdModeLegacy
+
+ switch resetCmdMode {
+ case resetCmdModeLegacy:
+ err := resetWithGit(entity, file, option)
+ return err
+ case resetCmdModeNative:
+
+ }
+ return errors.New("Unhandled reset operation")
+}
+
+func resetWithGit(entity *RepoEntity, file *File, option ResetOptions) error {
args := make([]string, 0)
args = append(args, resetCommand)
+
args = append(args, "--")
args = append(args, file.Name)
- if option.Hard {
- args = append(args, "--hard")
- }
- if option.Merge {
- args = append(args, "--merge")
+ if len(option.Rtype) > 0 {
+ args = append(args, "--"+string(option.Rtype))
}
- if option.Keep {
- args = append(args, "--keep")
- }
- out, err := GenericGitCommandWithOutput(strings.TrimSuffix(file.AbsPath, file.Name), args)
+ out, err := GenericGitCommandWithOutput(entity.AbsPath, args)
if err != nil {
- log.Warn("Error while add command")
+ log.Warn("Error while reset command")
return errors.New(out + "\n" + err.Error())
}
return nil
}
// ResetAll resets the changes in a repository, should be used wise
-func (entity *RepoEntity) ResetAll(option ResetOptions) error {
+func ResetAll(entity *RepoEntity, option ResetOptions) error {
+ resetCmdMode = addCmdModeNative
+
+ switch resetCmdMode {
+ case resetCmdModeLegacy:
+ err := resetAllWithGit(entity, option)
+ return err
+ case resetCmdModeNative:
+ err := resetAllWithGoGit(entity, option)
+ return err
+ }
+ return errors.New("Unhandled reset operation")
+}
+
+func resetAllWithGit(entity *RepoEntity, option ResetOptions) error {
args := make([]string, 0)
args = append(args, resetCommand)
- if option.Hard {
- args = append(args, "--hard")
+ if len(option.Rtype) > 0 {
+ args = append(args, "--"+string(option.Rtype))
}
out, err := GenericGitCommandWithOutput(entity.AbsPath, args)
if err != nil {
@@ -53,3 +105,26 @@ func (entity *RepoEntity) ResetAll(option ResetOptions) error {
}
return nil
}
+
+func resetAllWithGoGit(entity *RepoEntity, option ResetOptions) error {
+ w, err := entity.Repository.Worktree()
+ if err != nil {
+ return err
+ }
+ var mode git.ResetMode
+ switch option.Rtype {
+ case ResetHard:
+ mode = git.HardReset
+ case ResetMixed:
+ mode = git.MixedReset
+ case ResetMerge:
+ mode = git.MergeReset
+ case ResetSoft:
+ mode = git.SoftReset
+ }
+ err = w.Reset(&git.ResetOptions{
+ Commit: plumbing.NewHash(option.Hash),
+ Mode: mode,
+ })
+ return err
+}
diff --git a/pkg/git/cmd-status.go b/pkg/git/cmd-status.go
index 4cca604..d3d1918 100644
--- a/pkg/git/cmd-status.go
+++ b/pkg/git/cmd-status.go
@@ -1,6 +1,7 @@
package git
import (
+ "errors"
"os"
"regexp"
"strings"
@@ -8,7 +9,13 @@ import (
log "github.com/sirupsen/logrus"
)
-var statusCommand = "status"
+var (
+ statusCmdMode string
+
+ statusCommand = "status"
+ statusCmdModeLegacy = "git"
+ statusCmdModeNative = "go-git"
+)
// File represents the status of a file in an index or work tree
type File struct {
@@ -55,9 +62,21 @@ func shortStatus(entity *RepoEntity, option string) string {
return out
}
+func Status(entity *RepoEntity) ([]*File, error) {
+ statusCmdMode = statusCmdModeNative
+
+ switch statusCmdMode {
+ case statusCmdModeLegacy:
+ return statusWithGit(entity)
+ case statusCmdModeNative:
+ return statusWithGoGit(entity)
+ }
+ return nil, errors.New("Unhandled status operation")
+}
+
// LoadFiles function simply commands a git status and collects output in a
// structured way
-func (entity *RepoEntity) LoadFiles() ([]*File, error) {
+func statusWithGit(entity *RepoEntity) ([]*File, error) {
files := make([]*File, 0)
output := shortStatus(entity, "--untracked-files=all")
if len(output) == 0 {
@@ -80,6 +99,27 @@ func (entity *RepoEntity) LoadFiles() ([]*File, error) {
return files, nil
}
+func statusWithGoGit(entity *RepoEntity) ([]*File, error) {
+ files := make([]*File, 0)
+ w, err := entity.Repository.Worktree()
+ if err != nil {
+ return files, err
+ }
+ s, err := w.Status()
+ if err != nil {
+ return files, err
+ }
+ for k, v := range s {
+ files = append(files, &File{
+ Name: k,
+ AbsPath: entity.AbsPath + string(os.PathSeparator) + k,
+ X: FileStatus(v.Staging),
+ Y: FileStatus(v.Worktree),
+ })
+ }
+ return files, nil
+}
+
// Diff is a wrapper of "git diff" command for a file to compare with HEAD rev
func (file *File) Diff() (output string, err error) {
args := make([]string, 0)
diff --git a/pkg/gui/stagedview.go b/pkg/gui/stagedview.go
index f12c06d..294c0f7 100644
--- a/pkg/gui/stagedview.go
+++ b/pkg/gui/stagedview.go
@@ -36,20 +36,25 @@ func (gui *Gui) resetChanges(g *gocui.Gui, v *gocui.View) error {
}
_, cy := v.Cursor()
_, oy := v.Origin()
- if err := files[cy+oy].Reset(git.ResetOptions{}); err != nil {
+ if err := git.Reset(entity, files[cy+oy], git.ResetOptions{}); err != nil {
return err
}
- err = refreshAllStatusView(g, entity)
- return err
+ return refreshAllStatusView(g, entity)
}
func (gui *Gui) resetAllChanges(g *gocui.Gui, v *gocui.View) error {
entity := gui.getSelectedRepository()
- if err := entity.ResetAll(git.ResetOptions{}); err != nil {
+ ref, err := entity.Repository.Head()
+ if err != nil {
+ return err
+ }
+ if err := git.ResetAll(entity, git.ResetOptions{
+ Hash: ref.Hash().String(),
+ Rtype: git.ResetMixed,
+ }); err != nil {
return err
}
- err := refreshAllStatusView(g, entity)
- return err
+ return refreshAllStatusView(g, entity)
}
// refresh the main view and re-render the repository representations
diff --git a/pkg/gui/statusview.go b/pkg/gui/statusview.go
index b241ed6..c0a9c65 100644
--- a/pkg/gui/statusview.go
+++ b/pkg/gui/statusview.go
@@ -1,6 +1,7 @@
package gui
import (
+ "errors"
"fmt"
"time"
@@ -123,7 +124,7 @@ func (gui *Gui) closeStatusView(g *gocui.Gui, v *gocui.View) error {
}
func generateFileLists(entity *git.RepoEntity) (staged, unstaged []*git.File, err error) {
- files, err := entity.LoadFiles()
+ files, err := git.Status(entity)
if err != nil {
return nil, nil, err
}
@@ -195,12 +196,19 @@ func (gui *Gui) submitCommitMessageView(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return err
}
- // WIP: This better be removed to git pkg
- // TODO: read config and get name & e-mail
+ config, err := entity.Repository.Config()
+ if err != nil {
+ return err
+ }
+ name := config.Raw.Section("user").Option("name")
+ email := config.Raw.Section("user").Option("email")
+ if len(email) <= 0 {
+ return errors.New("User email needs to be provided")
+ }
_, err = w.Commit(v.ViewBuffer(), &ggt.CommitOptions{
Author: &object.Signature{
- Name: "İbrahim Serdar Açıkgöz",
- Email: "serdaracikgoz86@gmail.com",
+ Name: name,
+ Email: email,
When: time.Now(),
},
})
diff --git a/pkg/gui/unstagedview.go b/pkg/gui/unstagedview.go
index ef4866f..01b16de 100644
--- a/pkg/gui/unstagedview.go
+++ b/pkg/gui/unstagedview.go
@@ -34,7 +34,7 @@ func (gui *Gui) addChanges(g *gocui.Gui, v *gocui.View) error {
}
_, cy := v.Cursor()
_, oy := v.Origin()
- if err := files[cy+oy].Add(git.AddOptions{}); err != nil {
+ if err := git.Add(entity, files[cy+oy], git.AddOptions{}); err != nil {
return err
}
err = refreshAllStatusView(g, entity)
@@ -43,7 +43,7 @@ func (gui *Gui) addChanges(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) addAllChanges(g *gocui.Gui, v *gocui.View) error {
entity := gui.getSelectedRepository()
- if err := entity.AddAll(git.AddOptions{}); err != nil {
+ if err := git.AddAll(entity, git.AddOptions{}); err != nil {
return err
}
err := refreshAllStatusView(g, entity)