diff --git a/commands/bake.go b/commands/bake.go index 89edb42d..18d1f959 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -287,7 +287,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba } } - if err := saveLocalStateGroup(dockerCli, in, targets, bo, overrides, def); err != nil { + if err := saveLocalStateGroup(dockerCli, in, targets, bo); err != nil { return err } @@ -492,7 +492,14 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command { return cmd } -func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options, overrides []string, def any) error { +func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options) error { + l, err := localstate.New(confutil.NewConfig(dockerCli)) + if err != nil { + return err + } + + defer l.MigrateIfNeeded() + prm := confutil.MetadataProvenance() if len(in.metadataFile) == 0 { prm = confutil.MetadataProvenanceModeDisabled @@ -512,19 +519,10 @@ func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string if len(refs) == 0 { return nil } - l, err := localstate.New(confutil.NewConfig(dockerCli)) - if err != nil { - return err - } - dtdef, err := json.MarshalIndent(def, "", " ") - if err != nil { - return err - } + return l.SaveGroup(groupRef, localstate.StateGroup{ - Definition: dtdef, - Targets: targets, - Inputs: overrides, - Refs: refs, + Refs: refs, + Targets: targets, }) } diff --git a/localstate/localstate.go b/localstate/localstate.go index 4d486018..5d9723cd 100644 --- a/localstate/localstate.go +++ b/localstate/localstate.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strconv" "sync" "github.com/docker/buildx/util/confutil" @@ -14,6 +15,7 @@ import ( ) const ( + version = 2 refsDir = "refs" groupDir = "__group__" ) @@ -31,12 +33,8 @@ type State struct { } type StateGroup struct { - // Definition is the raw representation of the group (bake definition) - Definition []byte // Targets are the targets invoked Targets []string `json:",omitempty"` - // Inputs are the user inputs (bake overrides) - Inputs []string `json:",omitempty"` // Refs are used to track all the refs that belong to the same group Refs []string } @@ -52,9 +50,7 @@ func New(cfg *confutil.Config) (*LocalState, error) { if err := cfg.MkdirAll(refsDir, 0700); err != nil { return nil, err } - return &LocalState{ - cfg: cfg, - }, nil + return &LocalState{cfg: cfg}, nil } func (ls *LocalState) ReadRef(builderName, nodeName, id string) (*State, error) { @@ -87,8 +83,12 @@ func (ls *LocalState) SaveRef(builderName, nodeName, id string, st State) error return ls.cfg.AtomicWriteFile(filepath.Join(refDir, id), dt, 0644) } +func (ls *LocalState) GroupDir() string { + return filepath.Join(ls.cfg.Dir(), refsDir, groupDir) +} + func (ls *LocalState) ReadGroup(id string) (*StateGroup, error) { - dt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id)) + dt, err := os.ReadFile(filepath.Join(ls.GroupDir(), id)) if err != nil { return nil, err } @@ -208,7 +208,7 @@ func (ls *LocalState) removeGroup(id string) error { if id == "" { return errors.Errorf("group ref empty") } - f := filepath.Join(ls.cfg.Dir(), refsDir, groupDir, id) + f := filepath.Join(ls.GroupDir(), id) if _, err := os.Lstat(f); err != nil { if !os.IsNotExist(err) { return err @@ -230,3 +230,16 @@ func (ls *LocalState) validate(builderName, nodeName, id string) error { } return nil } + +func (ls *LocalState) readVersion() int { + if vdt, err := os.ReadFile(filepath.Join(ls.cfg.Dir(), refsDir, "version")); err == nil { + if v, err := strconv.Atoi(string(vdt)); err == nil { + return v + } + } + return 1 +} + +func (ls *LocalState) writeVersion(version int) error { + return ls.cfg.AtomicWriteFile(filepath.Join(refsDir, "version"), []byte(strconv.Itoa(version)), 0600) +} diff --git a/localstate/localstate_test.go b/localstate/localstate_test.go index 180f8e4c..0943d83d 100644 --- a/localstate/localstate_test.go +++ b/localstate/localstate_test.go @@ -68,10 +68,8 @@ var ( testStateGroupID = "kvqs0sgly2rmitz84r25u9qd0" testStateGroup = StateGroup{ - Definition: []byte(`{"group":{"default":{"targets":["pre-checkin"]},"pre-checkin":{"targets":["vendor-update","format","build"]}},"target":{"build":{"context":".","dockerfile":"dev.Dockerfile","target":"build-update","platforms":["linux/amd64"],"output":["."]},"format":{"context":".","dockerfile":"dev.Dockerfile","target":"format-update","platforms":["linux/amd64"],"output":["."]},"vendor-update":{"context":".","dockerfile":"dev.Dockerfile","target":"vendor-update","platforms":["linux/amd64"],"output":["."]}}}`), - Targets: []string{"pre-checkin"}, - Inputs: []string{"*.platform=linux/amd64"}, - Refs: []string{"builder/builder0/hx2qf1w11qvz1x3k471c5i8xw", "builder/builder0/968zj0g03jmlx0s8qslnvh6rl", "builder/builder0/naf44f9i1710lf7y12lv5hb1z"}, + Targets: []string{"pre-checkin"}, + Refs: []string{"builder/builder0/hx2qf1w11qvz1x3k471c5i8xw", "builder/builder0/968zj0g03jmlx0s8qslnvh6rl", "builder/builder0/naf44f9i1710lf7y12lv5hb1z"}, } testStateGroupRef1ID = "hx2qf1w11qvz1x3k471c5i8xw" diff --git a/localstate/migrate.go b/localstate/migrate.go new file mode 100644 index 00000000..1334e1de --- /dev/null +++ b/localstate/migrate.go @@ -0,0 +1,56 @@ +package localstate + +import ( + "encoding/json" + "os" + "path/filepath" + + "github.com/pkg/errors" +) + +func (ls *LocalState) MigrateIfNeeded() error { + currentVersion := ls.readVersion() + if currentVersion == version { + return nil + } + migrations := map[int]func(*LocalState) error{ + 2: (*LocalState).migration2, + } + for v := currentVersion + 1; v <= version; v++ { + migration, found := migrations[v] + if !found { + return errors.Errorf("localstate migration v%d not found", v) + } + if err := migration(ls); err != nil { + return errors.Wrapf(err, "localstate migration v%d failed", v) + } + } + return ls.writeVersion(version) +} + +func (ls *LocalState) migration2() error { + return filepath.Walk(ls.GroupDir(), func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + dt, err := os.ReadFile(path) + if err != nil { + return err + } + var stg StateGroup + if err := json.Unmarshal(dt, &stg); err != nil { + return err + } + mdt, err := json.Marshal(stg) + if err != nil { + return err + } + if err := os.WriteFile(path, mdt, 0600); err != nil { + return err + } + return nil + }) +}