Skip to content

Commit

Permalink
Move user binstubs to its own layer
Browse files Browse the repository at this point in the history
At runtime, the alphabetical order of the layer name determines the order it is loaded. At build time, the order that the `env` variable is modified determines the order.

At both build and runtime we want the bin stubs to come first on the PATH when executing user defined code. This was already working for runtime, but wasn't for build time as the "gems" layer was being prepended to the path after the "venv" layer (because the `venv` layer was being defined first, last definition wins).

I originally tried to fix this by defining the PATH inside of the "gems" layer along with the gems path but ran into heroku/libcnb.rs#899. The libcnb.rs project loads the user defined PATH modification last, but I'm unclear if that's spec defined behavior or not https://github.com/buildpacks/spec/blob/main/buildpack.md#layer-paths.
  • Loading branch information
schneems committed Jan 10, 2025
1 parent 24a34bd commit c91cee5
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
26 changes: 25 additions & 1 deletion buildpacks/ruby/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use layers::{
use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder};
use libcnb::data::build_plan::BuildPlanBuilder;
use libcnb::data::launch::LaunchBuilder;
use libcnb::data::layer_name;
use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder};
use libcnb::generic::{GenericMetadata, GenericPlatform};
use libcnb::layer_env::Scope;
use libcnb::layer::UncachedLayerDefinition;
use libcnb::layer_env::{LayerEnv, ModificationBehavior, Scope};
use libcnb::Platform;
use libcnb::{buildpack_main, Buildpack};
use std::io::stdout;
Expand Down Expand Up @@ -220,6 +222,28 @@ impl Buildpack for RubyBuildpack {
(bullet.done(), layer_env.apply(Scope::Build, &env))
};

env = {
let user_binstubs = context.uncached_layer(
layer_name!("user_binstubs"),
UncachedLayerDefinition {
build: true,
launch: true,
},
)?;
user_binstubs.write_env(
LayerEnv::new()
.chainable_insert(Scope::All, ModificationBehavior::Delimiter, "PATH", ":")
.chainable_insert(
Scope::All,
ModificationBehavior::Prepend,
"PATH",
context.app_dir.join("bin"),
),
)?;

user_binstubs.read_env()?.apply(Scope::Build, &env)
};

// ## Detect gems
let (mut build_output, gem_list, default_process) = {
let bullet = build_output.bullet("Default process detection");
Expand Down
12 changes: 2 additions & 10 deletions buildpacks/ruby/src/steps/default_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,12 @@ pub(crate) fn default_env(
.to_string();

let layer_ref = context.uncached_layer(
layer_name!("venv"),
layer_name!("env_defaults"),
UncachedLayerDefinition {
build: true,
launch: true,
},
)?;
let update_env = LayerEnv::new()
.chainable_insert(Scope::All, ModificationBehavior::Delimiter, "PATH", ":")
.chainable_insert(
Scope::All,
ModificationBehavior::Prepend,
"PATH",
context.app_dir.join("bin"),
);
let env = layer_ref
.write_env({
[
Expand All @@ -65,7 +57,7 @@ pub(crate) fn default_env(
("DISABLE_SPRING", "1"),
]
.iter()
.fold(update_env, |layer_env, (name, value)| {
.fold(LayerEnv::new(), |layer_env, (name, value)| {
layer_env.chainable_insert(Scope::All, ModificationBehavior::Default, name, value)
})
})
Expand Down

0 comments on commit c91cee5

Please sign in to comment.