263 lines
6.0 KiB
Go
263 lines
6.0 KiB
Go
//go:build !gogit
|
|
|
|
package git
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
)
|
|
|
|
type Repository interface {
|
|
Branches() ([]*plumbing.Reference, error)
|
|
// Auth(username string, password string) error
|
|
FetchContext(ctx context.Context, opts *git.FetchOptions) error
|
|
PushContext(ctx context.Context, opts *git.PushOptions) error
|
|
Head() (*plumbing.Reference, error)
|
|
Worktree() (Worktree, error)
|
|
}
|
|
|
|
type Worktree interface {
|
|
Checkout(*git.CheckoutOptions) error
|
|
PullContext(ctx context.Context, opts *git.PullOptions) error
|
|
Status() (git.Status, error)
|
|
AddWithOptions(opts *git.AddOptions) error
|
|
Commit(msg string, opts *git.CommitOptions) (plumbing.Hash, error)
|
|
Reset(opts *git.ResetOptions) error
|
|
}
|
|
|
|
type repository struct {
|
|
gocmd string
|
|
path string
|
|
// authUsername string
|
|
// authPassword string
|
|
}
|
|
|
|
func PlainOpenWithOptions(path string, opts *git.PlainOpenOptions) (Repository, error) {
|
|
gopath, err := exec.LookPath("git")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &repository{path: path, gocmd: gopath}, nil
|
|
}
|
|
|
|
/*
|
|
func (r *repository) Auth(username string, password string) error {
|
|
r.authUsername = username
|
|
r.authPassword = password
|
|
return nil
|
|
}
|
|
*/
|
|
|
|
func (r *repository) Branches() ([]*plumbing.Reference, error) {
|
|
var branches []*plumbing.Reference
|
|
cmd := exec.Command(r.gocmd, "show-ref", "--branches")
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
br := bytes.NewBuffer(buf)
|
|
for {
|
|
line, err := br.ReadString('\n')
|
|
if err != nil {
|
|
if err == io.EOF && line == "" {
|
|
break
|
|
} else if err != io.EOF && line == "" {
|
|
return nil, err
|
|
}
|
|
}
|
|
fields := strings.Fields(line)
|
|
if len(fields) != 2 {
|
|
return nil, fmt.Errorf("invalid fields %s", line)
|
|
}
|
|
branches = append(branches, plumbing.NewReferenceFromStrings(fields[1], fields[0]))
|
|
}
|
|
return branches, nil
|
|
}
|
|
|
|
func (r *repository) FetchContext(ctx context.Context, opts *git.FetchOptions) error {
|
|
args := []string{"fetch"}
|
|
if opts.Force {
|
|
args = append(args, "-f")
|
|
}
|
|
cmd := exec.CommandContext(ctx, r.gocmd, args...)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *repository) PushContext(ctx context.Context, opts *git.PushOptions) error {
|
|
args := []string{"push"}
|
|
|
|
if opts.Force {
|
|
args = append(args, "-f")
|
|
}
|
|
|
|
/* TODO
|
|
var refs []string
|
|
for _, ref := range opts.RefSpecs {
|
|
refs = append(refs, ref.String())
|
|
}
|
|
|
|
args = append(args, strings.Join(refs, " "))
|
|
*/
|
|
cmd := exec.CommandContext(ctx, r.gocmd, args...)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *repository) Head() (*plumbing.Reference, error) {
|
|
var head *plumbing.Reference
|
|
cmd := exec.Command(r.gocmd, "symbolic-ref", "--short", "HEAD")
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
br := bytes.NewBuffer(buf)
|
|
for {
|
|
line, err := br.ReadString('\n')
|
|
if err != nil {
|
|
if err == io.EOF && line == "" {
|
|
break
|
|
} else if err != io.EOF && line == "" {
|
|
return nil, err
|
|
}
|
|
}
|
|
fields := strings.Fields(line)
|
|
if len(fields) != 2 {
|
|
return nil, fmt.Errorf("invalid fields %s", line)
|
|
}
|
|
head = plumbing.NewReferenceFromStrings("HEAD", fields[0])
|
|
}
|
|
return head, nil
|
|
}
|
|
|
|
type worktree struct {
|
|
gocmd string
|
|
}
|
|
|
|
func (r *repository) Worktree() (Worktree, error) {
|
|
return &worktree{gocmd: r.gocmd}, nil
|
|
}
|
|
|
|
func (w *worktree) Checkout(opts *git.CheckoutOptions) error {
|
|
args := []string{"checkout"}
|
|
if opts.Create {
|
|
args = append(args, "-b", opts.Branch.Short())
|
|
}
|
|
if opts.Force {
|
|
args = append(args, "-f")
|
|
}
|
|
if opts.Hash.IsZero() {
|
|
args = append(args, opts.Branch.Short())
|
|
} else {
|
|
args = append(args, opts.Hash.String())
|
|
}
|
|
cmd := exec.Command(w.gocmd, args...)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *worktree) Status() (git.Status, error) {
|
|
return git.Status{}, nil
|
|
}
|
|
|
|
func (w *worktree) Reset(opts *git.ResetOptions) error {
|
|
args := []string{"reset"}
|
|
if opts.Mode == git.HardReset {
|
|
args = append(args, "--hard")
|
|
}
|
|
|
|
args = append(args, opts.Commit.String())
|
|
|
|
cmd := exec.Command(w.gocmd, args...)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = buf
|
|
return nil
|
|
}
|
|
|
|
func (w *worktree) Commit(msg string, opts *git.CommitOptions) (plumbing.Hash, error) {
|
|
cmd := exec.Command(w.gocmd, `commit`,
|
|
fmt.Sprintf(`--author="%s <%s>"`, opts.Author.Name, opts.Author.Email),
|
|
"-m", msg,
|
|
fmt.Sprintf(`--date="%s"`, opts.Author.When.Format(`Mon Jan _2 15:04:05 2006 -0700`)),
|
|
)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return plumbing.ZeroHash, fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
var head *plumbing.Reference
|
|
cmd = exec.Command(w.gocmd, "show-ref", "HEAD")
|
|
buf, err = cmd.CombinedOutput()
|
|
if err != nil {
|
|
return plumbing.ZeroHash, err
|
|
}
|
|
br := bytes.NewBuffer(buf)
|
|
for {
|
|
line, err := br.ReadString('\n')
|
|
if err != nil {
|
|
if err == io.EOF && line == "" {
|
|
break
|
|
} else if err != io.EOF && line == "" {
|
|
return plumbing.ZeroHash, err
|
|
}
|
|
}
|
|
fields := strings.Fields(line)
|
|
if len(fields) != 2 {
|
|
return plumbing.ZeroHash, fmt.Errorf("invalid fields %s", line)
|
|
}
|
|
head = plumbing.NewReferenceFromStrings("HEAD", fields[0])
|
|
}
|
|
|
|
return head.Hash(), nil
|
|
}
|
|
|
|
func (w *worktree) PullContext(ctx context.Context, opts *git.PullOptions) error {
|
|
args := []string{"pull"}
|
|
if opts.Force {
|
|
args = append(args, "-f")
|
|
}
|
|
if opts.Depth != 0 {
|
|
args = append(args, fmt.Sprintf("--depth=%d", opts.Depth))
|
|
}
|
|
|
|
cmd := exec.CommandContext(ctx, w.gocmd, args...)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (w *worktree) AddWithOptions(opts *git.AddOptions) error {
|
|
cmd := exec.Command(w.gocmd, "add", opts.Path)
|
|
buf, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("output %s error %w", buf, err)
|
|
}
|
|
|
|
return nil
|
|
}
|