diff --git a/internal/core/box.go b/internal/core/box.go index 884ac4552..ea3ed1d6a 100644 --- a/internal/core/box.go +++ b/internal/core/box.go @@ -5,10 +5,12 @@ import ( "io/ioutil" "net/http" "os" + "path/filepath" "sync" "time" "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/go-version" "github.com/hashicorp/vagrant-plugin-sdk/core" "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" @@ -26,6 +28,103 @@ type Box struct { m sync.Mutex } +func NewBox(opts ...BoxOption) (b *Box, err error) { + b = &Box{ + logger: hclog.L(), + box: &vagrant_server.Box{}, + } + + for _, opt := range opts { + if oerr := opt(b); oerr != nil { + err = multierror.Append(err, oerr) + } + } + + if b.basis == nil { + return nil, errors.New("Basis must be specified for the box") + } + + if b.box.Directory == "" { + return nil, errors.New("Box directory must be specified for the box") + + } + + metadataFile := filepath.Join(b.box.Directory, "metadata.json") + if _, err := os.Stat(metadataFile); err != nil { + return nil, err + } + + data, err := os.ReadFile(metadataFile) + if err != nil { + return nil, err + } + metadata, err := LoadBoxMetadata(data) + if err != nil { + return nil, err + } + mapstructure.Decode(metadata, &b.box.Metadata) + b.Save() + return +} + +type BoxOption func(*Box) error + +func BoxWithLogger(log hclog.Logger) BoxOption { + return func(b *Box) (err error) { + b.logger = log + return + } +} + +func BoxWithBasis(basis *Basis) BoxOption { + return func(b *Box) (err error) { + b.basis = basis + return + } +} + +func BoxWithName(name string) BoxOption { + return func(b *Box) (err error) { + b.box.Name = name + return + } +} + +func BoxWithVersion(ver string) BoxOption { + return func(b *Box) (err error) { + _, err = version.NewVersion(ver) + if err != nil { + return err + } + b.box.Version = ver + return + } +} + +func BoxWithProvider(provider string) BoxOption { + return func(b *Box) (err error) { + b.box.Provider = provider + return + } +} + +func BoxWithMetadataUrl(url string) BoxOption { + return func(b *Box) (err error) { + b.box.MetadataUrl = url + return + } +} + +func BoxWithDirectory(dir string) BoxOption { + return func(b *Box) (err error) { + if _, err := os.Stat(dir); err != nil { + return err + } + b.box.Directory = dir + return + } +} + func (b *Box) loadMetadata() (metadata *BoxMetadata, err error) { resp, err := http.Get(b.box.MetadataUrl) if err != nil { diff --git a/internal/core/box_test.go b/internal/core/box_test.go index a3348cf78..4409cf0d6 100644 --- a/internal/core/box_test.go +++ b/internal/core/box_test.go @@ -1,9 +1,15 @@ package core import ( + "context" + "io/ioutil" + "os" + "path/filepath" "testing" "time" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/vagrant/internal/plugin" "github.com/hashicorp/vagrant/internal/server/proto/vagrant_server" "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/timestamppb" @@ -39,6 +45,31 @@ func hashicorpBionicTestBox() *Box { } } +func TestNewBox(t *testing.T) { + pluginManager := plugin.NewManager( + context.Background(), + hclog.New(&hclog.LoggerOptions{}), + ) + basis := TestBasis(t, WithPluginManager(pluginManager)) + td, err := ioutil.TempDir("", "box-metadata") + require.NoError(t, err) + data := []byte("{}") + err = os.WriteFile(filepath.Join(td, "metadata.json"), data, 0644) + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(td) }) + + box, err := NewBox( + BoxWithBasis(basis), + BoxWithName("test/box"), + BoxWithVersion("1.2.3"), + BoxWithVersion("1.2.3"), + BoxWithDirectory(td), + ) + require.NoError(t, err) + require.NotNil(t, box) + require.Equal(t, "test/box", box.box.Name) +} + func TestBoxAutomaticUpdateCheckAllowed(t *testing.T) { testBox := newTestBox() // just did automated check