1package solver
2
3import (
4	"context"
5	"time"
6
7	"github.com/containerd/containerd/content"
8	"github.com/moby/buildkit/session"
9	"github.com/moby/buildkit/solver/pb"
10	digest "github.com/opencontainers/go-digest"
11	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
12)
13
14// Vertex is a node in a build graph. It defines an interface for a
15// content-addressable operation and its inputs.
16type Vertex interface {
17	// Digest returns a checksum of the definition up to the vertex including
18	// all of its inputs.
19	Digest() digest.Digest
20
21	// Sys returns an object used to resolve the executor for this vertex.
22	// In LLB solver, this value would be of type `llb.Op`.
23	Sys() interface{}
24
25	// Options return metadata associated with the vertex that doesn't change the
26	// definition or equality check of it.
27	Options() VertexOptions
28
29	// Inputs returns an array of edges the vertex depends on. An input edge is
30	// a vertex and an index from the returned array of results from an executor
31	// returned by Sys(). A vertex may have zero inputs.
32	Inputs() []Edge
33
34	Name() string
35}
36
37// Index is an index value for the return array of an operation. Index starts
38// counting from zero.
39type Index int
40
41// Edge is a connection point between vertexes. An edge references a specific
42// output of a vertex's operation. Edges are used as inputs to other vertexes.
43type Edge struct {
44	Index  Index
45	Vertex Vertex
46}
47
48// VertexOptions define optional metadata for a vertex that doesn't change the
49// definition or equality check of it. These options are not contained in the
50// vertex digest.
51type VertexOptions struct {
52	IgnoreCache  bool
53	CacheSources []CacheManager
54	Description  map[string]string // text values with no special meaning for solver
55	ExportCache  *bool
56	// WorkerConstraint
57}
58
59// Result is an abstract return value for a solve
60type Result interface {
61	ID() string
62	Release(context.Context) error
63	Sys() interface{}
64	Clone() Result
65}
66
67// CachedResult is a result connected with its cache key
68type CachedResult interface {
69	Result
70	CacheKeys() []ExportableCacheKey
71}
72
73type ResultProxy interface {
74	Result(context.Context) (CachedResult, error)
75	Release(context.Context) error
76	Definition() *pb.Definition
77}
78
79// CacheExportMode is the type for setting cache exporting modes
80type CacheExportMode int
81
82const (
83	// CacheExportModeMin exports a topmost allowed vertex and its dependencies
84	// that already have transferable layers
85	CacheExportModeMin CacheExportMode = iota
86	// CacheExportModeMax exports all possible non-root vertexes
87	CacheExportModeMax
88	// CacheExportModeRemoteOnly only exports vertexes that already have
89	// transferable layers
90	CacheExportModeRemoteOnly
91)
92
93// CacheExportOpt defines options for exporting build cache
94type CacheExportOpt struct {
95	// Convert can convert a build result to transferable object
96	Convert func(context.Context, Result) (*Remote, error)
97	// Mode defines a cache export algorithm
98	Mode CacheExportMode
99	// Session is the session group to client (for auth credentials etc)
100	Session session.Group
101}
102
103// CacheExporter can export the artifacts of the build chain
104type CacheExporter interface {
105	ExportTo(ctx context.Context, t CacheExporterTarget, opt CacheExportOpt) ([]CacheExporterRecord, error)
106}
107
108// CacheExporterTarget defines object capable of receiving exports
109type CacheExporterTarget interface {
110	Add(dgst digest.Digest) CacheExporterRecord
111	Visit(interface{})
112	Visited(interface{}) bool
113}
114
115// CacheExporterRecord is a single object being exported
116type CacheExporterRecord interface {
117	AddResult(createdAt time.Time, result *Remote)
118	LinkFrom(src CacheExporterRecord, index int, selector string)
119}
120
121// Remote is a descriptor or a list of stacked descriptors that can be pulled
122// from a content provider
123// TODO: add closer to keep referenced data from getting deleted
124type Remote struct {
125	Descriptors []ocispec.Descriptor
126	Provider    content.Provider
127}
128
129// CacheLink is a link between two cache records
130type CacheLink struct {
131	Source   digest.Digest `json:",omitempty"`
132	Input    Index         `json:",omitempty"`
133	Output   Index         `json:",omitempty"`
134	Base     digest.Digest `json:",omitempty"`
135	Selector digest.Digest `json:",omitempty"`
136}
137
138// Op defines how the solver can evaluate the properties of a vertex operation.
139// An op is executed in the worker, and is retrieved from the vertex by the
140// value of `vertex.Sys()`. The solver is configured with a resolve function to
141// convert a `vertex.Sys()` into an `Op`.
142type Op interface {
143	// CacheMap returns structure describing how the operation is cached.
144	// Currently only roots are allowed to return multiple cache maps per op.
145	CacheMap(context.Context, session.Group, int) (*CacheMap, bool, error)
146
147	// Exec runs an operation given results from previous operations.
148	Exec(ctx context.Context, g session.Group, inputs []Result) (outputs []Result, err error)
149}
150
151type ResultBasedCacheFunc func(context.Context, Result, session.Group) (digest.Digest, error)
152type PreprocessFunc func(context.Context, Result, session.Group) error
153
154// CacheMap is a description for calculating the cache key of an operation.
155type CacheMap struct {
156	// Digest returns a checksum for the operation. The operation result can be
157	// cached by a checksum that combines this digest and the cache keys of the
158	// operation's inputs.
159	//
160	// For example, in LLB this digest is a manifest digest for OCI images, or
161	// commit SHA for git sources.
162	Digest digest.Digest
163
164	// Deps contain optional selectors or content-based cache functions for its
165	// inputs.
166	Deps []struct {
167		// Selector is a digest that is merged with the cache key of the input.
168		// Selectors are not merged with the result of the `ComputeDigestFunc` for
169		// this input.
170		Selector digest.Digest
171
172		// ComputeDigestFunc should return a digest for the input based on its return
173		// value.
174		//
175		// For example, in LLB this is invoked to calculate the cache key based on
176		// the checksum of file contents from input snapshots.
177		ComputeDigestFunc ResultBasedCacheFunc
178
179		// PreprocessFunc is a function that runs on an input before it is passed to op
180		PreprocessFunc PreprocessFunc
181	}
182
183	// Opts specifies generic options that will be passed to cache load calls if/when
184	// the key associated with this CacheMap is used to load a ref. It allows options
185	// such as oci descriptor content providers and progress writers to be passed to
186	// the cache. Opts should not have any impact on the computed cache key.
187	Opts CacheOpts
188}
189
190// ExportableCacheKey is a cache key connected with an exporter that can export
191// a chain of cacherecords pointing to that key
192type ExportableCacheKey struct {
193	*CacheKey
194	Exporter CacheExporter
195}
196
197// CacheRecord is an identifier for loading in cache
198type CacheRecord struct {
199	ID        string
200	Size      int
201	CreatedAt time.Time
202	Priority  int
203
204	cacheManager *cacheManager
205	key          *CacheKey
206}
207
208// CacheManager determines if there is a result that matches the cache keys
209// generated during the build that could be reused instead of fully
210// reevaluating the vertex and its inputs. There can be multiple cache
211// managers, and specific managers can be defined per vertex using
212// `VertexOptions`.
213type CacheManager interface {
214	// ID is used to identify cache providers that are backed by same source
215	// to avoid duplicate calls to the same provider.
216	ID() string
217
218	// Query searches for cache paths from one cache key to the output of a
219	// possible match.
220	Query(inp []CacheKeyWithSelector, inputIndex Index, dgst digest.Digest, outputIndex Index) ([]*CacheKey, error)
221	Records(ck *CacheKey) ([]*CacheRecord, error)
222
223	// Load loads a cache record into a result reference.
224	Load(ctx context.Context, rec *CacheRecord) (Result, error)
225
226	// Save saves a result based on a cache key
227	Save(key *CacheKey, s Result, createdAt time.Time) (*ExportableCacheKey, error)
228}
229