cellarspoon
0aa37fcee8
All checks were successful
continuous-integration/drone/push Build is passing
188 lines
3.8 KiB
Go
188 lines
3.8 KiB
Go
package git
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"os/user"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"coopcloud.tech/abra/pkg/config"
|
|
"github.com/go-git/go-git/v5"
|
|
gitConfigPkg "github.com/go-git/go-git/v5/config"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// GetRecipeHead retrieves latest HEAD metadata.
|
|
func GetRecipeHead(recipeName string) (*plumbing.Reference, error) {
|
|
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
|
|
|
|
repo, err := git.PlainOpen(recipeDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
head, err := repo.Head()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return head, nil
|
|
}
|
|
|
|
// IsClean checks if a repo has unstaged changes
|
|
func IsClean(repoPath string) (bool, error) {
|
|
repo, err := git.PlainOpen(repoPath)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
worktree, err := repo.Worktree()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
patterns, err := GetExcludesFiles()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if len(patterns) > 0 {
|
|
worktree.Excludes = append(patterns, worktree.Excludes...)
|
|
}
|
|
|
|
status, err := worktree.Status()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if status.String() != "" {
|
|
logrus.Debugf("discovered git status in %s: %s", repoPath, status.String())
|
|
} else {
|
|
logrus.Debugf("discovered clean git status in %s", repoPath)
|
|
}
|
|
|
|
return status.IsClean(), nil
|
|
}
|
|
|
|
// GetExcludesFiles reads the exlude files from a global gitignore
|
|
func GetExcludesFiles() ([]gitignore.Pattern, error) {
|
|
var err error
|
|
var patterns []gitignore.Pattern
|
|
|
|
cfg, err := parseGitConfig()
|
|
if err != nil {
|
|
return patterns, err
|
|
}
|
|
|
|
excludesfile := getExcludesFile(cfg)
|
|
patterns, err = parseExcludesFile(excludesfile)
|
|
if err != nil {
|
|
return patterns, err
|
|
}
|
|
|
|
return patterns, nil
|
|
}
|
|
|
|
func parseGitConfig() (*gitConfigPkg.Config, error) {
|
|
cfg := gitConfigPkg.NewConfig()
|
|
|
|
usr, err := user.Current()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
globalGitConfig := filepath.Join(usr.HomeDir, ".gitconfig")
|
|
if _, err := os.Stat(globalGitConfig); err != nil {
|
|
if os.IsNotExist(err) {
|
|
logrus.Debugf("no %s exists, not reading any global gitignore config", globalGitConfig)
|
|
return cfg, nil
|
|
}
|
|
return cfg, err
|
|
}
|
|
|
|
b, err := ioutil.ReadFile(globalGitConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := cfg.Unmarshal(b); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return cfg, err
|
|
}
|
|
|
|
func getExcludesFile(cfg *gitConfigPkg.Config) string {
|
|
for _, sec := range cfg.Raw.Sections {
|
|
if sec.Name == "core" {
|
|
for _, opt := range sec.Options {
|
|
if opt.Key == "excludesfile" {
|
|
return opt.Value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return "~/.gitignore"
|
|
}
|
|
|
|
func parseExcludesFile(excludesfile string) ([]gitignore.Pattern, error) {
|
|
var ps []gitignore.Pattern
|
|
|
|
excludesfile, err := expandTilde(excludesfile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if _, err := os.Stat(excludesfile); err != nil {
|
|
if os.IsNotExist(err) {
|
|
logrus.Debugf("no %s exists, skipping reading gitignore paths", excludesfile)
|
|
return ps, nil
|
|
}
|
|
return ps, err
|
|
}
|
|
|
|
data, err := ioutil.ReadFile(excludesfile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var pathsRaw []string
|
|
for _, s := range strings.Split(string(data), "\n") {
|
|
if !strings.HasPrefix(s, "#") && len(strings.TrimSpace(s)) > 0 {
|
|
pathsRaw = append(pathsRaw, s)
|
|
ps = append(ps, gitignore.ParsePattern(s, nil))
|
|
}
|
|
}
|
|
|
|
logrus.Debugf("read global ignore paths: %s", strings.Join(pathsRaw, " "))
|
|
|
|
return ps, nil
|
|
}
|
|
|
|
func expandTilde(path string) (string, error) {
|
|
if !strings.HasPrefix(path, "~") {
|
|
return path, nil
|
|
}
|
|
|
|
var paths []string
|
|
u, err := user.Current()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for _, p := range strings.Split(path, string(filepath.Separator)) {
|
|
if p == "~" {
|
|
paths = append(paths, u.HomeDir)
|
|
} else {
|
|
paths = append(paths, p)
|
|
}
|
|
}
|
|
|
|
return filepath.Join(paths...), nil
|
|
}
|