-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When a developer needs to set environment variables only, they have to make a layer struct and pass it to `handle_layer`. Instead of forcing them to write a boilerplate struct, this commit provides two utility structs: - `DefaultEnvLayer` - Used to set default environment variables - `ConfigureEnvLayer` - Can be used with `LayerEnv::new()` to configure any environment variables (versus `DefaultEnvLayer` only creates default environment variables). An alternative to providing structs could be to provide functions that accept a context and layer name in addition to the required env data.
- Loading branch information
Showing
4 changed files
with
214 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
use libcnb::build::BuildContext; | ||
use libcnb::data::layer_content_metadata::LayerTypes; | ||
use libcnb::generic::GenericMetadata; | ||
use libcnb::layer::{Layer, LayerResult, LayerResultBuilder}; | ||
use libcnb::layer_env::{LayerEnv, ModificationBehavior, Scope}; | ||
use std::ffi::OsString; | ||
use std::marker::PhantomData; | ||
use std::path::Path; | ||
|
||
/// Set default environment variables | ||
/// | ||
/// If all you need to do is set default environment values, you can use | ||
/// the `DefaultEnvLayer::new` function to set those values without having | ||
/// to create a struct from scratch. | ||
/// | ||
/// ```no_run | ||
///# use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; | ||
///# use libcnb::data::launch::{LaunchBuilder, ProcessBuilder}; | ||
///# use libcnb::data::process_type; | ||
///# use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; | ||
///# use libcnb::generic::{GenericError, GenericMetadata, GenericPlatform}; | ||
///# use libcnb::{buildpack_main, Buildpack}; | ||
///# use libcnb::data::layer::LayerName; | ||
/// | ||
///# pub(crate) struct HelloWorldBuildpack; | ||
/// | ||
/// use libcnb::Env; | ||
/// use libcnb::data::layer_name; | ||
/// use libcnb::layer_env::Scope; | ||
/// use libherokubuildpack::env::DefaultEnvLayer; | ||
/// | ||
///# impl Buildpack for HelloWorldBuildpack { | ||
///# type Platform = GenericPlatform; | ||
///# type Metadata = GenericMetadata; | ||
///# type Error = GenericError; | ||
/// | ||
///# fn detect(&self, _context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> { | ||
///# todo!() | ||
///# } | ||
/// | ||
///# fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> { | ||
/// let env = Env::from_current(); | ||
/// // Don't forget to apply context.platform.env() too; | ||
/// | ||
/// let layer = context // | ||
/// .handle_layer( | ||
/// layer_name!("default_env"), | ||
/// DefaultEnvLayer::new( | ||
/// [ | ||
/// ("JRUBY_OPTS", "-Xcompile.invokedynamic=false"), | ||
/// ("RACK_ENV", "production"), | ||
/// ("RAILS_ENV", "production"), | ||
/// ("RAILS_SERVE_STATIC_FILES", "enabled"), | ||
/// ("RAILS_LOG_TO_STDOUT", "enabled"), | ||
/// ("MALLOC_ARENA_MAX", "2"), | ||
/// ("DISABLE_SPRING", "1"), | ||
/// ] | ||
/// .into_iter(), | ||
/// ), | ||
/// )?; | ||
/// let env = layer.env.apply(Scope::Build, &env); | ||
/// | ||
///# todo!() | ||
///# } | ||
///# } | ||
/// | ||
/// ``` | ||
pub struct DefaultEnvLayer; | ||
|
||
impl DefaultEnvLayer { | ||
#[allow(clippy::new_ret_no_self)] | ||
pub fn new<E, K, V, B>(env: E) -> ConfigureEnvLayer<B> | ||
where | ||
E: IntoIterator<Item = (K, V)> + Clone, | ||
K: Into<OsString>, | ||
V: Into<OsString>, | ||
B: libcnb::Buildpack, | ||
{ | ||
let mut layer_env = LayerEnv::new(); | ||
for (key, value) in env { | ||
layer_env = | ||
layer_env.chainable_insert(Scope::All, ModificationBehavior::Default, key, value); | ||
} | ||
|
||
ConfigureEnvLayer { | ||
data: layer_env, | ||
_buildpack: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
/// Set environment variables | ||
/// | ||
/// If you want to set many default environment variables you can use | ||
/// `DefaultEnvLayer`. If you need to set different types of environment | ||
/// variables you can use this struct `ConfigureEnvLayer` | ||
/// | ||
/// Example: | ||
/// | ||
/// ```no_run | ||
///# use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; | ||
///# use libcnb::data::launch::{LaunchBuilder, ProcessBuilder}; | ||
///# use libcnb::data::process_type; | ||
///# use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; | ||
///# use libcnb::generic::{GenericError, GenericMetadata, GenericPlatform}; | ||
///# use libcnb::{buildpack_main, Buildpack}; | ||
///# use libcnb::data::layer::LayerName; | ||
/// | ||
///# pub(crate) struct HelloWorldBuildpack; | ||
/// | ||
/// use libcnb::Env; | ||
/// use libcnb::data::layer_name; | ||
/// use libcnb::layer_env::{LayerEnv, ModificationBehavior, Scope}; | ||
/// use libherokubuildpack::env::ConfigureEnvLayer; | ||
/// | ||
///# impl Buildpack for HelloWorldBuildpack { | ||
///# type Platform = GenericPlatform; | ||
///# type Metadata = GenericMetadata; | ||
///# type Error = GenericError; | ||
/// | ||
///# fn detect(&self, _context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> { | ||
///# todo!() | ||
///# } | ||
/// | ||
///# fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> { | ||
/// let env = Env::from_current(); | ||
/// // Don't forget to apply context.platform.env() too; | ||
/// | ||
/// let layer = context // | ||
/// .handle_layer( | ||
/// layer_name!("configure_env"), | ||
/// ConfigureEnvLayer::new( | ||
/// LayerEnv::new() | ||
/// .chainable_insert( | ||
/// Scope::All, | ||
/// ModificationBehavior::Override, | ||
/// "BUNDLE_GEMFILE", // Tells bundler where to find the `Gemfile` | ||
/// context.app_dir.join("Gemfile"), | ||
/// ) | ||
/// .chainable_insert( | ||
/// Scope::All, | ||
/// ModificationBehavior::Override, | ||
/// "BUNDLE_CLEAN", // After successful `bundle install` bundler will automatically run `bundle clean` | ||
/// "1", | ||
/// ) | ||
/// .chainable_insert( | ||
/// Scope::All, | ||
/// ModificationBehavior::Override, | ||
/// "BUNDLE_DEPLOYMENT", // Requires the `Gemfile.lock` to be in sync with the current `Gemfile`. | ||
/// "1", | ||
/// ) | ||
/// .chainable_insert( | ||
/// Scope::All, | ||
/// ModificationBehavior::Default, | ||
/// "MY_ENV_VAR", | ||
/// "Whatever I want" | ||
/// ) | ||
/// ), | ||
/// )?; | ||
/// let env = layer.env.apply(Scope::Build, &env); | ||
/// | ||
///# todo!() | ||
///# } | ||
///# } | ||
/// | ||
/// ``` | ||
pub struct ConfigureEnvLayer<B: libcnb::Buildpack> { | ||
pub(crate) data: LayerEnv, | ||
pub(crate) _buildpack: std::marker::PhantomData<B>, | ||
} | ||
|
||
impl<B> ConfigureEnvLayer<B> | ||
where | ||
B: libcnb::Buildpack, | ||
{ | ||
#[must_use] | ||
pub fn new(env: LayerEnv) -> Self { | ||
ConfigureEnvLayer { | ||
data: env, | ||
_buildpack: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
impl<B> Layer for ConfigureEnvLayer<B> | ||
where | ||
B: libcnb::Buildpack, | ||
{ | ||
type Buildpack = B; | ||
type Metadata = GenericMetadata; | ||
|
||
fn types(&self) -> LayerTypes { | ||
LayerTypes { | ||
build: true, | ||
launch: true, | ||
cache: false, | ||
} | ||
} | ||
|
||
fn create( | ||
&self, | ||
_context: &BuildContext<Self::Buildpack>, | ||
_layer_path: &Path, | ||
) -> Result<LayerResult<Self::Metadata>, B::Error> { | ||
LayerResultBuilder::new(GenericMetadata::default()) | ||
.env(self.data.clone()) | ||
.build() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters