mirror of https://github.com/docker/buildx.git
				
				
				
			Merge pull request #1735 from tonistiigi/localstate
build: support for saving local state by build ref
This commit is contained in:
		
						commit
						28e6995f7c
					
				|  | @ -25,6 +25,7 @@ import ( | |||
| 	"github.com/containerd/containerd/platforms" | ||||
| 	"github.com/docker/buildx/builder" | ||||
| 	"github.com/docker/buildx/driver" | ||||
| 	"github.com/docker/buildx/localstate" | ||||
| 	"github.com/docker/buildx/util/dockerutil" | ||||
| 	"github.com/docker/buildx/util/imagetools" | ||||
| 	"github.com/docker/buildx/util/progress" | ||||
|  | @ -650,6 +651,12 @@ func toSolveOpt(ctx context.Context, node builder.Node, multiDriver bool, opt Op | |||
| 		so.FrontendAttrs["ulimit"] = ulimits | ||||
| 	} | ||||
| 
 | ||||
| 	// remember local state like directory path that is not sent to buildkit
 | ||||
| 	so.Ref = identity.NewID() | ||||
| 	if err := saveLocalState(so, opt, node, configDir); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &so, releaseF, nil | ||||
| } | ||||
| 
 | ||||
|  | @ -1617,3 +1624,40 @@ func noPrintFunc(opt map[string]Options) bool { | |||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func saveLocalState(so client.SolveOpt, opt Options, node builder.Node, configDir string) error { | ||||
| 	var err error | ||||
| 
 | ||||
| 	if so.Ref == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	lp := opt.Inputs.ContextPath | ||||
| 	dp := opt.Inputs.DockerfilePath | ||||
| 	if lp != "" || dp != "" { | ||||
| 		if lp != "" { | ||||
| 			lp, err = filepath.Abs(lp) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		if dp != "" { | ||||
| 			dp, err = filepath.Abs(dp) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		ls, err := localstate.New(configDir) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := ls.SaveRef(node.Builder, node.Name, so.Ref, localstate.State{ | ||||
| 			LocalPath:      lp, | ||||
| 			DockerfilePath: dp, | ||||
| 		}); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ import ( | |||
| 
 | ||||
| type Node struct { | ||||
| 	store.Node | ||||
| 	Builder     string | ||||
| 	Driver      driver.Driver | ||||
| 	DriverInfo  *driver.Info | ||||
| 	Platforms   []ocispecs.Platform | ||||
|  | @ -63,6 +64,7 @@ func (b *Builder) LoadNodes(ctx context.Context, withData bool) (_ []Node, err e | |||
| 					Node:        n, | ||||
| 					ProxyConfig: storeutil.GetProxyConfig(b.opts.dockerCli), | ||||
| 					Platforms:   n.Platforms, | ||||
| 					Builder:     b.Name, | ||||
| 				} | ||||
| 				defer func() { | ||||
| 					b.nodes[i] = node | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ import ( | |||
| 	"github.com/docker/buildx/driver" | ||||
| 	k8sutil "github.com/docker/buildx/driver/kubernetes/util" | ||||
| 	remoteutil "github.com/docker/buildx/driver/remote/util" | ||||
| 	"github.com/docker/buildx/localstate" | ||||
| 	"github.com/docker/buildx/store" | ||||
| 	"github.com/docker/buildx/store/storeutil" | ||||
| 	"github.com/docker/buildx/util/cobrautil" | ||||
|  | @ -170,6 +171,13 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { | |||
| 		if err := ng.Leave(in.nodeName); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ls, err := localstate.New(confutil.ConfigDir(dockerCli)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := ls.RemoveBuilderNode(ng.Name, in.nodeName); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else { | ||||
| 		switch { | ||||
| 		case driverName == "kubernetes": | ||||
|  |  | |||
|  | @ -0,0 +1,93 @@ | |||
| package localstate | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 
 | ||||
| 	"github.com/docker/docker/pkg/ioutils" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
| 
 | ||||
| const refsDir = "refs" | ||||
| 
 | ||||
| type State struct { | ||||
| 	LocalPath      string | ||||
| 	DockerfilePath string | ||||
| } | ||||
| 
 | ||||
| type LocalState struct { | ||||
| 	root string | ||||
| } | ||||
| 
 | ||||
| func New(root string) (*LocalState, error) { | ||||
| 	if root == "" { | ||||
| 		return nil, errors.Errorf("root dir empty") | ||||
| 	} | ||||
| 	if err := os.MkdirAll(filepath.Join(root, refsDir), 0700); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &LocalState{ | ||||
| 		root: root, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func (ls *LocalState) ReadRef(builderName, nodeName, id string) (*State, error) { | ||||
| 	if err := ls.validate(builderName, nodeName, id); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	dt, err := os.ReadFile(filepath.Join(ls.root, refsDir, builderName, nodeName, id)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var st State | ||||
| 	if err := json.Unmarshal(dt, &st); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &st, nil | ||||
| } | ||||
| 
 | ||||
| func (ls *LocalState) SaveRef(builderName, nodeName, id string, st State) error { | ||||
| 	if err := ls.validate(builderName, nodeName, id); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	refDir := filepath.Join(ls.root, refsDir, builderName, nodeName) | ||||
| 	if err := os.MkdirAll(refDir, 0700); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	dt, err := json.Marshal(st) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return ioutils.AtomicWriteFile(filepath.Join(refDir, id), dt, 0600) | ||||
| } | ||||
| 
 | ||||
| func (ls *LocalState) RemoveBuilder(builderName string) error { | ||||
| 	if builderName == "" { | ||||
| 		return errors.Errorf("builder name empty") | ||||
| 	} | ||||
| 	return os.RemoveAll(filepath.Join(ls.root, refsDir, builderName)) | ||||
| } | ||||
| 
 | ||||
| func (ls *LocalState) RemoveBuilderNode(builderName string, nodeName string) error { | ||||
| 	if builderName == "" { | ||||
| 		return errors.Errorf("builder name empty") | ||||
| 	} | ||||
| 	if nodeName == "" { | ||||
| 		return errors.Errorf("node name empty") | ||||
| 	} | ||||
| 	return os.RemoveAll(filepath.Join(ls.root, refsDir, builderName, nodeName)) | ||||
| } | ||||
| 
 | ||||
| func (ls *LocalState) validate(builderName, nodeName, id string) error { | ||||
| 	if builderName == "" { | ||||
| 		return errors.Errorf("builder name empty") | ||||
| 	} | ||||
| 	if nodeName == "" { | ||||
| 		return errors.Errorf("node name empty") | ||||
| 	} | ||||
| 	if id == "" { | ||||
| 		return errors.Errorf("ref ID empty") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | @ -7,6 +7,7 @@ import ( | |||
| 	"sort" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/docker/buildx/localstate" | ||||
| 	"github.com/docker/docker/pkg/ioutils" | ||||
| 	"github.com/gofrs/flock" | ||||
| 	"github.com/opencontainers/go-digest" | ||||
|  | @ -120,6 +121,13 @@ func (t *Txn) Remove(name string) error { | |||
| 	if err := t.RemoveLastActivity(name); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	ls, err := localstate.New(t.s.root) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := ls.RemoveBuilder(name); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return os.RemoveAll(filepath.Join(t.s.root, instanceDir, name)) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue