-
Notifications
You must be signed in to change notification settings - Fork 386
/
earthfile2llb.go
148 lines (136 loc) · 5.75 KB
/
earthfile2llb.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package earthfile2llb
import (
"context"
"fmt"
"github.com/moby/buildkit/client/llb"
gwclient "github.com/moby/buildkit/frontend/gateway/client"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sync/semaphore"
"github.com/earthly/earthly/ast"
"github.com/earthly/earthly/buildcontext"
"github.com/earthly/earthly/buildcontext/provider"
"github.com/earthly/earthly/cleanup"
"github.com/earthly/earthly/conslogging"
"github.com/earthly/earthly/domain"
"github.com/earthly/earthly/features"
"github.com/earthly/earthly/states"
"github.com/earthly/earthly/variables"
)
// ConvertOpt holds conversion parameters.
type ConvertOpt struct {
// GwClient is the BuildKit gateway client.
GwClient gwclient.Client
// Resolver is the build context resolver.
Resolver *buildcontext.Resolver
// GlobalImports is a map of imports used to dereference import ref targets, commands, etc.
GlobalImports map[string]domain.ImportTrackerVal
// The resolve mode for referenced images (force pull or prefer local).
ImageResolveMode llb.ResolveMode
// DockerBuilderFun is a fun that can be used to execute an image build. This
// is used as part of operations like DOCKER LOAD and DOCKER PULL, where
// a tar image is needed in the middle of a build.
DockerBuilderFun states.DockerBuilderFun
// CleanCollection is a collection of cleanup functions.
CleanCollection *cleanup.Collection
// Visited is a collection of target states which have been converted to LLB.
// This is used for deduplication and infinite cycle detection.
Visited *states.VisitedCollection
// Platform is the target platform of the build.
Platform *specs.Platform
// OverridingVars is a collection of build args used for overriding args in the build.
OverridingVars *variables.Scope
// A cache for image solves. (maybe dockerTag +) depTargetInputHash -> context containing image.tar.
SolveCache *states.SolveCache
// BuildContextProvider is the provider used for local build context files.
BuildContextProvider *provider.BuildContextProvider
// MetaResolver is the image meta resolver to use for resolving image metadata.
MetaResolver llb.ImageMetaResolver
// CacheImports is a set of docker tags that can be used to import cache. Note that this
// set is modified by the converter if InlineCache is enabled.
CacheImports *states.CacheImports
// UseInlineCache enables the inline caching feature (use any SAVE IMAGE --push declaration as
// cache import).
UseInlineCache bool
// UseFakeDep is an internal feature flag for fake dep.
UseFakeDep bool
// AllowLocally is an internal feature flag for controlling if LOCALLY directives can be used.
AllowLocally bool
// AllowInteractive is an internal feature flag for controlling if interactive sessions can be initiated.
AllowInteractive bool
// HasDangling represents whether the target has dangling instructions -
// ie if there are any non-SAVE commands after the first SAVE command,
// or if the target is invoked via BUILD command (not COPY nor FROM).
HasDangling bool
// Console is for logging
Console conslogging.ConsoleLogger
// AllowPrivileged is used to allow (or prevent) any "RUN --privileged" or RUNs under a LOCALLY target to be executed,
// when set to false, it prevents other referenced remote targets from requesting elevated privileges
AllowPrivileged bool
// Gitlookup is used to attach credentials to GIT CLONE operations
GitLookup *buildcontext.GitLookup
// ParallelConversion is a feature flag enabling the parallel conversion algorithm.
ParallelConversion bool
// Parallelism is a semaphore controlling the maximum parallelism.
Parallelism *semaphore.Weighted
// parentDepSub is a channel informing of any new dependencies from the parent.
parentDepSub chan string // chan of sts IDs.
}
// Earthfile2LLB parses a earthfile and executes the statements for a given target.
func Earthfile2LLB(ctx context.Context, target domain.Target, opt ConvertOpt) (mts *states.MultiTarget, err error) {
if opt.SolveCache == nil {
opt.SolveCache = states.NewSolveCache()
}
if opt.Visited == nil {
opt.Visited = states.NewVisitedCollection()
}
if opt.MetaResolver == nil {
opt.MetaResolver = NewCachedMetaResolver(opt.GwClient)
}
// Resolve build context.
bc, err := opt.Resolver.Resolve(ctx, opt.GwClient, target)
if err != nil {
return nil, errors.Wrapf(err, "resolve build context for target %s", target.String())
}
ftrs, err := features.GetFeatures(bc.Earthfile.Version)
if err != nil {
return nil, errors.Wrapf(err, "resolve feature set for version %v for target %s", bc.Earthfile.Version.Args, target.String())
}
if ftrs.ReferencedSaveOnly {
fmt.Printf("TODO feature-flip referenced save artifact as local feature in a future PR.\n")
}
targetWithMetadata := bc.Ref.(domain.Target)
sts, found, err := opt.Visited.Add(ctx, targetWithMetadata, opt.Platform, opt.AllowPrivileged, opt.OverridingVars, opt.parentDepSub)
if err != nil {
return nil, err
}
if found {
// This target has already been done.
return &states.MultiTarget{
Final: sts,
Visited: opt.Visited,
}, nil
}
converter, err := NewConverter(ctx, targetWithMetadata, bc, sts, opt)
if err != nil {
return nil, err
}
interpreter := newInterpreter(converter, targetWithMetadata, opt.AllowPrivileged, opt.ParallelConversion, opt.Parallelism, opt.Console, opt.GitLookup)
err = interpreter.Run(ctx, bc.Earthfile)
if err != nil {
return nil, err
}
return converter.FinalizeStates(ctx)
}
// GetTargets returns a list of targets from an Earthfile.
func GetTargets(filename string) ([]string, error) {
ef, err := ast.Parse(context.TODO(), filename, false)
if err != nil {
return nil, err
}
targets := make([]string, 0, len(ef.Targets))
for _, target := range ef.Targets {
targets = append(targets, target.Name)
}
return targets, nil
}