Skip to content

Commit

Permalink
Support combined exporter/cacher and reversed analyzer/restorer.
Browse files Browse the repository at this point in the history
* 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 <bergerl@google.com>
  • Loading branch information
lukasberger committed Nov 14, 2019
1 parent 78dc055 commit f2078ac
Show file tree
Hide file tree
Showing 25 changed files with 336 additions and 77 deletions.
6 changes: 4 additions & 2 deletions build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
55 changes: 55 additions & 0 deletions create_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
82 changes: 55 additions & 27 deletions internal/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand All @@ -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"))
Expand All @@ -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
}

Expand All @@ -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 {
Expand Down
37 changes: 25 additions & 12 deletions internal/build/phases.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)...,
),
Expand Down Expand Up @@ -112,16 +117,16 @@ 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
}
defer export.Cleanup()
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",
Expand All @@ -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)),
)
}

Expand Down
Loading

0 comments on commit f2078ac

Please sign in to comment.