From b333e86efc796df12dd39f006b908a5207c9e069 Mon Sep 17 00:00:00 2001 From: Manuel Fuchs Date: Fri, 14 Jun 2024 11:00:17 +0200 Subject: [PATCH 1/4] Migrate readonly-layer-files test buildpack to struct layer API --- .../readonly-layer-files/src/layer.rs | 54 ------------------- .../readonly-layer-files/src/main.rs | 33 +++++++++--- 2 files changed, 25 insertions(+), 62 deletions(-) delete mode 100644 test-buildpacks/readonly-layer-files/src/layer.rs diff --git a/test-buildpacks/readonly-layer-files/src/layer.rs b/test-buildpacks/readonly-layer-files/src/layer.rs deleted file mode 100644 index 2f1e3402..00000000 --- a/test-buildpacks/readonly-layer-files/src/layer.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::TestBuildpack; -use libcnb::build::BuildContext; -use libcnb::data::layer_content_metadata::LayerTypes; -use libcnb::generic::GenericMetadata; -use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder}; -use libcnb::Buildpack; -use std::fs; -use std::fs::Permissions; -use std::os::unix::fs::PermissionsExt; -use std::path::Path; - -pub(crate) struct TestLayer; - -impl Layer for TestLayer { - type Buildpack = TestBuildpack; - type Metadata = GenericMetadata; - - fn types(&self) -> LayerTypes { - LayerTypes { - launch: true, - build: true, - cache: true, - } - } - - fn create( - &mut self, - _context: &BuildContext, - layer_path: &Path, - ) -> Result, ::Error> { - let directory = layer_path.join("sub_directory"); - fs::create_dir_all(&directory).expect("Couldn't create subdirectory"); - - fs::write(directory.join("foo.txt"), "hello world!").expect("Couldn't write file"); - - // By making the sub-directory read-only, files inside it cannot be deleted. This would - // cause issues when libcnb.rs tries to delete a cached layer directory unless libcnb.rs - // handles this case explicitly. - fs::set_permissions(&directory, Permissions::from_mode(0o555)) - .expect("Couldn't set permissions to read-only"); - - LayerResultBuilder::new(GenericMetadata::default()).build() - } - - fn existing_layer_strategy( - &mut self, - _context: &BuildContext, - _layer_data: &LayerData, - ) -> Result::Error> { - // Even though this is (currently) the default, we explicitly declare it here to make sure - // the layer will be recreated, even if the default in libcnb changes. - Ok(ExistingLayerStrategy::Recreate) - } -} diff --git a/test-buildpacks/readonly-layer-files/src/main.rs b/test-buildpacks/readonly-layer-files/src/main.rs index 96b264fa..853376f7 100644 --- a/test-buildpacks/readonly-layer-files/src/main.rs +++ b/test-buildpacks/readonly-layer-files/src/main.rs @@ -1,15 +1,12 @@ -// This test buildpack uses the older trait Layer API. It will be updated to the newer API -// before the next libcnb.rs release. -#![allow(deprecated)] - -mod layer; - -use crate::layer::TestLayer; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::layer_name; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::{GenericMetadata, GenericPlatform}; +use libcnb::layer::{CachedLayerDefinition, InspectRestoredAction, InvalidMetadataAction}; use libcnb::{buildpack_main, Buildpack}; +use std::fs; +use std::fs::Permissions; +use std::os::unix::fs::PermissionsExt; // Suppress warnings due to the `unused_crate_dependencies` lint not handling integration tests well. #[cfg(test)] @@ -27,7 +24,27 @@ impl Buildpack for TestBuildpack { } fn build(&self, context: BuildContext) -> libcnb::Result { - context.handle_layer(layer_name!("test"), TestLayer)?; + let layer_ref = context.cached_layer( + layer_name!("test"), + CachedLayerDefinition { + build: true, + launch: true, + invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, + inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::DeleteLayer, + }, + )?; + + let directory = layer_ref.path().join("sub_directory"); + fs::create_dir_all(&directory).expect("Couldn't create subdirectory"); + + fs::write(directory.join("foo.txt"), "hello world!").expect("Couldn't write file"); + + // By making the sub-directory read-only, files inside it cannot be deleted. This would + // cause issues when libcnb.rs tries to delete a cached layer directory unless libcnb.rs + // handles this case explicitly. + fs::set_permissions(&directory, Permissions::from_mode(0o555)) + .expect("Couldn't set permissions to read-only"); + BuildResultBuilder::new().build() } } From da148a1742eace597158a4feb8398389b653f68f Mon Sep 17 00:00:00 2001 From: Manuel Fuchs Date: Fri, 14 Jun 2024 11:11:26 +0200 Subject: [PATCH 2/4] Migrate sbom test buildpack to struct layer API --- test-buildpacks/sbom/src/main.rs | 72 ++++++++++++++++--- test-buildpacks/sbom/src/test_layer.rs | 60 ---------------- test-buildpacks/sbom/src/test_layer_2.rs | 52 -------------- .../sbom/tests/integration_test.rs | 3 +- 4 files changed, 62 insertions(+), 125 deletions(-) delete mode 100644 test-buildpacks/sbom/src/test_layer.rs delete mode 100644 test-buildpacks/sbom/src/test_layer_2.rs diff --git a/test-buildpacks/sbom/src/main.rs b/test-buildpacks/sbom/src/main.rs index f8543cf7..5620eecd 100644 --- a/test-buildpacks/sbom/src/main.rs +++ b/test-buildpacks/sbom/src/main.rs @@ -1,17 +1,11 @@ -// This test buildpack uses the older trait Layer API. It will be updated to the newer API -// before the next libcnb.rs release. -#![allow(deprecated)] - -mod test_layer; -mod test_layer_2; - -use crate::test_layer::TestLayer; -use crate::test_layer_2::TestLayer2; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::layer_name; use libcnb::data::sbom::SbomFormat; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::{GenericMetadata, GenericPlatform}; +use libcnb::layer::{ + CachedLayerDefinition, InspectRestoredAction, InvalidMetadataAction, LayerState, +}; use libcnb::sbom::Sbom; use libcnb::{buildpack_main, Buildpack}; @@ -31,8 +25,64 @@ impl Buildpack for TestBuildpack { } fn build(&self, context: BuildContext) -> libcnb::Result { - context.handle_layer(layer_name!("test"), TestLayer)?; - context.handle_layer(layer_name!("test2"), TestLayer2)?; + let first_layer_ref = context.cached_layer( + layer_name!("test"), + CachedLayerDefinition { + build: true, + launch: true, + invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, + inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::KeepLayer, + }, + )?; + + match first_layer_ref.state { + LayerState::Restored { .. } => { + first_layer_ref.replace_sboms(&[])?; + } + LayerState::Empty { .. } => { + first_layer_ref.replace_sboms(&[ + Sbom::from_bytes( + SbomFormat::CycloneDxJson, + *include_bytes!("../etc/cyclonedx_3.sbom.json"), + ), + Sbom::from_bytes( + SbomFormat::SpdxJson, + *include_bytes!("../etc/spdx_3.sbom.json"), + ), + Sbom::from_bytes( + SbomFormat::SyftJson, + *include_bytes!("../etc/syft_3.sbom.json"), + ), + ])?; + } + } + + let second_layer_ref = context.cached_layer( + layer_name!("test2"), + CachedLayerDefinition { + build: true, + launch: true, + invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, + inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::KeepLayer, + }, + )?; + + if let LayerState::Empty { .. } = second_layer_ref.state { + second_layer_ref.replace_sboms(&[ + Sbom::from_bytes( + SbomFormat::CycloneDxJson, + *include_bytes!("../etc/cyclonedx_2.sbom.json"), + ), + Sbom::from_bytes( + SbomFormat::SpdxJson, + *include_bytes!("../etc/spdx_2.sbom.json"), + ), + Sbom::from_bytes( + SbomFormat::SyftJson, + *include_bytes!("../etc/syft_2.sbom.json"), + ), + ])?; + } BuildResultBuilder::new() .launch_sbom(Sbom::from_bytes( diff --git a/test-buildpacks/sbom/src/test_layer.rs b/test-buildpacks/sbom/src/test_layer.rs deleted file mode 100644 index ce4154cb..00000000 --- a/test-buildpacks/sbom/src/test_layer.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{SbomFormat, TestBuildpack}; -use libcnb::build::BuildContext; -use libcnb::data::layer_content_metadata::LayerTypes; -use libcnb::generic::GenericMetadata; -use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder}; -use libcnb::sbom::Sbom; -use libcnb::Buildpack; -use std::path::Path; - -pub(crate) struct TestLayer; - -impl Layer for TestLayer { - type Buildpack = TestBuildpack; - type Metadata = GenericMetadata; - - fn types(&self) -> LayerTypes { - LayerTypes { - launch: true, - build: true, - cache: true, - } - } - - fn create( - &mut self, - _context: &BuildContext, - _layer_path: &Path, - ) -> Result, ::Error> { - LayerResultBuilder::new(GenericMetadata::default()) - .sbom(Sbom::from_bytes( - SbomFormat::CycloneDxJson, - *include_bytes!("../etc/cyclonedx_3.sbom.json"), - )) - .sbom(Sbom::from_bytes( - SbomFormat::SpdxJson, - *include_bytes!("../etc/spdx_3.sbom.json"), - )) - .sbom(Sbom::from_bytes( - SbomFormat::SyftJson, - *include_bytes!("../etc/syft_3.sbom.json"), - )) - .build() - } - - fn existing_layer_strategy( - &mut self, - _context: &BuildContext, - _layer_data: &LayerData, - ) -> Result::Error> { - Ok(ExistingLayerStrategy::Update) - } - - fn update( - &mut self, - _context: &BuildContext, - _layer_data: &LayerData, - ) -> Result, ::Error> { - LayerResultBuilder::new(GenericMetadata::default()).build() - } -} diff --git a/test-buildpacks/sbom/src/test_layer_2.rs b/test-buildpacks/sbom/src/test_layer_2.rs deleted file mode 100644 index bf244321..00000000 --- a/test-buildpacks/sbom/src/test_layer_2.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{SbomFormat, TestBuildpack}; -use libcnb::build::BuildContext; -use libcnb::data::layer_content_metadata::LayerTypes; -use libcnb::generic::GenericMetadata; -use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder}; -use libcnb::sbom::Sbom; -use libcnb::Buildpack; -use std::path::Path; - -pub(crate) struct TestLayer2; - -impl Layer for TestLayer2 { - type Buildpack = TestBuildpack; - type Metadata = GenericMetadata; - - fn types(&self) -> LayerTypes { - LayerTypes { - launch: true, - build: true, - cache: true, - } - } - - fn create( - &mut self, - _context: &BuildContext, - _layer_path: &Path, - ) -> Result, ::Error> { - LayerResultBuilder::new(GenericMetadata::default()) - .sbom(Sbom::from_bytes( - SbomFormat::CycloneDxJson, - *include_bytes!("../etc/cyclonedx_2.sbom.json"), - )) - .sbom(Sbom::from_bytes( - SbomFormat::SpdxJson, - *include_bytes!("../etc/spdx_2.sbom.json"), - )) - .sbom(Sbom::from_bytes( - SbomFormat::SyftJson, - *include_bytes!("../etc/syft_2.sbom.json"), - )) - .build() - } - - fn existing_layer_strategy( - &mut self, - _context: &BuildContext, - _layer_data: &LayerData, - ) -> Result::Error> { - Ok(ExistingLayerStrategy::Keep) - } -} diff --git a/test-buildpacks/sbom/tests/integration_test.rs b/test-buildpacks/sbom/tests/integration_test.rs index df5f35b9..1e28d364 100644 --- a/test-buildpacks/sbom/tests/integration_test.rs +++ b/test-buildpacks/sbom/tests/integration_test.rs @@ -113,8 +113,7 @@ fn test() { context.rebuild(&build_config, |context| { context.download_sbom_files(|sbom_files| { - // The 'test' layer does not return any SBOM files in its update implementation. This - // must result in no SBOM files being used from previous build. + // The buildpack removes restored SBOMs from the 'test' layer. assert!(!sbom_files .path_for( &buildpack_id, From 34dd6ed888ebf79608002ea717cff4d337ee85f1 Mon Sep 17 00:00:00 2001 From: Manuel Fuchs Date: Fri, 14 Jun 2024 11:45:10 +0200 Subject: [PATCH 3/4] Migrate execd example buildpack to struct layer API --- examples/execd/src/layer.rs | 35 ----------------------------------- examples/execd/src/main.rs | 24 +++++++++++++++--------- 2 files changed, 15 insertions(+), 44 deletions(-) delete mode 100644 examples/execd/src/layer.rs diff --git a/examples/execd/src/layer.rs b/examples/execd/src/layer.rs deleted file mode 100644 index fbf4a124..00000000 --- a/examples/execd/src/layer.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::ExecDBuildpack; -use libcnb::build::BuildContext; -use libcnb::data::layer_content_metadata::LayerTypes; -use libcnb::generic::GenericMetadata; -use libcnb::layer::{Layer, LayerResult, LayerResultBuilder}; -use libcnb::{additional_buildpack_binary_path, Buildpack}; -use std::path::Path; - -pub(crate) struct ExecDLayer; - -impl Layer for ExecDLayer { - type Buildpack = ExecDBuildpack; - type Metadata = GenericMetadata; - - fn types(&self) -> LayerTypes { - LayerTypes { - launch: true, - build: false, - cache: false, - } - } - - fn create( - &mut self, - _context: &BuildContext, - _layer_path: &Path, - ) -> Result, ::Error> { - LayerResultBuilder::new(GenericMetadata::default()) - .exec_d_program( - "dice_roller", - additional_buildpack_binary_path!("dice_roller"), - ) - .build() - } -} diff --git a/examples/execd/src/main.rs b/examples/execd/src/main.rs index 84c2fc42..791e7df3 100644 --- a/examples/execd/src/main.rs +++ b/examples/execd/src/main.rs @@ -1,18 +1,12 @@ -// This example uses the older trait Layer API. The example will be updated to the newer API -// before the next libcnb.rs release. -#![allow(deprecated)] - -mod layer; - -use crate::layer::ExecDLayer; use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::layer_name; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::{GenericError, GenericMetadata, GenericPlatform}; -use libcnb::{buildpack_main, Buildpack}; +use libcnb::{additional_buildpack_binary_path, buildpack_main, Buildpack}; // Suppress warnings due to the `unused_crate_dependencies` lint not handling integration tests well. use fastrand as _; +use libcnb::layer::UncachedLayerDefinition; #[cfg(test)] use libcnb_test as _; @@ -28,7 +22,19 @@ impl Buildpack for ExecDBuildpack { } fn build(&self, context: BuildContext) -> libcnb::Result { - context.handle_layer(layer_name!("layer_name"), ExecDLayer)?; + let layer_ref = context.uncached_layer( + layer_name!("layer_name"), + UncachedLayerDefinition { + build: false, + launch: true, + }, + )?; + + layer_ref.replace_exec_d_programs([( + "dice_roller", + additional_buildpack_binary_path!("dice_roller"), + )])?; + BuildResultBuilder::new().build() } } From b49d6cedd322096ee158581045230c438d9f911a Mon Sep 17 00:00:00 2001 From: Manuel Fuchs Date: Tue, 18 Jun 2024 11:16:55 +0200 Subject: [PATCH 4/4] Update after rebase --- examples/execd/src/main.rs | 2 +- test-buildpacks/readonly-layer-files/src/main.rs | 6 +++--- test-buildpacks/sbom/src/main.rs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/execd/src/main.rs b/examples/execd/src/main.rs index 791e7df3..9686943c 100644 --- a/examples/execd/src/main.rs +++ b/examples/execd/src/main.rs @@ -30,7 +30,7 @@ impl Buildpack for ExecDBuildpack { }, )?; - layer_ref.replace_exec_d_programs([( + layer_ref.write_exec_d_programs([( "dice_roller", additional_buildpack_binary_path!("dice_roller"), )])?; diff --git a/test-buildpacks/readonly-layer-files/src/main.rs b/test-buildpacks/readonly-layer-files/src/main.rs index 853376f7..1d4d3f93 100644 --- a/test-buildpacks/readonly-layer-files/src/main.rs +++ b/test-buildpacks/readonly-layer-files/src/main.rs @@ -2,7 +2,7 @@ use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder}; use libcnb::data::layer_name; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::{GenericMetadata, GenericPlatform}; -use libcnb::layer::{CachedLayerDefinition, InspectRestoredAction, InvalidMetadataAction}; +use libcnb::layer::{CachedLayerDefinition, InvalidMetadataAction, RestoredLayerAction}; use libcnb::{buildpack_main, Buildpack}; use std::fs; use std::fs::Permissions; @@ -29,8 +29,8 @@ impl Buildpack for TestBuildpack { CachedLayerDefinition { build: true, launch: true, - invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, - inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::DeleteLayer, + invalid_metadata_action: &|_| InvalidMetadataAction::DeleteLayer, + restored_layer_action: &|_: &GenericMetadata, _| RestoredLayerAction::DeleteLayer, }, )?; diff --git a/test-buildpacks/sbom/src/main.rs b/test-buildpacks/sbom/src/main.rs index 5620eecd..49f8a1ce 100644 --- a/test-buildpacks/sbom/src/main.rs +++ b/test-buildpacks/sbom/src/main.rs @@ -4,7 +4,7 @@ use libcnb::data::sbom::SbomFormat; use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder}; use libcnb::generic::{GenericMetadata, GenericPlatform}; use libcnb::layer::{ - CachedLayerDefinition, InspectRestoredAction, InvalidMetadataAction, LayerState, + CachedLayerDefinition, InvalidMetadataAction, LayerState, RestoredLayerAction, }; use libcnb::sbom::Sbom; use libcnb::{buildpack_main, Buildpack}; @@ -30,17 +30,17 @@ impl Buildpack for TestBuildpack { CachedLayerDefinition { build: true, launch: true, - invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, - inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::KeepLayer, + invalid_metadata_action: &|_| InvalidMetadataAction::DeleteLayer, + restored_layer_action: &|_: &GenericMetadata, _| RestoredLayerAction::KeepLayer, }, )?; match first_layer_ref.state { LayerState::Restored { .. } => { - first_layer_ref.replace_sboms(&[])?; + first_layer_ref.write_sboms(&[])?; } LayerState::Empty { .. } => { - first_layer_ref.replace_sboms(&[ + first_layer_ref.write_sboms(&[ Sbom::from_bytes( SbomFormat::CycloneDxJson, *include_bytes!("../etc/cyclonedx_3.sbom.json"), @@ -62,13 +62,13 @@ impl Buildpack for TestBuildpack { CachedLayerDefinition { build: true, launch: true, - invalid_metadata: &|_| InvalidMetadataAction::DeleteLayer, - inspect_restored: &|_: &GenericMetadata, _| InspectRestoredAction::KeepLayer, + invalid_metadata_action: &|_| InvalidMetadataAction::DeleteLayer, + restored_layer_action: &|_: &GenericMetadata, _| RestoredLayerAction::KeepLayer, }, )?; if let LayerState::Empty { .. } = second_layer_ref.state { - second_layer_ref.replace_sboms(&[ + second_layer_ref.write_sboms(&[ Sbom::from_bytes( SbomFormat::CycloneDxJson, *include_bytes!("../etc/cyclonedx_2.sbom.json"),