From f2078ac05b374b3978a420b35da488e0ca203d13 Mon Sep 17 00:00:00 2001 From: Lukas Berger Date: Thu, 14 Nov 2019 10:56:32 -0800 Subject: [PATCH] Support combined exporter/cacher and reversed analyzer/restorer. * Add support for Platform API Version 0.2 * Extend the incompatible-platform-version check to include a minimum-supported version. * When encountering lifecycle with platform API version 0.2 and above: * Stop requiring cacher when creating a new builder. * Remove cacher build phase. * Reorder analyzer and restorer build phases. * Change the -path cache flag name to -cache-dir. Signed-off-by: Lukas Berger --- build.go | 6 +- build_test.go | 3 +- create_builder_test.go | 55 +++++++++ internal/build/build.go | 82 +++++++++----- internal/build/phases.go | 37 ++++-- internal/builder/builder_test.go | 107 +++++++++++++++--- internal/builder/lifecycle.go | 30 ++--- internal/builder/lifecycle_test.go | 67 +++++++++-- .../lifecycle-v1.2.3-arch/analyzer | 1 + .../lifecycle-v1.2.3-arch/builder | 1 + .../lifecycle-v1.2.3-arch/cacher | 0 .../lifecycle-v1.2.3-arch/detector | 1 + .../lifecycle-v1.2.3-arch/exporter | 1 + .../lifecycle-v1.2.3-arch/launcher | 1 + .../lifecycle-v1.2.3-arch/restorer | 1 + .../lifecycle-platform-0.1/lifecycle.toml | 6 + .../builder/testdata/lifecycle/lifecycle.toml | 2 +- .../lifecycle-v3.4.5-arch/analyzer | 1 + .../lifecycle-v3.4.5-arch/builder | 1 + .../lifecycle-v3.4.5-arch/cacher | 0 .../lifecycle-v3.4.5-arch/detector | 1 + .../lifecycle-v3.4.5-arch/exporter | 1 + .../lifecycle-v3.4.5-arch/launcher | 1 + .../lifecycle-v3.4.5-arch/restorer | 1 + .../lifecycle-platform-0.1/lifecycle.toml | 6 + 25 files changed, 336 insertions(+), 77 deletions(-) create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/analyzer create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/builder rename internal/builder/testdata/{lifecycle => lifecycle-platform-0.1}/lifecycle-v1.2.3-arch/cacher (100%) create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/detector create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/exporter create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/launcher create mode 100755 internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/restorer create mode 100644 internal/builder/testdata/lifecycle-platform-0.1/lifecycle.toml create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/analyzer create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/builder rename testdata/{lifecycle => lifecycle-platform-0.1}/lifecycle-v3.4.5-arch/cacher (100%) create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/detector create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/exporter create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/launcher create mode 100755 testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/restorer create mode 100644 testdata/lifecycle-platform-0.1/lifecycle.toml diff --git a/build.go b/build.go index 724332636..c37d5632a 100644 --- a/build.go +++ b/build.go @@ -121,10 +121,12 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { lcPlatformAPIVersion = descriptor.API.PlatformVersion } - if !api.MustParse(build.PlatformAPIVersion).SupportsVersion(lcPlatformAPIVersion) { + if lcPlatformAPIVersion.Compare(api.MustParse(build.MinPlatformAPIVersion)) == -1 || + lcPlatformAPIVersion.Compare(api.MustParse(build.PlatformAPIVersion)) == 1 { return errors.Errorf( - "pack %s (Platform API version %s) is incompatible with builder %s (Platform API version %s)", + "pack %s (Platform API versions %s and %s) is incompatible with builder %s (Platform API version %s)", cmd.Version, + build.MinPlatformAPIVersion, build.PlatformAPIVersion, style.Symbol(opts.Builder), lcPlatformAPIVersion, diff --git a/build_test.go b/build_test.go index d50a51aed..43ba46697 100644 --- a/build_test.go +++ b/build_test.go @@ -1040,8 +1040,9 @@ func testBuild(t *testing.T, when spec.G, it spec.S) { h.AssertError(t, err, fmt.Sprintf( - "pack %s (Platform API version %s) is incompatible with builder %s (Platform API version %s)", + "pack %s (Platform API versions %s and %s) is incompatible with builder %s (Platform API version %s)", cmd.Version, + build.MinPlatformAPIVersion, build.PlatformAPIVersion, style.Symbol(builderName), "0.9", diff --git a/create_builder_test.go b/create_builder_test.go index 4c0e4f170..935341c4e 100644 --- a/create_builder_test.go +++ b/create_builder_test.go @@ -75,6 +75,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { mockDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/bp-one.tgz").Return(blob.NewBlob(filepath.Join("testdata", "buildpack")), nil).AnyTimes() mockDownloader.EXPECT().Download(gomock.Any(), "some/buildpack/dir").Return(blob.NewBlob(filepath.Join("testdata", "buildpack")), nil).AnyTimes() mockDownloader.EXPECT().Download(gomock.Any(), "file:///some-lifecycle").Return(blob.NewBlob(filepath.Join("testdata", "lifecycle")), nil).AnyTimes() + mockDownloader.EXPECT().Download(gomock.Any(), "file:///some-lifecycle-platform-0-1").Return(blob.NewBlob(filepath.Join("testdata", "lifecycle-platform-0.1")), nil).AnyTimes() subject = &Client{ logger: logger, @@ -302,6 +303,60 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { it("should embed the lifecycle", func() { h.AssertEq(t, bldr.LifecycleDescriptor().Info.Version.String(), "3.4.5") + h.AssertEq(t, bldr.LifecycleDescriptor().API.PlatformVersion.String(), "0.2") + + layerTar, err := fakeBuildImage.FindLayerWithPath("/cnb/lifecycle") + h.AssertNil(t, err) + assertTarHasFile(t, layerTar, "/cnb/lifecycle/detector") + assertTarHasFile(t, layerTar, "/cnb/lifecycle/restorer") + assertTarHasFile(t, layerTar, "/cnb/lifecycle/analyzer") + assertTarHasFile(t, layerTar, "/cnb/lifecycle/builder") + assertTarHasFile(t, layerTar, "/cnb/lifecycle/exporter") + assertTarHasFile(t, layerTar, "/cnb/lifecycle/launcher") + }) + }) + + when("creation succeeds for platform API < 0.2", func() { + var bldr *builder.Builder + + it.Before(func() { + opts.BuilderConfig.Lifecycle = pubbldr.LifecycleConfig{URI: "file:///some-lifecycle-platform-0-1"} + err := subject.CreateBuilder(context.TODO(), opts) + h.AssertNil(t, err) + h.AssertEq(t, fakeBuildImage.IsSaved(), true) + + bldr, err = builder.FromImage(fakeBuildImage) + h.AssertNil(t, err) + }) + + it("should set basic metadata", func() { + h.AssertEq(t, bldr.Name(), "some/builder") + h.AssertEq(t, bldr.Description(), "Some description") + h.AssertEq(t, bldr.UID, 1234) + h.AssertEq(t, bldr.GID, 4321) + h.AssertEq(t, bldr.StackID, "some.stack.id") + }) + + it("should set buildpack and order metadata", func() { + bpInfo := dist.BuildpackInfo{ + ID: "bp.one", + Version: "1.2.3", + } + h.AssertEq(t, bldr.Buildpacks(), []builder.BuildpackMetadata{{ + BuildpackInfo: bpInfo, + Latest: true, + }}) + h.AssertEq(t, bldr.Order(), dist.Order{{ + Group: []dist.BuildpackRef{{ + BuildpackInfo: bpInfo, + Optional: false, + }}, + }}) + }) + + it("should embed the lifecycle", func() { + h.AssertEq(t, bldr.LifecycleDescriptor().Info.Version.String(), "3.4.5") + h.AssertEq(t, bldr.LifecycleDescriptor().API.PlatformVersion.String(), "0.1") layerTar, err := fakeBuildImage.FindLayerWithPath("/cnb/lifecycle") h.AssertNil(t, err) diff --git a/internal/build/build.go b/internal/build/build.go index dd96b095b..cc2507197 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -10,27 +10,33 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/pkg/errors" + "github.com/buildpack/pack/internal/api" "github.com/buildpack/pack/internal/builder" "github.com/buildpack/pack/internal/cache" "github.com/buildpack/pack/internal/style" "github.com/buildpack/pack/logging" ) -// PlatformAPIVersion is the current Platform API Version supported by this version of pack. -const PlatformAPIVersion = "0.1" +const ( + // MinPlatformAPIVersion is the minimum Platform API Version supported by this version of pack. + MinPlatformAPIVersion = "0.1" + // PlatformAPIVersion is the current Platform API Version supported by this version of pack. + PlatformAPIVersion = "0.2" +) type Lifecycle struct { - builder *builder.Builder - logger logging.Logger - docker *client.Client - appPath string - appOnce *sync.Once - httpProxy string - httpsProxy string - noProxy string - version string - LayersVolume string - AppVolume string + builder *builder.Builder + logger logging.Logger + docker *client.Client + appPath string + appOnce *sync.Once + httpProxy string + httpsProxy string + noProxy string + version string + platformAPIVersion string + LayersVolume string + AppVolume string } type Cache interface { @@ -59,6 +65,11 @@ type LifecycleOptions struct { Network string } +// CombinedExporterCacher returns true if the lifecycle contains combined exporter/cacher phases and reversed analyzer/restorer phases. +func (l *Lifecycle) CombinedExporterCacher() bool { + return api.MustParse(l.platformAPIVersion).Compare(api.MustParse("0.2")) >= 0 +} + func (l *Lifecycle) Execute(ctx context.Context, opts LifecycleOptions) error { l.Setup(opts) defer l.Cleanup() @@ -79,16 +90,30 @@ func (l *Lifecycle) Execute(ctx context.Context, opts LifecycleOptions) error { return err } - l.logger.Info(style.Step("RESTORING")) - if opts.ClearCache { - l.logger.Info("Skipping 'restore' due to clearing cache") - } else if err := l.Restore(ctx, buildCache.Name()); err != nil { - return err - } + if l.CombinedExporterCacher() { + l.logger.Info(style.Step("ANALYZING")) + if err := l.Analyze(ctx, opts.Image.Name(), opts.Publish, opts.ClearCache); err != nil { + return err + } - l.logger.Info(style.Step("ANALYZING")) - if err := l.Analyze(ctx, opts.Image.Name(), opts.Publish, opts.ClearCache); err != nil { - return err + l.logger.Info(style.Step("RESTORING")) + if opts.ClearCache { + l.logger.Info("Skipping 'restore' due to clearing cache") + } else if err := l.Restore(ctx, buildCache.Name()); err != nil { + return err + } + } else { + l.logger.Info(style.Step("RESTORING")) + if opts.ClearCache { + l.logger.Info("Skipping 'restore' due to clearing cache") + } else if err := l.Restore(ctx, buildCache.Name()); err != nil { + return err + } + + l.logger.Info(style.Step("ANALYZING")) + if err := l.Analyze(ctx, opts.Image.Name(), opts.Publish, opts.ClearCache); err != nil { + return err + } } l.logger.Info(style.Step("BUILDING")) @@ -97,15 +122,17 @@ func (l *Lifecycle) Execute(ctx context.Context, opts LifecycleOptions) error { } l.logger.Info(style.Step("EXPORTING")) - launchCacheName := launchCache.Name() - if err := l.Export(ctx, opts.Image.Name(), opts.RunImage, opts.Publish, launchCacheName); err != nil { + if err := l.Export(ctx, opts.Image.Name(), opts.RunImage, opts.Publish, launchCache.Name(), buildCache.Name()); err != nil { return err } - l.logger.Info(style.Step("CACHING")) - if err := l.Cache(ctx, buildCache.Name()); err != nil { - return err + if !l.CombinedExporterCacher() { + l.logger.Info(style.Step("CACHING")) + if err := l.Cache(ctx, buildCache.Name()); err != nil { + return err + } } + return nil } @@ -119,6 +146,7 @@ func (l *Lifecycle) Setup(opts LifecycleOptions) { l.httpsProxy = opts.HTTPSProxy l.noProxy = opts.NoProxy l.version = opts.Builder.LifecycleDescriptor().Info.Version.String() + l.platformAPIVersion = opts.Builder.LifecycleDescriptor().API.PlatformVersion.String() } func (l *Lifecycle) Cleanup() error { diff --git a/internal/build/phases.go b/internal/build/phases.go index 8a48691b0..238626c6a 100644 --- a/internal/build/phases.go +++ b/internal/build/phases.go @@ -34,12 +34,17 @@ func (l *Lifecycle) Detect(ctx context.Context, networkMode string) error { } func (l *Lifecycle) Restore(ctx context.Context, cacheName string) error { + cacheFlag := "-path" + if l.CombinedExporterCacher() { + cacheFlag = "-cache-dir" + } + restore, err := l.NewPhase( "restorer", WithDaemonAccess(), WithArgs( l.withLogLevel( - "-path", cacheDir, + cacheFlag, cacheDir, "-layers", layersDir, )..., ), @@ -112,8 +117,8 @@ func (l *Lifecycle) Build(ctx context.Context, networkMode string) error { return build.Run(ctx) } -func (l *Lifecycle) Export(ctx context.Context, repoName string, runImage string, publish bool, launchCacheName string) error { - export, err := l.newExport(repoName, runImage, publish, launchCacheName) +func (l *Lifecycle) Export(ctx context.Context, repoName string, runImage string, publish bool, launchCacheName, cacheName string) error { + export, err := l.newExport(repoName, runImage, publish, launchCacheName, cacheName) if err != nil { return err } @@ -121,7 +126,7 @@ func (l *Lifecycle) Export(ctx context.Context, repoName string, runImage string return export.Run(ctx) } -func (l *Lifecycle) newExport(repoName, runImage string, publish bool, launchCacheName string) (*Phase, error) { +func (l *Lifecycle) newExport(repoName, runImage string, publish bool, launchCacheName, cacheName string) (*Phase, error) { if publish { return l.NewPhase( "exporter", @@ -137,20 +142,28 @@ func (l *Lifecycle) newExport(repoName, runImage string, publish bool, launchCac ) } + args := []string{} + if l.CombinedExporterCacher() { + args = append(args, "-cache-dir", cacheDir) + } + args = append( + args, + "-image", runImage, + "-layers", layersDir, + "-app", appDir, + "-daemon", + "-launch-cache", launchCacheDir, + repoName, + ) + return l.NewPhase( "exporter", WithDaemonAccess(), WithArgs( - l.withLogLevel( - "-image", runImage, - "-layers", layersDir, - "-app", appDir, - "-daemon", - "-launch-cache", launchCacheDir, - repoName, - )..., + l.withLogLevel(args...)..., ), WithBinds(fmt.Sprintf("%s:%s", launchCacheName, launchCacheDir)), + WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)), ) } diff --git a/internal/builder/builder_test.go b/internal/builder/builder_test.go index 5e657db9e..75598c0a4 100644 --- a/internal/builder/builder_test.go +++ b/internal/builder/builder_test.go @@ -38,16 +38,17 @@ func TestBuilder(t *testing.T) { func testBuilder(t *testing.T, when spec.G, it spec.S) { var ( - baseImage *fakes.Image - subject *builder.Builder - mockController *gomock.Controller - mockLifecycle *testmocks.MockLifecycle - bp1v1 dist.Buildpack - bp1v2 dist.Buildpack - bp2v1 dist.Buildpack - bpOrder dist.Buildpack - outBuf bytes.Buffer - logger logging.Logger + baseImage *fakes.Image + subject *builder.Builder + mockController *gomock.Controller + mockLifecycle *testmocks.MockLifecycle + mockLifecyclePlatform01 *testmocks.MockLifecycle + bp1v1 dist.Buildpack + bp1v2 dist.Buildpack + bp2v1 dist.Buildpack + bpOrder dist.Buildpack + outBuf bytes.Buffer + logger logging.Logger ) it.Before(func() { @@ -62,7 +63,20 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) { Version: &builder.Version{Version: *semver.MustParse("1.2.3")}, }, API: builder.LifecycleAPI{ - PlatformVersion: api.MustParse("2.2"), + PlatformVersion: api.MustParse("0.2"), + BuildpackVersion: api.MustParse("0.2"), + }, + }).AnyTimes() + + mockLifecyclePlatform01 = testmocks.NewMockLifecycle(mockController) + mockLifecyclePlatform01.EXPECT().Open().Return(archive.ReadDirAsTar( + filepath.Join("testdata", "lifecycle-platform-0.1"), ".", 0, 0, 0755), nil).AnyTimes() + mockLifecyclePlatform01.EXPECT().Descriptor().Return(builder.LifecycleDescriptor{ + Info: builder.LifecycleInfo{ + Version: &builder.Version{Version: *semver.MustParse("1.2.3")}, + }, + API: builder.LifecycleAPI{ + PlatformVersion: api.MustParse("0.1"), BuildpackVersion: api.MustParse("0.2"), }, }).AnyTimes() @@ -556,12 +570,77 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) { h.HasModTime(archive.NormalizedDateTime), ) + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/launcher", + h.ContentEquals("launcher"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + }) + + it("sets the lifecycle version on the metadata", func() { + label, err := baseImage.Label("io.buildpacks.builder.metadata") + h.AssertNil(t, err) + + var metadata builder.Metadata + h.AssertNil(t, json.Unmarshal([]byte(label), &metadata)) + h.AssertEq(t, metadata.Lifecycle.Version.String(), "1.2.3") + h.AssertEq(t, metadata.Lifecycle.API.PlatformVersion.String(), "0.2") + h.AssertEq(t, metadata.Lifecycle.API.BuildpackVersion.String(), "0.2") + }) + }) + + when("#SetLifecycle with Platform API version 0.1", func() { + it.Before(func() { + h.AssertNil(t, subject.SetLifecycle(mockLifecyclePlatform01)) + + h.AssertNil(t, subject.Save(logger)) + h.AssertEq(t, baseImage.IsSaved(), true) + }) + + it("should add the lifecycle binaries including cacher as an image layer", func() { + layerTar, err := baseImage.FindLayerWithPath("/cnb/lifecycle") + h.AssertNil(t, err) + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle", + h.IsDirectory(), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/detector", + h.ContentEquals("detector"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/restorer", + h.ContentEquals("restorer"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/analyzer", + h.ContentEquals("analyzer"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/builder", + h.ContentEquals("builder"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/exporter", + h.ContentEquals("exporter"), + h.HasFileMode(0755), + h.HasModTime(archive.NormalizedDateTime), + ) + h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/cacher", h.ContentEquals("cacher"), h.HasFileMode(0755), h.HasModTime(archive.NormalizedDateTime), ) - h.AssertOnTarEntry(t, layerTar, "/cnb/lifecycle/launcher", h.ContentEquals("launcher"), h.HasFileMode(0755), @@ -576,7 +655,7 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) { var metadata builder.Metadata h.AssertNil(t, json.Unmarshal([]byte(label), &metadata)) h.AssertEq(t, metadata.Lifecycle.Version.String(), "1.2.3") - h.AssertEq(t, metadata.Lifecycle.API.PlatformVersion.String(), "2.2") + h.AssertEq(t, metadata.Lifecycle.API.PlatformVersion.String(), "0.1") h.AssertEq(t, metadata.Lifecycle.API.BuildpackVersion.String(), "0.2") }) }) @@ -738,7 +817,7 @@ func testBuilder(t *testing.T, when spec.G, it spec.S) { it.Before(func() { h.AssertNil(t, baseImage.SetLabel( "io.buildpacks.builder.metadata", - `{"buildpacks": [{"id": "prev.id"}], "groups": [{"buildpacks": [{"id": "prev.id"}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}, "lifecycle": {"version": "6.6.6", "api": {"buildpack": "0.2", "platform": "2.2"}}}`, + `{"buildpacks": [{"id": "prev.id"}], "groups": [{"buildpacks": [{"id": "prev.id"}]}], "stack": {"runImage": {"image": "prev/run", "mirrors": ["prev/mirror"]}}, "lifecycle": {"version": "6.6.6", "api": {"buildpack": "0.2", "platform": "0.2"}}}`, )) var err error diff --git a/internal/builder/lifecycle.go b/internal/builder/lifecycle.go index 7dd3736dc..37aa588a7 100644 --- a/internal/builder/lifecycle.go +++ b/internal/builder/lifecycle.go @@ -24,18 +24,6 @@ const ( DefaultPlatformAPIVersion = "0.1" ) -var ( - lifecycleBinaries = []string{ - "detector", - "restorer", - "analyzer", - "builder", - "exporter", - "cacher", - "launcher", - } -) - type Blob interface { Open() (io.ReadCloser, error) } @@ -112,6 +100,22 @@ func (l *lifecycle) Descriptor() LifecycleDescriptor { return l.descriptor } +// Binaries returns a list of all binaries contained in the lifecycle. +func (l *lifecycle) binaries() []string { + binaries := []string{ + "detector", + "restorer", + "analyzer", + "builder", + "exporter", + "launcher", + } + if l.Descriptor().API.PlatformVersion.Compare(api.MustParse("0.2")) < 0 { + binaries = append(binaries, "cacher") + } + return binaries +} + func (l *lifecycle) validateBinaries() error { rc, err := l.Open() if err != nil { @@ -135,7 +139,7 @@ func (l *lifecycle) validateBinaries() error { headers[pathMatches[1]] = true } } - for _, p := range lifecycleBinaries { + for _, p := range l.binaries() { _, found := headers[p] if !found { return fmt.Errorf("did not find '%s' in tar", p) diff --git a/internal/builder/lifecycle_test.go b/internal/builder/lifecycle_test.go index dfbd38043..194417683 100644 --- a/internal/builder/lifecycle_test.go +++ b/internal/builder/lifecycle_test.go @@ -25,16 +25,28 @@ func TestLifecycle(t *testing.T) { func testLifecycle(t *testing.T, when spec.G, it spec.S) { when("#NewLifecycle", func() { - it("makes a lifecycle from a blob", func() { - lifecycle, err := builder.NewLifecycle(blob.NewBlob(filepath.Join("testdata", "lifecycle"))) - h.AssertNil(t, err) - h.AssertEq(t, lifecycle.Descriptor().Info.Version.String(), "1.2.3") - h.AssertEq(t, lifecycle.Descriptor().API.PlatformVersion.String(), "0.2") - h.AssertEq(t, lifecycle.Descriptor().API.BuildpackVersion.String(), "0.3") + when("there is a descriptor file with platform version 0.1 with cacher", func() { + it("makes a lifecycle from a blob", func() { + lifecycle, err := builder.NewLifecycle(blob.NewBlob(filepath.Join("testdata", "lifecycle-platform-0.1"))) + h.AssertNil(t, err) + h.AssertEq(t, lifecycle.Descriptor().Info.Version.String(), "1.2.3") + h.AssertEq(t, lifecycle.Descriptor().API.PlatformVersion.String(), "0.1") + h.AssertEq(t, lifecycle.Descriptor().API.BuildpackVersion.String(), "0.3") + }) + }) + + when("there is a descriptor file with platform version 0.2", func() { + it("makes a lifecycle from a blob", func() { + lifecycle, err := builder.NewLifecycle(blob.NewBlob(filepath.Join("testdata", "lifecycle"))) + h.AssertNil(t, err) + h.AssertEq(t, lifecycle.Descriptor().Info.Version.String(), "1.2.3") + h.AssertEq(t, lifecycle.Descriptor().API.PlatformVersion.String(), "0.2") + h.AssertEq(t, lifecycle.Descriptor().API.BuildpackVersion.String(), "0.3") + }) }) when("there is no descriptor file", func() { - it("assumes 0.1 API versions", func() { + it("assumes Platform API version 0.1", func() { lifecycle, err := builder.NewLifecycle(&fakeEmptyBlob{}) h.AssertNil(t, err) h.AssertEq(t, lifecycle.Descriptor().Info.Version.String(), "0.3.0") @@ -75,6 +87,47 @@ func testLifecycle(t *testing.T, when spec.G, it spec.S) { h.AssertError(t, err, "validating binaries") }) }) + + when("the lifecycle has platform version 0.1 and is missing cacher", func() { + var tmpDir string + + it.Before(func() { + var err error + tmpDir, err = ioutil.TempDir("", "") + h.AssertNil(t, err) + + h.AssertNil(t, ioutil.WriteFile(filepath.Join(tmpDir, "lifecycle.toml"), []byte(` +[api] + platform = "0.1" + buildpack = "0.3" + +[lifecycle] + version = "1.2.3" +`), os.ModePerm)) + + h.AssertNil(t, os.Mkdir(filepath.Join(tmpDir, "lifecycle"), os.ModePerm)) + + for _, f := range []string{ + "detector", + "restorer", + "analyzer", + "builder", + "exporter", + "launcher", + } { + h.AssertNil(t, ioutil.WriteFile(filepath.Join(tmpDir, "lifecycle", f), []byte("content"), os.ModePerm)) + } + }) + + it.After(func() { + h.AssertNil(t, os.RemoveAll(tmpDir)) + }) + + it("returns an error", func() { + _, err := builder.NewLifecycle(blob.NewBlob(tmpDir)) + h.AssertError(t, err, "validating binaries") + }) + }) }) } diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/analyzer b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/analyzer new file mode 100755 index 000000000..2c7cce34c --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/analyzer @@ -0,0 +1 @@ +analyzer \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/builder b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/builder new file mode 100755 index 000000000..b05c21cd9 --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/builder @@ -0,0 +1 @@ +builder \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle/lifecycle-v1.2.3-arch/cacher b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/cacher similarity index 100% rename from internal/builder/testdata/lifecycle/lifecycle-v1.2.3-arch/cacher rename to internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/cacher diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/detector b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/detector new file mode 100755 index 000000000..4ca7e105c --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/detector @@ -0,0 +1 @@ +detector \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/exporter b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/exporter new file mode 100755 index 000000000..76a0149ce --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/exporter @@ -0,0 +1 @@ +exporter \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/launcher b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/launcher new file mode 100755 index 000000000..89f76d0bc --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/launcher @@ -0,0 +1 @@ +launcher \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/restorer b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/restorer new file mode 100755 index 000000000..f6d18366f --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle-v1.2.3-arch/restorer @@ -0,0 +1 @@ +restorer \ No newline at end of file diff --git a/internal/builder/testdata/lifecycle-platform-0.1/lifecycle.toml b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle.toml new file mode 100644 index 000000000..5468f4fbb --- /dev/null +++ b/internal/builder/testdata/lifecycle-platform-0.1/lifecycle.toml @@ -0,0 +1,6 @@ +[api] + platform = "0.1" + buildpack = "0.3" + +[lifecycle] + version = "1.2.3" diff --git a/internal/builder/testdata/lifecycle/lifecycle.toml b/internal/builder/testdata/lifecycle/lifecycle.toml index f5a9e93ab..4e59c9ca3 100644 --- a/internal/builder/testdata/lifecycle/lifecycle.toml +++ b/internal/builder/testdata/lifecycle/lifecycle.toml @@ -3,4 +3,4 @@ buildpack = "0.3" [lifecycle] - version = "1.2.3" \ No newline at end of file + version = "1.2.3" diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/analyzer b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/analyzer new file mode 100755 index 000000000..2c7cce34c --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/analyzer @@ -0,0 +1 @@ +analyzer \ No newline at end of file diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/builder b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/builder new file mode 100755 index 000000000..b05c21cd9 --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/builder @@ -0,0 +1 @@ +builder \ No newline at end of file diff --git a/testdata/lifecycle/lifecycle-v3.4.5-arch/cacher b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/cacher similarity index 100% rename from testdata/lifecycle/lifecycle-v3.4.5-arch/cacher rename to testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/cacher diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/detector b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/detector new file mode 100755 index 000000000..4ca7e105c --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/detector @@ -0,0 +1 @@ +detector \ No newline at end of file diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/exporter b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/exporter new file mode 100755 index 000000000..76a0149ce --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/exporter @@ -0,0 +1 @@ +exporter \ No newline at end of file diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/launcher b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/launcher new file mode 100755 index 000000000..89f76d0bc --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/launcher @@ -0,0 +1 @@ +launcher \ No newline at end of file diff --git a/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/restorer b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/restorer new file mode 100755 index 000000000..f6d18366f --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle-v3.4.5-arch/restorer @@ -0,0 +1 @@ +restorer \ No newline at end of file diff --git a/testdata/lifecycle-platform-0.1/lifecycle.toml b/testdata/lifecycle-platform-0.1/lifecycle.toml new file mode 100644 index 000000000..a04d09398 --- /dev/null +++ b/testdata/lifecycle-platform-0.1/lifecycle.toml @@ -0,0 +1,6 @@ +[api] + platform = "0.1" + buildpack = "0.3" + +[lifecycle] + version = "3.4.5"