local-server/pkg/clustersconfig/defaults.go

161 lines
2.9 KiB
Go

package clustersconfig
import (
"fmt"
"io"
"io/ioutil"
"log"
"path"
"path/filepath"
"strings"
billy "gopkg.in/src-d/go-billy.v4"
git "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/object"
yaml "gopkg.in/yaml.v2"
)
type Defaults struct {
repo *git.Repository
fs billy.Filesystem
}
type defaultRef struct {
From string
}
func NewDefaults(path string) (d *Defaults, err error) {
repo, err := git.PlainOpen(path)
if err != nil {
return
}
d = &Defaults{
repo: repo,
}
return
}
func (d *Defaults) Load(dir, suffix string, value Rev, data []byte) (err error) {
ref := defaultRef{}
if err = yaml.Unmarshal(data, &ref); err != nil {
return
}
if len(ref.From) != 0 {
if Debug {
log.Printf("loading defaults %q", ref.From)
}
parts := strings.SplitN(ref.From, ":", 2)
if len(parts) != 2 {
err = fmt.Errorf("bad default reference: %q", ref.From)
return
}
rev, fileName := parts[0], parts[1]
if err = d.decodeDefault(rev, path.Join(dir, fileName+suffix), value); err != nil {
return
}
value.SetRev(rev)
}
err = yaml.Unmarshal(data, value)
return
}
func (d *Defaults) Open(rev, filePath string) (rd io.Reader, err error) {
log.Printf("openning defaults at %s:%s", rev, filePath)
tree, err := d.treeAt(rev)
if err != nil {
return
}
file, err := tree.File(filePath)
if err == object.ErrFileNotFound {
return nil, nil
} else if err != nil {
return
}
return file.Reader()
}
func (d *Defaults) ReadAll(rev, filePath string) (ba []byte, err error) {
rd, err := d.Open(rev, filePath)
if err != nil || rd == nil {
return
}
return ioutil.ReadAll(rd)
}
func (d *Defaults) List(rev, dir string) (names []string, err error) {
log.Printf("listing defaults at %s:%s", rev, dir)
tree, err := d.treeAt(rev)
if err != nil {
return
}
dirPrefix := dir + "/"
err = tree.Files().ForEach(func(f *object.File) (err error) {
if !strings.HasPrefix(f.Name, dirPrefix) {
return
}
if !strings.HasSuffix(f.Name, ".yaml") {
return
}
names = append(names, strings.TrimSuffix(filepath.Base(f.Name), ".yaml"))
return
})
return
}
func (d *Defaults) treeAt(rev string) (tree *object.Tree, err error) {
h, err := d.repo.ResolveRevision(plumbing.Revision(rev))
if err != nil {
return
}
obj, err := d.repo.Object(plumbing.AnyObject, *h)
if err != nil {
return
}
for {
switch o := obj.(type) {
case *object.Tag: // tag -> commit
obj, err = o.Object()
case *object.Commit: // commit -> tree
msg := o.Message
if len(msg) > 30 {
msg = msg[:27] + "..."
}
log.Printf("open defaults at commit %s: %s", o.Hash.String()[:7], msg)
return o.Tree()
default:
err = object.ErrUnsupportedObject
}
if err != nil {
return
}
}
}
func (d *Defaults) decodeDefault(rev, filePath string, value Rev) (err error) {
ba, err := d.ReadAll(rev, filePath)
if err != nil {
return
}
return yaml.Unmarshal(ba, value)
}