diff --git a/internal/server/singleprocess/state/box.go b/internal/server/singleprocess/state/box.go index d4e57f83f..695570b29 100644 --- a/internal/server/singleprocess/state/box.go +++ b/internal/server/singleprocess/state/box.go @@ -3,6 +3,7 @@ package state import ( "github.com/golang/protobuf/proto" "github.com/hashicorp/go-memdb" + "github.com/hashicorp/go-version" "github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk" "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" bolt "go.etcd.io/bbolt" @@ -66,6 +67,20 @@ func (s *State) BoxPut(box *vagrant_server.Box) error { return err } +func (s *State) BoxFind(b *vagrant_plugin_sdk.Ref_Box) (*vagrant_server.Box, error) { + memTxn := s.inmem.Txn(false) + defer memTxn.Abort() + + var result *vagrant_server.Box + err := s.db.View(func(dbTxn *bolt.Tx) error { + var err error + result, err = s.boxFind(dbTxn, memTxn, b) + return err + }) + + return result, err +} + func (s *State) boxList( memTxn *memdb.Txn, ) (r []*vagrant_plugin_sdk.Ref_Box, err error) { @@ -144,6 +159,53 @@ func (s *State) boxPut( return } +func (s *State) boxFind( + dbTxn *bolt.Tx, + memTxn *memdb.Txn, + ref *vagrant_plugin_sdk.Ref_Box, +) (r *vagrant_server.Box, err error) { + var match *boxIndexRecord + highestVersion, _ := version.NewVersion("0.0.0") + req := s.newBoxIndexRecordByRef(ref) + // Get the name first + if req.Name != "" { + raw, err := memTxn.Get( + boxIndexTableName, + boxIndexNameIndexName, + req.Name, + ) + if err != nil { + return nil, err + } + for e := raw.Next(); e != nil; e = raw.Next() { + boxIndexEntry := e.(*boxIndexRecord) + if req.Version != "" { + if boxIndexEntry.Version != req.Version { + continue + } + } + if req.Provider != "" { + if boxIndexEntry.Provider != req.Provider { + continue + } + } + v, _ := version.NewVersion(boxIndexEntry.Version) + if v.GreaterThan(highestVersion) { + highestVersion = v + match = boxIndexEntry + } + } + + if match != nil { + return s.boxGet(dbTxn, memTxn, &vagrant_plugin_sdk.Ref_Box{ + ResourceId: match.Id, + }) + } + } + + return +} + const ( boxIndexIdIndexName = "id" boxIndexNameIndexName = "name" diff --git a/internal/server/singleprocess/state/box_test.go b/internal/server/singleprocess/state/box_test.go index 572ee25b9..c8a40f94b 100644 --- a/internal/server/singleprocess/state/box_test.go +++ b/internal/server/singleprocess/state/box_test.go @@ -117,4 +117,80 @@ func TestBox(t *testing.T) { require.NoError(err) require.Len(b, 2) }) + + t.Run("Find", func(t *testing.T) { + require := require.New(t) + + s := TestState(t) + defer s.Close() + + err := s.BoxPut(&vagrant_server.Box{ + Id: "hashicorp/bionic-1.2.3-virtualbox", + Name: "hashicorp/bionic", + Version: "1.2.3", + Provider: "virtualbox", + }) + require.NoError(err) + + err = s.BoxPut(&vagrant_server.Box{ + Id: "hashicorp/bionic-1.2.4-virtualbox", + Name: "hashicorp/bionic", + Version: "1.2.4", + Provider: "virtualbox", + }) + require.NoError(err) + + b, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "hashicorp/bionic", + }) + require.NoError(err) + require.Equal(b.Name, "hashicorp/bionic") + require.Equal(b.Version, "1.2.4") + + b2, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "hashicorp/bionic", + Version: "1.2.3", + }) + require.NoError(err) + require.Equal(b2.Name, "hashicorp/bionic") + require.Equal(b2.Version, "1.2.3") + + b3, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "hashicorp/bionic", + Version: "1.2.3", + Provider: "virtualbox", + }) + require.NoError(err) + require.Equal(b3.Name, "hashicorp/bionic") + require.Equal(b3.Version, "1.2.3") + require.Equal(b3.Provider, "virtualbox") + + b4, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "hashicorp/bionic", + Version: "1.2.3", + Provider: "dontexist", + }) + require.NoError(err) + require.Nil(b4) + + b5, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "hashicorp/bionic", + Version: "9.9.9", + Provider: "virtualbox", + }) + require.NoError(err) + require.Nil(b5) + + b6, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Version: "1.2.3", + }) + require.NoError(err) + require.Nil(b6) + + b7, err := s.BoxFind(&vagrant_plugin_sdk.Ref_Box{ + Name: "dontexist", + }) + require.NoError(err) + require.Nil(b7) + }) }