forked from mlafeldt/chef-runner
/
resolver.go
115 lines (95 loc) · 2.86 KB
/
resolver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Package resolver provides a generic cookbook dependency resolver.
package resolver
import (
"errors"
"io/ioutil"
"path"
"strings"
"github.com/mlafeldt/chef-runner/chef/cookbook"
"github.com/mlafeldt/chef-runner/log"
"github.com/mlafeldt/chef-runner/resolver/berkshelf"
"github.com/mlafeldt/chef-runner/resolver/dir"
"github.com/mlafeldt/chef-runner/resolver/librarian"
"github.com/mlafeldt/chef-runner/util"
)
// A Resolver resolves cookbook dependencies and installs them to directory dst.
// This is the interface that all resolvers need to implement.
type Resolver interface {
Resolve(dst string) error
Name() string
}
func findResolverByName(name string) (Resolver, error) {
var resolvers = [...]Resolver{
berkshelf.Resolver{},
librarian.Resolver{},
dir.Resolver{},
}
for _, r := range resolvers {
if strings.HasPrefix(strings.ToLower(r.Name()), strings.ToLower(name)) {
return r, nil
}
}
return nil, errors.New("unknown resolver name: " + name)
}
func findResolver(name, dst string) (Resolver, error) {
if name != "" {
return findResolverByName(name)
}
cb, _ := cookbook.NewCookbook(".")
// If the current folder is a cookbook and its dependencies have
// already been resolved, only update this cookbook with rsync.
// TODO: improve this check by comparing timestamps etc.
if cb.Name != "" && util.FileExist(dst) {
return dir.Resolver{}, nil
}
if util.FileExist("Berksfile") {
return berkshelf.Resolver{}, nil
}
if util.FileExist("Cheffile") {
return librarian.Resolver{}, nil
}
if cb.Name != "" {
return dir.Resolver{}, nil
}
log.Error("Berksfile, Cheffile, or metadata.rb must exist in current directory")
return nil, errors.New("cookbooks could not be found")
}
func stripCookbooks(dst string) error {
cookbookDirs, err := ioutil.ReadDir(dst)
if err != nil {
return err
}
for _, dir := range cookbookDirs {
if !dir.IsDir() {
continue
}
cb := cookbook.Cookbook{Path: path.Join(dst, dir.Name())}
if err := cb.Strip(); err != nil {
return err
}
}
return nil
}
// Resolve resolves cookbook dependencies using the named resolver. If no
// resolver is specified, it will be guessed based on the files present in the
// current directory. After resolving dependencies, all non-cookbook files will
// be deleted as well.
func Resolve(name, dst string) error {
log.Debug("Preparing cookbooks")
r, err := findResolver(name, dst)
if err != nil {
return err
}
log.Infof("Installing cookbook dependencies with %s resolver\n", r.Name())
if err := r.Resolve(dst); err != nil {
return err
}
log.Info("Stripping non-cookbook files")
return stripCookbooks(dst)
}
// AutoResolve automatically resolves cookbook dependencies based on the files
// present in the current directory. After resolving dependencies, all
// non-cookbook files will be deleted as well.
func AutoResolve(dst string) error {
return Resolve("", dst)
}