diff options
| 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 |
| commit | af7b9a486062d85223a16af1e08660aab8c4b260 (patch) | |
| tree | d21c1a5a1ff747b5774235561ecb6e4fd9c57e98 | |
| parent | login implementation stablized, some renaming, some refactoring and updated r... (diff) | |
| download | gitbatch-af7b9a486062d85223a16af1e08660aab8c4b260.tar.gz | |
migrating commands to go-git
| -rw-r--r-- | pkg/git/cmd-add.go | 63 | ||||
| -rw-r--r-- | pkg/git/cmd-commit.go | 93 | ||||
| -rw-r--r-- | pkg/git/cmd-config.go | 107 | ||||
| -rw-r--r-- | pkg/git/cmd-reset.go | 113 | ||||
| -rw-r--r-- | pkg/git/cmd-status.go | 44 | ||||
| -rw-r--r-- | pkg/gui/stagedview.go | 17 | ||||
| -rw-r--r-- | pkg/gui/statusview.go | 18 | ||||
| -rw-r--r-- | pkg/gui/unstagedview.go | 4 |
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) |
