libcnb/layer/struct_api/mod.rs
1pub(crate) mod handling;
2
3// BuildContext is only used in RustDoc (https://github.com/rust-lang/rust/issues/79542)
4use crate::Buildpack;
5#[allow(unused)]
6use crate::build::BuildContext;
7use crate::layer::shared::{WriteLayerError, replace_layer_exec_d_programs, replace_layer_sboms};
8use crate::layer::{LayerError, ReadLayerError};
9use crate::layer_env::LayerEnv;
10use crate::sbom::Sbom;
11use libcnb_data::generic::GenericMetadata;
12use libcnb_data::layer::LayerName;
13use serde::Serialize;
14use std::borrow::Borrow;
15use std::collections::HashMap;
16use std::marker::PhantomData;
17use std::path::{Path, PathBuf};
18
19/// A definition for a cached layer.
20///
21/// Refer to the docs of [`BuildContext::cached_layer`] for usage examples.
22pub struct CachedLayerDefinition<'a, M, MA, RA> {
23 /// Whether the layer is intended for build.
24 pub build: bool,
25 /// Whether the layer is intended for launch.
26 pub launch: bool,
27 /// Callback for when the metadata of a restored layer cannot be parsed as `M`.
28 ///
29 /// Allows replacing the metadata before continuing (i.e. migration to a newer version) or
30 /// deleting the layer.
31 pub invalid_metadata_action: &'a dyn Fn(&GenericMetadata) -> MA,
32 /// Callback when the layer was restored from cache to validate the contents and metadata.
33 /// Can be used to delete existing cached layers.
34 pub restored_layer_action: &'a dyn Fn(&M, &Path) -> RA,
35}
36
37/// A definition for an uncached layer.
38///
39/// Refer to the docs of [`BuildContext::uncached_layer`] for usage examples.
40pub struct UncachedLayerDefinition {
41 /// Whether the layer is intended for build.
42 pub build: bool,
43 /// Whether the layer is intended for launch.
44 pub launch: bool,
45}
46
47/// The action to take when the layer metadata is invalid.
48#[derive(Copy, Clone, Debug)]
49pub enum InvalidMetadataAction<M> {
50 /// Delete the existing layer.
51 DeleteLayer,
52 /// Keep the layer, but replace the metadata. Commonly used to migrate to a newer
53 /// metadata format.
54 ReplaceMetadata(M),
55}
56
57/// The action to take when a previously cached layer was restored.
58#[derive(Copy, Clone, Debug)]
59pub enum RestoredLayerAction {
60 /// Delete the restored layer.
61 DeleteLayer,
62 /// Keep the restored layer. It can then be used as-is or updated if required.
63 KeepLayer,
64}
65
66/// Framework metadata about the layer state.
67///
68/// See: [`BuildContext::cached_layer`] and [`BuildContext::uncached_layer`]
69#[derive(Copy, Clone, Debug, Eq, PartialEq)]
70pub enum LayerState<MAC, RAC> {
71 /// The layer contains validated cached contents from a previous buildpack run.
72 ///
73 /// See: `restored_layer_action` in [`CachedLayerDefinition`].
74 Restored { cause: RAC },
75 /// The layer is empty. Inspect the contained [`EmptyLayerCause`] for the cause.
76 Empty { cause: EmptyLayerCause<MAC, RAC> },
77}
78
79/// The cause of a layer being empty.
80#[derive(Copy, Clone, Debug, Eq, PartialEq)]
81pub enum EmptyLayerCause<MAC, RAC> {
82 /// The layer wasn't cached in a previous buildpack run and was newly created.
83 NewlyCreated,
84 /// The layer was cached in a previous buildpack run, but the metadata was invalid and couldn't
85 /// be converted into a valid form. Subsequently, the layer was deleted entirely.
86 ///
87 /// See: `invalid_metadata_action` in [`CachedLayerDefinition`].
88 InvalidMetadataAction { cause: MAC },
89 /// The layer was cached in a previous buildpack run, but the `restored_layer_action` function
90 /// rejected the contents and/or metadata.
91 ///
92 /// See: `restored_layer_action` in [`CachedLayerDefinition`].
93 RestoredLayerAction { cause: RAC },
94}
95
96/// A value-to-value conversion for layer actions.
97///
98/// Similar to [`Into`], but specialized. Allowing it to also be implemented for
99/// values in the standard library such as [`Result`].
100///
101/// Implement this trait if you want to use your own types as actions.
102///
103/// libcnb ships with generic implementations for the majority of the use-cases:
104/// - Using [`RestoredLayerAction`] or [`InvalidMetadataAction`] directly.
105/// - Using [`RestoredLayerAction`] or [`InvalidMetadataAction`] directly, wrapped in a Result.
106/// - Using [`RestoredLayerAction`] or [`InvalidMetadataAction`] with a cause value in a tuple.
107/// - Using [`RestoredLayerAction`] or [`InvalidMetadataAction`] with a cause value in a tuple, wrapped in a Result.
108pub trait IntoAction<T, C, E> {
109 fn into_action(self) -> Result<(T, C), E>;
110}
111
112// Allows to use the layer actions directly.
113impl<T, E> IntoAction<T, (), E> for T {
114 fn into_action(self) -> Result<(T, ()), E> {
115 Ok((self, ()))
116 }
117}
118
119// Allows to use the layer actions directly wrapped in a Result.
120impl<T, E> IntoAction<T, (), E> for Result<T, E> {
121 fn into_action(self) -> Result<(T, ()), E> {
122 self.map(|value| (value, ()))
123 }
124}
125
126// Allows to use the layer actions directly with a cause as a tuple.
127impl<T, C, E> IntoAction<T, C, E> for (T, C) {
128 fn into_action(self) -> Result<(T, C), E> {
129 Ok(self)
130 }
131}
132
133// Allows to use the layer actions directly with a cause as a tuple wrapped in a Result.
134impl<T, C, E> IntoAction<T, C, E> for Result<(T, C), E> {
135 fn into_action(self) -> Result<(T, C), E> {
136 self
137 }
138}
139
140/// A reference to an existing layer on disk.
141///
142/// Provides functions to modify the layer such as replacing its metadata, environment, SBOMs or
143/// exec.d programs.
144///
145/// To obtain a such a reference, use [`BuildContext::cached_layer`] or [`BuildContext::uncached_layer`].
146pub struct LayerRef<B, MAC, RAC>
147where
148 B: Buildpack + ?Sized,
149{
150 name: LayerName,
151 // Technically not part of the layer itself. However, the functions that modify the layer
152 // will need a reference to the layers directory as they will also modify files outside the
153 // actual layer directory. To make LayerRef nice to use, we bite the bullet and include
154 // the layers_dir here.
155 layers_dir: PathBuf,
156 buildpack: PhantomData<B>,
157 pub state: LayerState<MAC, RAC>,
158}
159
160impl<B, MAC, RAC> LayerRef<B, MAC, RAC>
161where
162 B: Buildpack,
163{
164 /// Returns the path to the layer on disk.
165 pub fn path(&self) -> PathBuf {
166 self.layers_dir.join(self.name.as_str())
167 }
168
169 /// Writes the given layer metadata to disk.
170 ///
171 /// Any existing layer metadata will be overwritten. The new value does not have to be of the
172 /// same type as the existing metadata.
173 pub fn write_metadata<M>(&self, metadata: M) -> crate::Result<(), B::Error>
174 where
175 M: Serialize,
176 {
177 crate::layer::shared::replace_layer_metadata(&self.layers_dir, &self.name, metadata)
178 .map_err(|error| {
179 crate::Error::LayerError(LayerError::WriteLayerError(
180 WriteLayerError::WriteLayerMetadataError(error),
181 ))
182 })
183 }
184
185 /// Writes the given layer environment to disk.
186 ///
187 /// Any existing layer environment will be overwritten.
188 pub fn write_env(&self, env: impl Borrow<LayerEnv>) -> crate::Result<(), B::Error> {
189 env.borrow()
190 .write_to_layer_dir(self.path())
191 .map_err(|error| {
192 crate::Error::LayerError(LayerError::WriteLayerError(WriteLayerError::IoError(
193 error,
194 )))
195 })
196 }
197
198 /// Reads the current layer environment from disk.
199 ///
200 /// Note that this includes implicit entries such as adding `bin/` to `PATH`. See [`LayerEnv`]
201 /// docs for details on implicit entries.
202 pub fn read_env(&self) -> crate::Result<LayerEnv, B::Error> {
203 LayerEnv::read_from_layer_dir(self.path()).map_err(|error| {
204 crate::Error::LayerError(LayerError::ReadLayerError(ReadLayerError::IoError(error)))
205 })
206 }
207
208 /// Writes the given SBOMs to disk.
209 ///
210 /// Any existing SBOMs will be overwritten.
211 pub fn write_sboms(&self, sboms: &[Sbom]) -> crate::Result<(), B::Error> {
212 replace_layer_sboms(&self.layers_dir, &self.name, sboms).map_err(|error| {
213 crate::Error::LayerError(LayerError::WriteLayerError(
214 WriteLayerError::ReplaceLayerSbomsError(error),
215 ))
216 })
217 }
218
219 /// Writes the given exec.d programs to disk.
220 ///
221 /// Any existing exec.d programs will be overwritten.
222 pub fn write_exec_d_programs<P, S>(&self, programs: P) -> crate::Result<(), B::Error>
223 where
224 S: Into<String>,
225 P: IntoIterator<Item = (S, PathBuf)>,
226 {
227 let programs = programs
228 .into_iter()
229 .map(|(k, v)| (k.into(), v))
230 .collect::<HashMap<_, _>>();
231
232 replace_layer_exec_d_programs(&self.layers_dir, &self.name, &programs).map_err(|error| {
233 crate::Error::LayerError(LayerError::WriteLayerError(
234 WriteLayerError::ReplaceLayerExecdProgramsError(error),
235 ))
236 })
237 }
238}