1
0
Fork 0
mirror of https://git.sr.ht/~rjarry/aerc synced 2025-07-07 04:00:21 +02:00
aerc/lib/pama/revctrl/git.go
Robin Jarry 8edf7b0e4d log: move package to lib
This has nothing to do at the root of the source tree.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Bence Ferdinandy <bence@ferdinandy.com>
2024-02-14 23:04:38 +01:00

128 lines
3 KiB
Go

package revctrl
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"git.sr.ht/~rjarry/aerc/lib/log"
"git.sr.ht/~rjarry/aerc/lib/pama/models"
)
func init() {
register("git", newGit)
}
func newGit(s string) models.RevisionController {
return &git{path: strings.TrimSpace(s)}
}
type git struct {
path string
}
func (g git) Support() bool {
_, exitcode, err := g.do("rev-parse")
return exitcode == 0 && err == nil
}
func (g git) Root() (string, error) {
s, _, err := g.do("rev-parse", "--show-toplevel")
return s, err
}
func (g git) Head() (string, error) {
s, _, err := g.do("rev-list", "-n 1", "HEAD")
return s, err
}
func (g git) History(commit string) ([]string, error) {
s, _, err := g.do("rev-list", "--reverse", fmt.Sprintf("%s..HEAD", commit))
return strings.Fields(s), err
}
func (g git) Subject(commit string) string {
s, exitcode, err := g.do("log", "-1", "--pretty=%s", commit)
if exitcode > 0 || err != nil {
return ""
}
return s
}
func (g git) Author(commit string) string {
s, exitcode, err := g.do("log", "-1", "--pretty=%an", commit)
if exitcode > 0 || err != nil {
return ""
}
return s
}
func (g git) Date(commit string) string {
s, exitcode, err := g.do("log", "-1", "--pretty=%as", commit)
if exitcode > 0 || err != nil {
return ""
}
return s
}
func (g git) Drop(commit string) error {
_, exitcode, err := g.do("rebase", "--onto", commit+"^", commit)
if exitcode > 0 {
return fmt.Errorf("failed to drop commit %s", commit)
}
return err
}
func (g git) Exists(commit string) bool {
_, exitcode, err := g.do("merge-base", "--is-ancestor", commit, "HEAD")
return exitcode == 0 && err == nil
}
func (g git) Clean() bool {
// is a rebase in progress?
dirs := []string{"rebase-merge", "rebase-apply"}
for _, dir := range dirs {
relPath, _, err := g.do("rev-parse", "--git-path", dir)
if err == nil {
if _, err := os.Stat(filepath.Join(g.path, relPath)); !os.IsNotExist(err) {
log.Errorf("%s exists: another rebase in progress..", dir)
return false
}
}
}
// are there unstaged changes?
s, exitcode, err := g.do("diff-index", "HEAD")
return len(s) == 0 && exitcode == 0 && err == nil
}
func (g git) CreateWorktree(target, commit string) error {
_, exitcode, err := g.do("worktree", "add", target, commit)
if exitcode > 0 {
return fmt.Errorf("failed to create worktree in %s: %w", target, err)
}
return err
}
func (g git) DeleteWorktree(target string) error {
_, exitcode, err := g.do("worktree", "remove", target)
if exitcode > 0 {
return fmt.Errorf("failed to delete worktree in %s: %w", target, err)
}
return err
}
func (g git) ApplyCmd() string {
// TODO: should we return a *exec.Cmd instead of a string?
return fmt.Sprintf("git -C %s am -3 --empty drop", g.path)
}
func (g git) do(args ...string) (string, int, error) {
proc := exec.Command("git", "-C", g.path)
proc.Args = append(proc.Args, args...)
proc.Env = os.Environ()
result, err := proc.Output()
return string(bytes.TrimSpace(result)), proc.ProcessState.ExitCode(), err
}