-
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.
Change Layer interface from &self to &mut self
The primary driver for wanting to mutate a layer is a desire for stateful logging. I hit this in the consuming state-machine interface, and previously, Josh hit it in a logging interface designed to track indentation level. Upside: - Developers are now allowed to do whatever they want within a layer - It's more technically correct to require a single reference for these functions. With the prior interface, it would be theoretically possible to execute the same Layer in parallel (though unlikely) - We can now change things between function calls. Downside: - Mutable self means there's no guarantee something didn't change between function calls.
- Loading branch information
Showing
10 changed files
with
210 additions
and
26 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
use crate::RubyBuildpack; | ||
use crate::{util, RubyBuildpackError}; | ||
use libcnb::build::BuildContext; | ||
use libcnb::data::layer_content_metadata::LayerTypes; | ||
use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder}; | ||
use libcnb::Env; | ||
use serde::Deserialize; | ||
use serde::Serialize; | ||
use std::path::Path; | ||
use std::process::Command; | ||
|
||
#[derive(Deserialize, Serialize, Debug, Clone)] | ||
pub(crate) struct BundlerLayerMetadata { | ||
gemfile_lock_checksum: String, | ||
} | ||
|
||
pub(crate) struct BundlerLayer { | ||
pub ruby_env: Env, | ||
} | ||
|
||
impl Layer for BundlerLayer { | ||
type Buildpack = RubyBuildpack; | ||
type Metadata = BundlerLayerMetadata; | ||
|
||
fn types(&self) -> LayerTypes { | ||
LayerTypes { | ||
build: true, | ||
launch: true, | ||
cache: true, | ||
} | ||
} | ||
|
||
fn create( | ||
&mut self, | ||
context: &BuildContext<Self::Buildpack>, | ||
layer_path: &Path, | ||
) -> Result<LayerResult<Self::Metadata>, RubyBuildpackError> { | ||
println!("---> Installing bundler"); | ||
|
||
util::run_simple_command( | ||
Command::new("gem") | ||
.args(["install", "bundler", "--force"]) | ||
.envs(&self.ruby_env), | ||
RubyBuildpackError::GemInstallBundlerCommandError, | ||
RubyBuildpackError::GemInstallBundlerUnexpectedExitStatus, | ||
)?; | ||
|
||
println!("---> Installing gems"); | ||
|
||
util::run_simple_command( | ||
Command::new("bundle") | ||
.args([ | ||
"install", | ||
"--path", | ||
layer_path.to_str().unwrap(), | ||
"--binstubs", | ||
layer_path.join("bin").to_str().unwrap(), | ||
]) | ||
.envs(&self.ruby_env), | ||
RubyBuildpackError::BundleInstallCommandError, | ||
RubyBuildpackError::BundleInstallUnexpectedExitStatus, | ||
)?; | ||
|
||
LayerResultBuilder::new(BundlerLayerMetadata { | ||
gemfile_lock_checksum: util::sha256_checksum(context.app_dir.join("Gemfile.lock")) | ||
.map_err(RubyBuildpackError::CouldNotGenerateChecksum)?, | ||
}) | ||
.build() | ||
} | ||
|
||
fn existing_layer_strategy( | ||
&mut self, | ||
context: &BuildContext<Self::Buildpack>, | ||
layer: &LayerData<Self::Metadata>, | ||
) -> Result<ExistingLayerStrategy, RubyBuildpackError> { | ||
util::sha256_checksum(context.app_dir.join("Gemfile.lock")) | ||
.map_err(RubyBuildpackError::CouldNotGenerateChecksum) | ||
.map(|checksum| { | ||
if checksum == layer.content_metadata.metadata.gemfile_lock_checksum { | ||
ExistingLayerStrategy::Keep | ||
} else { | ||
ExistingLayerStrategy::Update | ||
} | ||
}) | ||
} | ||
|
||
fn update( | ||
&mut self, | ||
context: &BuildContext<Self::Buildpack>, | ||
layer: &LayerData<Self::Metadata>, | ||
) -> Result<LayerResult<Self::Metadata>, RubyBuildpackError> { | ||
println!("---> Reusing gems"); | ||
|
||
util::run_simple_command( | ||
Command::new("bundle") | ||
.args(["config", "--local", "path", layer.path.to_str().unwrap()]) | ||
.envs(&self.ruby_env), | ||
RubyBuildpackError::BundleConfigCommandError, | ||
RubyBuildpackError::BundleConfigUnexpectedExitStatus, | ||
)?; | ||
|
||
util::run_simple_command( | ||
Command::new("bundle") | ||
.args([ | ||
"config", | ||
"--local", | ||
"bin", | ||
layer.path.join("bin").as_path().to_str().unwrap(), | ||
]) | ||
.envs(&self.ruby_env), | ||
RubyBuildpackError::BundleConfigCommandError, | ||
RubyBuildpackError::BundleConfigUnexpectedExitStatus, | ||
)?; | ||
|
||
LayerResultBuilder::new(BundlerLayerMetadata { | ||
gemfile_lock_checksum: util::sha256_checksum(context.app_dir.join("Gemfile.lock")) | ||
.map_err(RubyBuildpackError::CouldNotGenerateChecksum)?, | ||
}) | ||
.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::util; | ||
use crate::{RubyBuildpack, RubyBuildpackError}; | ||
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::path::Path; | ||
use tempfile::NamedTempFile; | ||
|
||
pub(crate) struct RubyLayer; | ||
|
||
impl Layer for RubyLayer { | ||
type Buildpack = RubyBuildpack; | ||
type Metadata = GenericMetadata; | ||
|
||
fn types(&self) -> LayerTypes { | ||
LayerTypes { | ||
build: true, | ||
launch: true, | ||
cache: false, | ||
} | ||
} | ||
|
||
fn create( | ||
&mut self, | ||
context: &BuildContext<Self::Buildpack>, | ||
layer_path: &Path, | ||
) -> Result<LayerResult<Self::Metadata>, RubyBuildpackError> { | ||
println!("---> Download and extracting Ruby"); | ||
|
||
let ruby_tgz = | ||
NamedTempFile::new().map_err(RubyBuildpackError::CouldNotCreateTemporaryFile)?; | ||
|
||
util::download( | ||
&context.buildpack_descriptor.metadata.ruby_url, | ||
ruby_tgz.path(), | ||
) | ||
.map_err(RubyBuildpackError::RubyDownloadError)?; | ||
|
||
util::untar(ruby_tgz.path(), layer_path).map_err(RubyBuildpackError::RubyUntarError)?; | ||
|
||
LayerResultBuilder::new(GenericMetadata::default()) | ||
.env( | ||
LayerEnv::new() | ||
.chainable_insert( | ||
Scope::All, | ||
ModificationBehavior::Prepend, | ||
"PATH", | ||
context.app_dir.join(".gem/ruby/2.6.6/bin"), | ||
) | ||
.chainable_insert( | ||
Scope::All, | ||
ModificationBehavior::Prepend, | ||
"LD_LIBRARY_PATH", | ||
layer_path, | ||
), | ||
) | ||
.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
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
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
Oops, something went wrong.