Skip to content

Commit

Permalink
Polish
Browse files Browse the repository at this point in the history
  • Loading branch information
Malax committed Jun 13, 2024
1 parent d4a8d67 commit 9bd75d7
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 37 deletions.
12 changes: 6 additions & 6 deletions libcnb/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,21 @@ impl<B: Buildpack + ?Sized> BuildContext<B> {
cache: false,
},
&|_| InvalidMetadataAction::DeleteLayer,
&|_: &GenericMetadata, _| InspectExistingAction::Delete,
&|_: &GenericMetadata, _| InspectExistingAction::DeleteLayer,
layer_name,
&self.layers_dir,
)
}

pub fn cached_layer<'a, M, X, Y, O, I>(
pub fn cached_layer<'a, M, MA, EA, MAC, EAC>(
&self,
layer_name: LayerName,
layer_definition: impl Borrow<CachedLayerDefinition<'a, M, O, I>>,
) -> crate::Result<LayerRef<B, X, Y>, B::Error>
layer_definition: impl Borrow<CachedLayerDefinition<'a, M, MA, EA>>,
) -> crate::Result<LayerRef<B, MAC, EAC>, B::Error>
where
M: 'a + Serialize + DeserializeOwned,
O: 'a + IntoAction<InvalidMetadataAction<M>, X, B::Error>,
I: 'a + IntoAction<InspectExistingAction, Y, B::Error>,
MA: 'a + IntoAction<InvalidMetadataAction<M>, MAC, B::Error>,
EA: 'a + IntoAction<InspectExistingAction, EAC, B::Error>,
{
let layer_definition = layer_definition.borrow();

Expand Down
24 changes: 12 additions & 12 deletions libcnb/src/layer/struct_api/handling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ use serde::Serialize;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};

