package vcs
import (
"errors"
"os"
"alin.ovh/homestead/shared/config"
"alin.ovh/homestead/shared/file"
"alin.ovh/x/log"
"github.com/Southclaws/fault"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
)
type Options struct {
LocalPath string
RemoteURL config.URL
Branch string
}
type Repository struct {
repo *git.Repository
log *log.Logger
remoteURL config.URL
}
func CloneOrOpen(cfg *Options, log *log.Logger) (*Repository, bool, error) {
var r *git.Repository
var err error
exists := file.Exists(cfg.LocalPath)
if !exists {
r, err = git.PlainClone(cfg.LocalPath, false, &git.CloneOptions{
URL: cfg.RemoteURL.String(),
Progress: os.Stdout,
})
} else {
r, err = git.PlainOpen(cfg.LocalPath)
}
if err != nil {
return nil, exists, fault.Wrap(err)
}
return &Repository{
log: log,
remoteURL: cfg.RemoteURL,
repo: r,
}, exists, nil
}
func (r *Repository) Update(rev string) (bool, error) {
r.log.Info("updating repository", "from", r.HeadSHA())
err := r.repo.Fetch(&git.FetchOptions{
Prune: true,
})
if err != nil {
if errors.Is(err, git.NoErrAlreadyUpToDate) {
r.log.Info("already up-to-date")
return true, nil
}
return false, fault.Wrap(err)
}
rem, err := r.repo.Remote("origin")
if err != nil {
return false, fault.Wrap(err)
}
refs, err := rem.List(&git.ListOptions{
Timeout: 5,
})
if err != nil {
return false, fault.Wrap(err)
}
var hash plumbing.Hash
if rev != "" {
for _, ref := range refs {
if ref.Name() == plumbing.Main {
hash = ref.Hash()
break
}
}
} else {
hash = plumbing.NewHash(rev)
}
wt, err := r.repo.Worktree()
if err != nil {
return false, fault.Wrap(err)
}
err = wt.Checkout(&git.CheckoutOptions{
Hash: hash,
Force: true,
})
if err != nil {
return false, fault.Wrap(err)
}
r.log.Info("updated to", "rev", hash)
return true, r.Clean(wt)
}
func (r *Repository) Clean(wt *git.Worktree) error {
st, err := wt.Status()
if err != nil {
return fault.Wrap(err)
}
if !st.IsClean() {
err = wt.Clean(&git.CleanOptions{
Dir: true,
})
if err != nil {
return fault.Wrap(err)
}
}
return nil
}
func (r *Repository) HeadSHA() string {
head, err := r.repo.Head()
if err != nil {
return ""
}
return head.Hash().String()
}
shared/vcs/repository.go (view raw)