-
Notifications
You must be signed in to change notification settings - Fork 386
/
resolver.go
116 lines (105 loc) · 3.46 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
116
package buildcontext
import (
"context"
"path/filepath"
"strings"
"github.com/earthly/earthly/ast"
"github.com/earthly/earthly/ast/spec"
"github.com/earthly/earthly/cleanup"
"github.com/earthly/earthly/conslogging"
"github.com/earthly/earthly/domain"
"github.com/earthly/earthly/util/gitutil"
"github.com/earthly/earthly/util/llbutil/pllb"
"github.com/earthly/earthly/util/syncutil/synccache"
gwclient "github.com/moby/buildkit/frontend/gateway/client"
"github.com/pkg/errors"
)
// DockerfileMetaTarget is a target name prefix which signals the resolver that the build file is a
// dockerfile. The DockerfileMetaTarget is really not a valid Earthly target otherwise.
const DockerfileMetaTarget = "@dockerfile:"
// Data represents a resolved target's build context data.
type Data struct {
// The parsed Earthfile AST.
Earthfile spec.Earthfile
// BuildFilePath is the local path where the Earthfile or Dockerfile can be found.
BuildFilePath string
// BuildContext is the state to use for the build.
BuildContext pllb.State
// GitMetadata contains git metadata information.
GitMetadata *gitutil.GitMetadata
// Target is the earthly reference.
Ref domain.Reference
// LocalDirs is the local dirs map to be passed as part of the buildkit solve.
LocalDirs map[string]string
}
// Resolver is a build context resolver.
type Resolver struct {
gr *gitResolver
lr *localResolver
parseCache *synccache.SyncCache // local path -> AST
console conslogging.ConsoleLogger
}
// NewResolver returns a new NewResolver.
func NewResolver(sessionID string, cleanCollection *cleanup.Collection, gitLookup *GitLookup, console conslogging.ConsoleLogger) *Resolver {
return &Resolver{
gr: &gitResolver{
cleanCollection: cleanCollection,
projectCache: synccache.New(),
buildFileCache: synccache.New(),
gitLookup: gitLookup,
},
lr: &localResolver{
gitMetaCache: synccache.New(),
sessionID: sessionID,
console: console,
},
parseCache: synccache.New(),
console: console,
}
}
// Resolve returns resolved context data for a given Earthly reference. If the reference is a target,
// then the context will include a build context and possibly additional local directories.
func (r *Resolver) Resolve(ctx context.Context, gwClient gwclient.Client, ref domain.Reference) (*Data, error) {
if ref.IsUnresolvedImportReference() {
return nil, errors.Errorf("cannot resolve non-dereferenced import ref %s", ref.String())
}
var d *Data
var err error
localDirs := make(map[string]string)
if ref.IsRemote() {
// Remote.
d, err = r.gr.resolveEarthProject(ctx, gwClient, ref)
if err != nil {
return nil, err
}
} else {
// Local.
if _, isTarget := ref.(domain.Target); isTarget {
localDirs[ref.GetLocalPath()] = ref.GetLocalPath()
}
d, err = r.lr.resolveLocal(ctx, ref)
if err != nil {
return nil, err
}
}
d.Ref = gitutil.ReferenceWithGitMeta(ref, d.GitMetadata)
d.LocalDirs = localDirs
if !strings.HasPrefix(ref.GetName(), DockerfileMetaTarget) {
d.Earthfile, err = r.parseEarthfile(ctx, d.BuildFilePath)
if err != nil {
return nil, err
}
}
return d, nil
}
func (r *Resolver) parseEarthfile(ctx context.Context, path string) (spec.Earthfile, error) {
path = filepath.Clean(path)
efValue, err := r.parseCache.Do(ctx, path, func(ctx context.Context, k interface{}) (interface{}, error) {
return ast.Parse(ctx, k.(string), true)
})
if err != nil {
return spec.Earthfile{}, err
}
ef := efValue.(spec.Earthfile)
return ef, nil
}