build: add cache-from and cache-to support

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
pull/33/head
Tonis Tiigi 6 years ago
parent 2ad963bcb1
commit 96a148020a

@ -210,6 +210,7 @@ type Target struct {
Labels map[string]string `json:"labels,omitempty"`
Tags []string `json:"tags,omitempty"`
CacheFrom []string `json:"cache-from,omitempty"`
CacheTo []string `json:"cache-to,omitempty"`
Target *string `json:"target,omitempty"`
Secrets []string `json:"secret,omitempty"`
SSH []string `json:"ssh,omitempty"`
@ -251,7 +252,6 @@ func toBuildOpt(t Target) (*build.Options, error) {
Tags: t.Tags,
BuildArgs: t.Args,
Labels: t.Labels,
// CacheFrom: t.CacheFrom,
}
platforms, err := build.ParsePlatformSpecs(t.Platforms)
@ -278,6 +278,18 @@ func toBuildOpt(t Target) (*build.Options, error) {
bo.Target = *t.Target
}
cacheImports, err := build.ParseCacheEntry(t.CacheFrom)
if err != nil {
return nil, err
}
bo.CacheFrom = cacheImports
cacheExports, err := build.ParseCacheEntry(t.CacheTo)
if err != nil {
return nil, err
}
bo.CacheTo = cacheExports
return bo, nil
}
@ -325,6 +337,12 @@ func merge(t1, t2 Target) Target {
if t2.Platforms != nil { // no merge
t1.Platforms = t2.Platforms
}
if len(t2.CacheFrom) > 0 { // no merge
t1.CacheFrom = t2.CacheFrom
}
if len(t2.CacheTo) > 0 { // no merge
t1.CacheTo = t2.CacheTo
}
t1.Inherits = append(t1.Inherits, t2.Inherits...)
return t1
}

@ -47,6 +47,9 @@ type Options struct {
Exports []client.ExportEntry
Session []session.Attachable
CacheFrom []client.CacheOptionsEntry
CacheTo []client.CacheOptionsEntry
// DockerTarget
}
@ -133,10 +136,27 @@ func Build(ctx context.Context, drivers []DriverInfo, opt map[string]Options, do
}
}
if v, ok := opt.BuildArgs["BUILDKIT_INLINE_CACHE"]; ok {
if v, _ := strconv.ParseBool(v); v {
opt.CacheTo = append(opt.CacheTo, client.CacheOptionsEntry{
Type: "inline",
Attrs: map[string]string{},
})
}
}
for _, e := range opt.CacheTo {
if e.Type != "inline" && !d.Features()[driver.CacheExport] {
return nil, notSupported(d, driver.CacheExport)
}
}
so := client.SolveOpt{
Frontend: "dockerfile.v0",
FrontendAttrs: map[string]string{},
LocalDirs: map[string]string{},
CacheExports: opt.CacheTo,
CacheImports: opt.CacheFrom,
}
switch len(opt.Exports) {

@ -0,0 +1,60 @@
package build
import (
"encoding/csv"
"strings"
"github.com/moby/buildkit/client"
"github.com/pkg/errors"
)
func ParseCacheEntry(in []string) ([]client.CacheOptionsEntry, error) {
imports := make([]client.CacheOptionsEntry, 0, len(in))
for _, in := range in {
csvReader := csv.NewReader(strings.NewReader(in))
fields, err := csvReader.Read()
if err != nil {
return nil, err
}
if isRefOnlyFormat(fields) {
for _, field := range fields {
imports = append(imports, client.CacheOptionsEntry{
Type: "registry",
Attrs: map[string]string{"ref": field},
})
}
continue
}
im := client.CacheOptionsEntry{
Attrs: map[string]string{},
}
for _, field := range fields {
parts := strings.SplitN(field, "=", 2)
if len(parts) != 2 {
return nil, errors.Errorf("invalid value %s", field)
}
key := strings.ToLower(parts[0])
value := parts[1]
switch key {
case "type":
im.Type = value
default:
im.Attrs[key] = value
}
}
if im.Type == "" {
return nil, errors.Errorf("type required form> %q", in)
}
imports = append(imports, im)
}
return imports, nil
}
func isRefOnlyFormat(in []string) bool {
for _, v := range in {
if strings.Contains(v, "=") {
return false
}
}
return true
}

@ -26,6 +26,7 @@ type buildOptions struct {
buildArgs []string
cacheFrom []string
cacheTo []string
target string
platforms []string
secrets []string
@ -153,6 +154,18 @@ func runBuild(dockerCli command.Cli, in buildOptions) error {
opts.Exports = outputs
cacheImports, err := build.ParseCacheEntry(in.cacheFrom)
if err != nil {
return err
}
opts.CacheFrom = cacheImports
cacheExports, err := build.ParseCacheEntry(in.cacheTo)
if err != nil {
return err
}
opts.CacheTo = cacheExports
return buildTargets(ctx, dockerCli, map[string]build.Options{"default": opts}, in.progress)
}
@ -195,7 +208,8 @@ func buildCmd(dockerCli command.Cli) *cobra.Command {
flags.StringArrayVar(&options.labels, "label", []string{}, "Set metadata for an image")
flags.StringSliceVar(&options.cacheFrom, "cache-from", []string{}, "Images to consider as cache sources")
flags.StringArrayVar(&options.cacheFrom, "cache-from", []string{}, "External cache sources (eg. user/app:cache, type=local,src=path/to/dir)")
flags.StringArrayVar(&options.cacheTo, "cache-to", []string{}, "Cache export destinations (eg. user/app:cache, type=local,dest=path/to/dir)")
flags.StringVar(&options.target, "target", "", "Set the target build stage to build.")

Loading…
Cancel
Save