2020-02-24 19:14:46 +03:00
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
2022-11-10 09:42:13 +03:00
|
|
|
"io/fs"
|
2020-02-24 19:14:46 +03:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2020-04-22 12:15:42 +03:00
|
|
|
"github.com/sirupsen/logrus"
|
2020-02-24 19:14:46 +03:00
|
|
|
"gopkg.in/src-d/go-git.v4"
|
2020-04-16 04:24:50 +03:00
|
|
|
"gopkg.in/src-d/go-git.v4/config"
|
2020-02-24 19:14:46 +03:00
|
|
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
2022-10-28 12:31:03 +03:00
|
|
|
|
2022-11-10 09:42:13 +03:00
|
|
|
stderrors "errors"
|
|
|
|
|
2022-10-28 12:31:03 +03:00
|
|
|
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
|
2020-02-24 19:14:46 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// Default Codegen Assets constants
|
|
|
|
const (
|
|
|
|
ActionsCodegenOrg string = "hasura/codegen-assets"
|
2020-10-22 09:35:05 +03:00
|
|
|
ActionsCodegenRepoURI string = "https://github.com/hasura/codegen-assets.git"
|
|
|
|
ActionsCodegenDirName string = "actions-codegen-assets"
|
2020-02-24 19:14:46 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type GitUtil struct {
|
|
|
|
URI string
|
|
|
|
Path string
|
|
|
|
|
|
|
|
// Optional
|
2020-04-22 12:15:42 +03:00
|
|
|
ReferenceName plumbing.ReferenceName
|
|
|
|
DisableCloneOrUpdate bool
|
|
|
|
Logger *logrus.Logger
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewGitUtil(uri string, path string, refName string) *GitUtil {
|
|
|
|
cfg := &GitUtil{
|
|
|
|
URI: uri,
|
|
|
|
Path: path,
|
|
|
|
ReferenceName: plumbing.HEAD,
|
|
|
|
}
|
|
|
|
if refName != "" {
|
|
|
|
cfg.ReferenceName = plumbing.NewBranchReferenceName(refName)
|
|
|
|
}
|
|
|
|
return cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GitUtil) EnsureCloned() error {
|
2022-10-28 12:31:03 +03:00
|
|
|
var op errors.Op = "util.GitUtil.EnsureCloned"
|
2020-04-22 12:15:42 +03:00
|
|
|
if g.DisableCloneOrUpdate {
|
|
|
|
g.Logger.Debugf("skipping clone/update for %s", g.URI)
|
|
|
|
return nil
|
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
if ok, err := g.IsGitCloned(); err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
} else if !ok {
|
|
|
|
_, err := git.PlainClone(g.Path, false, &git.CloneOptions{
|
|
|
|
URL: g.URI,
|
|
|
|
ReferenceName: g.ReferenceName,
|
|
|
|
})
|
|
|
|
if err != nil && err != git.ErrRepositoryAlreadyExists {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GitUtil) IsGitCloned() (bool, error) {
|
2022-10-28 12:31:03 +03:00
|
|
|
var op errors.Op = "util.GitUtil.IsGitCloned"
|
2020-02-24 19:14:46 +03:00
|
|
|
f, err := os.Stat(filepath.Join(g.Path, ".git"))
|
2022-11-10 09:42:13 +03:00
|
|
|
if stderrors.Is(err, fs.ErrNotExist) {
|
2020-02-24 19:14:46 +03:00
|
|
|
return false, nil
|
|
|
|
}
|
2022-10-28 12:31:03 +03:00
|
|
|
if err != nil {
|
|
|
|
return false, errors.E(op, err)
|
|
|
|
}
|
|
|
|
return f.IsDir(), nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// EnsureUpdated will ensure the destination path exists and is up to date.
|
|
|
|
func (g *GitUtil) EnsureUpdated() error {
|
2022-10-28 12:31:03 +03:00
|
|
|
var op errors.Op = "util.GitUtil.EnsureUpdated"
|
2020-04-22 12:15:42 +03:00
|
|
|
if g.DisableCloneOrUpdate {
|
|
|
|
g.Logger.Debugf("skipping clone/update for %s", g.URI)
|
|
|
|
return nil
|
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
if err := g.EnsureCloned(); err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
|
|
|
}
|
|
|
|
if err := g.updateAndCleanUntracked(); err != nil {
|
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2022-10-28 12:31:03 +03:00
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *GitUtil) updateAndCleanUntracked() error {
|
2022-10-28 12:31:03 +03:00
|
|
|
var op errors.Op = "util.GitUtil.updateAndCleanUntracked"
|
2020-02-24 19:14:46 +03:00
|
|
|
repo, err := git.PlainOpen(g.Path)
|
|
|
|
if err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2020-04-16 04:24:50 +03:00
|
|
|
err = repo.Fetch(&git.FetchOptions{
|
|
|
|
RefSpecs: []config.RefSpec{"refs/*:refs/*"},
|
|
|
|
})
|
2020-02-24 19:14:46 +03:00
|
|
|
if err != nil && err != git.NoErrAlreadyUpToDate {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
wt, err := repo.Worktree()
|
|
|
|
if err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2020-04-16 04:24:50 +03:00
|
|
|
err = wt.Checkout(&git.CheckoutOptions{
|
|
|
|
Branch: g.ReferenceName,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-04-16 04:24:50 +03:00
|
|
|
}
|
|
|
|
err = wt.Pull(&git.PullOptions{
|
|
|
|
ReferenceName: g.ReferenceName,
|
2020-11-20 10:59:00 +03:00
|
|
|
Force: true,
|
2020-04-16 04:24:50 +03:00
|
|
|
})
|
2020-02-24 19:14:46 +03:00
|
|
|
if err != nil && err != git.NoErrAlreadyUpToDate {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
err = wt.Reset(&git.ResetOptions{
|
2020-04-16 04:24:50 +03:00
|
|
|
Mode: git.HardReset,
|
2020-02-24 19:14:46 +03:00
|
|
|
})
|
|
|
|
if err != nil {
|
2022-10-28 12:31:03 +03:00
|
|
|
return errors.E(op, err)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2022-10-28 12:31:03 +03:00
|
|
|
err = wt.Clean(&git.CleanOptions{
|
2020-02-24 19:14:46 +03:00
|
|
|
Dir: true,
|
|
|
|
})
|
2022-10-28 12:31:03 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, err)
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|