mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-28 00:17:42 +08:00
build: add cache-from and cache-to support
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
parent
2ad963bcb1
commit
96a148020a
20
bake/bake.go
20
bake/bake.go
@ -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) {
|
||||
|
60
build/cache.go
Normal file
60
build/cache.go
Normal file
@ -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…
x
Reference in New Issue
Block a user