forked from toolshed/abra
.gitea
cli
cmd
pkg
app
autocomplete
client
compose
config
container
context
dns
formatter
git
branch.go
clone.go
commit.go
common.go
init.go
push.go
read.go
remote.go
integration
limit
lint
recipe
secret
server
service
ssh
test
upstream
web
scripts
tests
.drone.yml
.e2e.env.sample
.envrc.sample
.gitignore
.goreleaser.yml
AUTHORS.md
LICENSE
Makefile
README.md
go.mod
go.sum
renovate.json
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
|
|
}
|