From 9bd75d7bae72daba377000d1f78309ae4806de84 Mon Sep 17 00:00:00 2001 From: Manuel Fuchs Date: Thu, 13 Jun 2024 12:25:02 +0200 Subject: [PATCH] Polish --- libcnb/src/build.rs | 12 ++-- libcnb/src/layer/struct_api/handling.rs | 24 ++++---- libcnb/src/layer/struct_api/mod.rs | 75 ++++++++++++++++++------- 3 files changed, 74 insertions(+), 37 deletions(-) diff --git a/libcnb/src/build.rs b/libcnb/src/build.rs index aade6553..63ca9d26 100644 --- a/libcnb/src/build.rs +++ b/libcnb/src/build.rs @@ -133,21 +133,21 @@ impl BuildContext { 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>, - ) -> crate::Result, B::Error> + layer_definition: impl Borrow>, + ) -> crate::Result, B::Error> where M: 'a + Serialize + DeserializeOwned, - O: 'a + IntoAction, X, B::Error>, - I: 'a + IntoAction, + MA: 'a + IntoAction, MAC, B::Error>, + EA: 'a + IntoAction, { let layer_definition = layer_definition.borrow(); diff --git a/libcnb/src/layer/struct_api/handling.rs b/libcnb/src/layer/struct_api/handling.rs index f8e00c53..afc8bfe6 100644 --- a/libcnb/src/layer/struct_api/handling.rs +++ b/libcnb/src/layer/struct_api/handling.rs @@ -16,18 +16,18 @@ use serde::Serialize; use std::marker::PhantomData; use std::path::{Path, PathBuf}; -pub(crate) fn handle_layer( +pub(crate) fn handle_layer( 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, B::Error> +) -> crate::Result, B::Error> where B: Buildpack + ?Sized, M: Serialize + DeserializeOwned, - MA: IntoAction, MC, B::Error>, - IA: IntoAction, + MA: IntoAction, MAC, B::Error>, + EA: IntoAction, { match read_layer::(layers_dir, &layer_name) { Ok(None) => create_layer(layer_types, &layer_name, layers_dir, EmptyReason::Uncached), @@ -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 @@ -82,7 +82,7 @@ where layer_types, &layer_name, layers_dir, - EmptyReason::MetadataInvalid(cause), + EmptyReason::MetadataInvalid { cause }, ) } (InvalidMetadataAction::ReplaceMetadata(metadata), _) => { @@ -104,12 +104,12 @@ where } } -fn create_layer( +fn create_layer( layer_types: LayerTypes, layer_name: &LayerName, layers_dir: &Path, - empty_reason: EmptyReason, -) -> Result, crate::Error> + empty_reason: EmptyReason, +) -> Result, crate::Error> where B: Buildpack + ?Sized, { diff --git a/libcnb/src/layer/struct_api/mod.rs b/libcnb/src/layer/struct_api/mod.rs index faf42354..263b9f89 100644 --- a/libcnb/src/layer/struct_api/mod.rs +++ b/libcnb/src/layer/struct_api/mod.rs @@ -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; @@ -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, @@ -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, @@ -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 { + /// 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 { +#[derive(Copy, Clone, Debug)] +pub enum LayerContents { /// 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), + Empty(EmptyReason), } -pub enum EmptyReason { +#[derive(Copy, Clone, Debug)] +pub enum EmptyReason { /// 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 { fn into_action(self) -> Result<(T, C), E>; } +// Allows to use the layer actions directly. impl IntoAction for T { fn into_action(self) -> Result<(T, ()), E> { Ok((self, ())) } } +// Allows to use the layer actions directly wrapped in a Result. +impl IntoAction for Result { + 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 IntoAction 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 IntoAction for Result<(T, C), E> { fn into_action(self) -> Result<(T, C), E> { self } } -impl IntoAction for Result { - fn into_action(self) -> Result<(T, ()), E> { - self.map(|value| (value, ())) - } -} - -pub struct LayerRef +/// 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 where B: Buildpack + ?Sized, { name: LayerName, layers_dir: PathBuf, buildpack: PhantomData, - pub contents: LayerContents, + pub contents: LayerContents, } -impl LayerRef +impl LayerRef 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(&self, metadata: M) -> crate::Result<(), B::Error> where M: Serialize, @@ -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( @@ -150,6 +186,7 @@ where }) } + /// Replace all existing layer exec.d programs with new ones. pub fn replace_exec_d_programs(&self, programs: P) -> crate::Result<(), B::Error> where S: Into,