pub(crate) fn handle_layer<B, M, MA, IA, MC, IC>(
pub(crate) fn handle_layer<B, M, MA, EA, MAC, EAC>(
layer_types: LayerTypes,
invalid_metadata: &dyn Fn(&GenericMetadata) -> MA,
inspect_existing: &dyn Fn(&M, &Path) -> IA,
inspect_existing: &dyn Fn(&M, &Path) -> EA,
layer_name: LayerName,
layers_dir: &Path,
) -> crate::Result<LayerRef<B, MC, IC>, B::Error>
) -> crate::Result<LayerRef<B, MAC, EAC>, B::Error>
where
B: Buildpack + ?Sized,
M: Serialize + DeserializeOwned,
MA: IntoAction<InvalidMetadataAction<M>, MC, B::Error>,
IA: IntoAction<InspectExistingAction, IC, B::Error>,
MA: IntoAction<InvalidMetadataAction<M>, MAC, B::Error>,
EA: IntoAction<InspectExistingAction, EAC, B::Error>,
{
match read_layer::<M, _>(layers_dir, &layer_name) {
Ok(None) => create_layer(layer_types, &layer_name, layers_dir, EmptyReason::Uncached),
Expand All @@ -37,17 +37,17 @@ where
.map_err(crate::Error::BuildpackError)?;

match inspect_action {
(InspectExistingAction::Delete, cause) => {
(InspectExistingAction::DeleteLayer, cause) => {
delete_layer(layers_dir, &layer_name).map_err(LayerError::DeleteLayerError)?;

create_layer(
layer_types,
&layer_name,
layers_dir,
EmptyReason::Inspect(cause),
EmptyReason::Inspect { cause },
)
}
(InspectExistingAction::Keep, cause) => {
(InspectExistingAction::KeepLayer, cause) => {
// Always write the layer types as:
// a) they might be different from what is currently on disk
// b) the cache field will be removed by CNB lifecycle on cache restore
Expand Down Expand Up @@ -82,7 +82,7 @@ where
layer_types,
&layer_name,
layers_dir,
EmptyReason::MetadataInvalid(cause),
EmptyReason::MetadataInvalid { cause },
)
}
(InvalidMetadataAction::ReplaceMetadata(metadata), _) => {
Expand All @@ -104,12 +104,12 @@ where
}
}

fn create_layer<X, Y, B>(
fn create_layer<B, MAC, EAC>(
layer_types: LayerTypes,
layer_name: &LayerName,
layers_dir: &Path,
empty_reason: EmptyReason<X, Y>,
) -> Result<LayerRef<B, X, Y>, crate::Error<B::Error>>
empty_reason: EmptyReason<MAC, EAC>,
) -> Result<LayerRef<B, MAC, EAC>, crate::Error<B::Error>>
where
B: Buildpack + ?Sized,
{
Expand Down
75 changes: 56 additions & 19 deletions libcnb/src/layer/struct_api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub(crate) mod handling;

use crate::build::BuildContext;
use crate::layer::shared::{replace_layer_exec_d_programs, replace_layer_sboms, WriteLayerError};
use crate::layer::LayerError;
use crate::layer_env::LayerEnv;
Expand All @@ -13,6 +14,8 @@ use std::marker::PhantomData;
use std::path::{Path, PathBuf};

/// A definition for a cached layer.
///
/// Refer to the docs of [`BuildContext::cached_layer`] for usage examples.
pub struct CachedLayerDefinition<'a, M, MA, EA> {
/// Whether the layer is intended for build.
pub build: bool,
Expand All @@ -29,6 +32,8 @@ pub struct CachedLayerDefinition<'a, M, MA, EA> {
}

/// A definition for an uncached layer.
///
/// Refer to the docs of [`BuildContext::uncached_layer`] for usage examples.
pub struct UncachedLayerDefinition {
/// Whether the layer is intended for build.
pub build: bool,
Expand All @@ -37,93 +42,122 @@ pub struct UncachedLayerDefinition {
}

/// The action to take when the layer metadata is invalid.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum InvalidMetadataAction<M> {
/// Delete the existing layer.
DeleteLayer,
/// Keep the layer, but replace the metadata. Commonly used to migrate to a newer
/// metadata format.
ReplaceMetadata(M),
}

/// The action to take after inspecting existing layer data.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum InspectExistingAction {
Delete,
Keep,
/// Delete the existing layer.
DeleteLayer,
/// Keep the layer as-is.
KeepLayer,
}

pub enum LayerContents<X, Y> {
#[derive(Copy, Clone, Debug)]
pub enum LayerContents<MAC, EAC> {
/// The layer contains validated cached contents from a previous buildpack run.
///
/// See: `inspect_existing` in [`CachedLayerDefinition`].
Cached(Y),
Cached(EAC),
/// The layer is empty. Inspect the contained [`EmptyReason`] for details why.
Empty(EmptyReason<X, Y>),
Empty(EmptyReason<MAC, EAC>),
}

pub enum EmptyReason<X, Y> {
#[derive(Copy, Clone, Debug)]
pub enum EmptyReason<MAC, EAC> {
/// The layer wasn't cached in a previous buildpack run.
Uncached,
/// The layer was cached in a previous buildpack run, but the metadata was invalid and couldn't
/// be converted into a valid form. Subsequently, the layer was deleted entirely.
///
/// See: `invalid_metadata` in [`CachedLayerDefinition`].
MetadataInvalid(X),
MetadataInvalid { cause: MAC },
/// The layer was cached in a previous buildpack run, but the `inspect_existing` function
/// rejected the contents.
///
/// See: `inspect_existing` in [`CachedLayerDefinition`].
Inspect(Y),
Inspect { cause: EAC },
}

/// A value-to-value conversion for layer actions.
///
/// Similar to [`Into`], but specialized. Allowing it to also be implemented for
/// values in the standard library such as [`Result`].
///
/// Implement this trait if you want to use your own types as actions.
///
/// libcnb ships with generic implementations for the majority of the use-cases:
/// - Using [`InspectExistingAction`] or [`InvalidMetadataAction`] directly.
/// - Using [`InspectExistingAction`] or [`InvalidMetadataAction`] directly, wrapped in a Result.
/// - Using [`InspectExistingAction`] or [`InvalidMetadataAction`] with a cause value in a tuple.
/// - Using [`InspectExistingAction`] or [`InvalidMetadataAction`] with a cause value in a tuple, wrapped in a Result.
pub trait IntoAction<T, C, E> {
fn into_action(self) -> Result<(T, C), E>;
}

// Allows to use the layer actions directly.
impl<T, E> IntoAction<T, (), E> for T {
fn into_action(self) -> Result<(T, ()), E> {
Ok((self, ()))
}
}

// Allows to use the layer actions directly wrapped in a Result.
impl<T, E> IntoAction<T, (), E> for Result<T, E> {
fn into_action(self) -> Result<(T, ()), E> {
self.map(|value| (value, ()))
}
}

// Allows to use the layer actions directly with a cause as a tuple.
impl<T, C, E> IntoAction<T, C, E> for (T, C) {
fn into_action(self) -> Result<(T, C), E> {
Ok(self)
}
}

// Allows to use the layer actions directly with a cause as a tuple wrapped in a Result.
impl<T, C, E> IntoAction<T, C, E> for Result<(T, C), E> {
fn into_action(self) -> Result<(T, C), E> {
self
}
}

impl<T, E> IntoAction<T, (), E> for Result<T, E> {
fn into_action(self) -> Result<(T, ()), E> {
self.map(|value| (value, ()))
}
}

pub struct LayerRef<B, X, Y>
/// A reference to an existing layer on disk.
///
/// Provides functions to modify the layer such as replacing its metadata, environment, SBOMs or
/// exec.d programs.
///
/// To obtain a such a reference, use [`BuildContext::cached_layer`] or [`BuildContext::uncached_layer`].
pub struct LayerRef<B, MAC, EAC>
where
B: Buildpack + ?Sized,
{
name: LayerName,
layers_dir: PathBuf,
buildpack: PhantomData<B>,
pub contents: LayerContents<X, Y>,
pub contents: LayerContents<MAC, EAC>,
}

impl<B, X, Y> LayerRef<B, X, Y>
impl<B, MAC, EAC> LayerRef<B, MAC, EAC>
where
B: Buildpack,
{
/// Returns the path to the layer on disk.
pub fn path(&self) -> PathBuf {
self.layers_dir.join(self.name.as_str())
}

/// Replaces the existing layer metadata with a new value.
///
/// The new value does not have to be of the same type as the existing metadata.
pub fn replace_metadata<M>(&self, metadata: M) -> crate::Result<(), B::Error>
where
M: Serialize,
Expand All @@ -136,12 +170,14 @@ where
})
}

/// Replaces the existing layer environment with a new one.
pub fn replace_env(&self, env: &LayerEnv) -> crate::Result<(), B::Error> {
env.write_to_layer_dir(self.path()).map_err(|error| {
crate::Error::LayerError(LayerError::WriteLayerError(WriteLayerError::IoError(error)))
})
}

/// Replace all existing layer SBOMs with new ones.
pub fn replace_sboms(&self, sboms: &[Sbom]) -> crate::Result<(), B::Error> {
replace_layer_sboms(&self.layers_dir, &self.name, sboms).map_err(|error| {
crate::Error::LayerError(LayerError::WriteLayerError(
Expand All @@ -150,6 +186,7 @@ where
})
}

/// Replace all existing layer exec.d programs with new ones.
pub fn replace_exec_d_programs<P, S>(&self, programs: P) -> crate::Result<(), B::Error>
where
S: Into<String>,
Expand Down

0 comments on commit 9bd75d7

Please sign in to comment.