pkg/gcpbuildpack/layer.go (101 lines of code) (raw):

// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package gcpbuildpack import ( "os" "strings" "github.com/GoogleCloudPlatform/buildpacks/pkg/buildererror" "github.com/GoogleCloudPlatform/buildpacks/pkg/env" "github.com/buildpacks/libcnb/v2" ) const ( layerMode os.FileMode = 0755 ) type layerOption func(ctx *Context, l *libcnb.Layer) error // BuildLayer specifies a Build layer. var BuildLayer = func(ctx *Context, l *libcnb.Layer) error { l.Build = true return nil } // CacheLayer specifies a Cache layer. var CacheLayer = func(ctx *Context, l *libcnb.Layer) error { l.Cache = true return nil } // LaunchLayer specifies a Launch layer. var LaunchLayer = func(ctx *Context, l *libcnb.Layer) error { l.Launch = true return nil } // LaunchLayerIfDevMode specifies a Launch layer, but only if dev mode is enabled. var LaunchLayerIfDevMode = func(ctx *Context, l *libcnb.Layer) error { devMode, err := env.IsDevMode() if err != nil { ctx.Warnf("Dev mode not enabled: %v", err) return nil } if devMode { l.Launch = true } return nil } // LaunchLayerUnlessSkipRuntimeLaunch specifies a Launch layer unless XGoogleSkipRuntimeLaunch is set to "true". var LaunchLayerUnlessSkipRuntimeLaunch = func(ctx *Context, l *libcnb.Layer) error { skip, err := env.IsPresentAndTrue(env.XGoogleSkipRuntimeLaunch) if err != nil { return buildererror.Errorf(buildererror.StatusInternal, err.Error()) } if !skip { l.Launch = true } return nil } // Layer returns a layer, creating its directory. func (ctx *Context) Layer(name string, opts ...layerOption) (*libcnb.Layer, error) { if strings.Contains(name, "/") { return nil, buildererror.Errorf(buildererror.StatusInternal, "%v is an invalid layer name; layer names may not contain '/'", name) } l, err := ctx.buildContext.Layers.Layer(name) if err != nil { return nil, buildererror.Errorf(buildererror.StatusInternal, err.Error()) } if err := ctx.MkdirAll(l.Path, layerMode); err != nil { return nil, buildererror.Errorf(buildererror.StatusInternal, "creating %s: %v", l.Path, err) } for _, o := range opts { if err := o(ctx, &l); err != nil { return nil, err } } if l.Metadata == nil { l.Metadata = make(map[string]interface{}) } ctx.layerContributors = append(ctx.layerContributors, layerContributor{l: &l}) ctx.buildResult.Layers = append(ctx.buildResult.Layers, l) return &l, nil } type layerContributor struct { l *libcnb.Layer } // Contribute accepts a layer and transforms it, returning a layer. func (lc layerContributor) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { return *lc.l, nil } // Name is the name of the layer. func (lc layerContributor) Name() string { return lc.l.Name } // ClearLayer erases the existing layer, and re-creates the directory. func (ctx *Context) ClearLayer(l *libcnb.Layer) error { if err := ctx.RemoveAll(l.Path); err != nil { return err } if err := ctx.MkdirAll(l.Path, layerMode); err != nil { return err } l.Metadata = make(map[string]interface{}) return nil } // SetMetadata sets metadata on the layer. func (ctx *Context) SetMetadata(l *libcnb.Layer, key, value string) { l.Metadata[key] = value } // GetMetadata gets metadata from the layer. func (ctx *Context) GetMetadata(l *libcnb.Layer, key string) string { v, ok := l.Metadata[key] if !ok { return "" } s, ok := v.(string) if !ok { ctx.Exit(1, buildererror.Errorf(buildererror.StatusInternal, "could not cast metadata %v to string", v)) } return s }