mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-05-29 17:05:46 +08:00
Merge pull request #33 from tonistiigi/remote-cache
build: add cache-from and cache-to support
This commit is contained in:
commit
7f474ed28e
20
bake/bake.go
20
bake/bake.go
@ -210,6 +210,7 @@ type Target struct {
|
|||||||
Labels map[string]string `json:"labels,omitempty"`
|
Labels map[string]string `json:"labels,omitempty"`
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
CacheFrom []string `json:"cache-from,omitempty"`
|
CacheFrom []string `json:"cache-from,omitempty"`
|
||||||
|
CacheTo []string `json:"cache-to,omitempty"`
|
||||||
Target *string `json:"target,omitempty"`
|
Target *string `json:"target,omitempty"`
|
||||||
Secrets []string `json:"secret,omitempty"`
|
Secrets []string `json:"secret,omitempty"`
|
||||||
SSH []string `json:"ssh,omitempty"`
|
SSH []string `json:"ssh,omitempty"`
|
||||||
@ -251,7 +252,6 @@ func toBuildOpt(t Target) (*build.Options, error) {
|
|||||||
Tags: t.Tags,
|
Tags: t.Tags,
|
||||||
BuildArgs: t.Args,
|
BuildArgs: t.Args,
|
||||||
Labels: t.Labels,
|
Labels: t.Labels,
|
||||||
// CacheFrom: t.CacheFrom,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
platforms, err := build.ParsePlatformSpecs(t.Platforms)
|
platforms, err := build.ParsePlatformSpecs(t.Platforms)
|
||||||
@ -278,6 +278,18 @@ func toBuildOpt(t Target) (*build.Options, error) {
|
|||||||
bo.Target = *t.Target
|
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
|
return bo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,6 +337,12 @@ func merge(t1, t2 Target) Target {
|
|||||||
if t2.Platforms != nil { // no merge
|
if t2.Platforms != nil { // no merge
|
||||||
t1.Platforms = t2.Platforms
|
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...)
|
t1.Inherits = append(t1.Inherits, t2.Inherits...)
|
||||||
return t1
|
return t1
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,9 @@ type Options struct {
|
|||||||
Exports []client.ExportEntry
|
Exports []client.ExportEntry
|
||||||
Session []session.Attachable
|
Session []session.Attachable
|
||||||
|
|
||||||
|
CacheFrom []client.CacheOptionsEntry
|
||||||
|
CacheTo []client.CacheOptionsEntry
|
||||||
|
|
||||||
// DockerTarget
|
// 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{
|
so := client.SolveOpt{
|
||||||
Frontend: "dockerfile.v0",
|
Frontend: "dockerfile.v0",
|
||||||
FrontendAttrs: map[string]string{},
|
FrontendAttrs: map[string]string{},
|
||||||
LocalDirs: map[string]string{},
|
LocalDirs: map[string]string{},
|
||||||
|
CacheExports: opt.CacheTo,
|
||||||
|
CacheImports: opt.CacheFrom,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch len(opt.Exports) {
|
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
|
buildArgs []string
|
||||||
|
|
||||||
cacheFrom []string
|
cacheFrom []string
|
||||||
|
cacheTo []string
|
||||||
target string
|
target string
|
||||||
platforms []string
|
platforms []string
|
||||||
secrets []string
|
secrets []string
|
||||||
@ -153,6 +154,18 @@ func runBuild(dockerCli command.Cli, in buildOptions) error {
|
|||||||
|
|
||||||
opts.Exports = outputs
|
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)
|
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.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.")
|
flags.StringVar(&options.target, "target", "", "Set the target build stage to build.")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user