cmd/ruby/runtime/main.go (92 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. // Implements ruby/runtime buildpack. // The runtime buildpack installs the Ruby runtime. package main import ( "fmt" "os" "path/filepath" "github.com/GoogleCloudPlatform/buildpacks/pkg/env" gcp "github.com/GoogleCloudPlatform/buildpacks/pkg/gcpbuildpack" "github.com/GoogleCloudPlatform/buildpacks/pkg/nodejs" "github.com/GoogleCloudPlatform/buildpacks/pkg/ruby" "github.com/GoogleCloudPlatform/buildpacks/pkg/runtime" ) var osNodeVersionMap = map[string]string{ "ubuntu1804": "12.22.12", "ubuntu2204": "*", } // Rails apps using the "webpack" gem require Node.js for asset precompilation. func getRailsNodeVersion(ctx *gcp.Context) string { return osNodeVersionMap[runtime.OSForStack(ctx)] } func main() { gcp.Main(detectFn, buildFn) } func detectFn(ctx *gcp.Context) (gcp.DetectResult, error) { if result := runtime.CheckOverride("ruby"); result != nil { return result, nil } gemfileExists, err := ctx.FileExists("Gemfile") if err != nil { return nil, err } if gemfileExists { return gcp.OptInFileFound("Gemfile"), nil } gemsRbExists, err := ctx.FileExists("gems.rb") if err != nil { return nil, err } if gemsRbExists { return gcp.OptInFileFound("gems.rb"), nil } atLeastOne, err := ctx.HasAtLeastOneOutsideDependencyDirectories("*.rb") if err != nil { return nil, fmt.Errorf("finding *.rb files: %w", err) } if !atLeastOne { return gcp.OptOut("no .rb files found"), nil } return gcp.OptIn("found .rb files"), nil } func buildFn(ctx *gcp.Context) error { version, err := ruby.DetectVersion(ctx) if err != nil { return fmt.Errorf("determining runtime version: %w", err) } rl, err := ctx.Layer("ruby", gcp.BuildLayer, gcp.CacheLayer, gcp.LaunchLayerUnlessSkipRuntimeLaunch) if err != nil { return fmt.Errorf("creating layer: %w", err) } // Rails asset precompilation needs Node.js installed. Set the version if customer has not set it. if os.Getenv(nodejs.EnvNodeVersion) == "" { railsNodeVersion := getRailsNodeVersion(ctx) ctx.Logf("Setting Nodejs runtime version %s: %s", nodejs.EnvNodeVersion, railsNodeVersion) rl.BuildEnvironment.Override(nodejs.EnvNodeVersion, railsNodeVersion) } _, err = runtime.InstallTarballIfNotCached(ctx, runtime.Ruby, version, rl) if err != nil { return err } versionInstalled, _ := runtime.ResolveVersion(ctx, runtime.Ruby, version, runtime.OSForStack(ctx)) // Store the installed Ruby version for subsequent buildpacks (like RubyGems) that depend on it. rl.BuildEnvironment.Override(ruby.RubyVersionKey, versionInstalled) ctx.Exec([]string{"ldd", filepath.Join(rl.Path, "lib/ruby/3.1.0/x86_64-linux/psych.so")}) // For GAE and GCF, install RubyGems and Bundler in the same layer to maintain compatibility // with existing builder images. if env.IsGAE() || env.IsGCF() { err = runtime.PinGemAndBundlerVersion(ctx, version, rl) if err != nil { return fmt.Errorf("updating rubygems and bundler: %w", err) } } // Ruby sometimes writes to local directories tmp/ and log/, so we link these to writable areas. localTemp := filepath.Join(ctx.ApplicationRoot(), "tmp") localLog := filepath.Join(ctx.ApplicationRoot(), "log") ctx.Logf("Removing 'tmp' and 'log' directories in user code") if err := ctx.RemoveAll(localTemp); err != nil { return err } if err := ctx.RemoveAll(localLog); err != nil { return err } if err := ctx.Symlink("/tmp", localTemp); err != nil { return err } if err := ctx.Symlink("/var/log", localLog); err != nil { return err } return nil }