Skip to content

Commit

Permalink
Add stateful logging to a layer in the examples
Browse files Browse the repository at this point in the history
Status: I can get it into the layer, but cannot get it back out. Need to add a LayerData.layer property.
  • Loading branch information
schneems committed Jan 29, 2024
1 parent c7b81e9 commit 97584c2
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 14 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ libcnb-data = { version = "=0.17.0", path = "libcnb-data" }
libcnb-package = { version = "=0.17.0", path = "libcnb-package" }
libcnb-proc-macros = { version = "=0.17.0", path = "libcnb-proc-macros" }
libcnb-test = { version = "=0.17.0", path = "libcnb-test" }
libherokubuildpack = { version = "=0.17.0", path = "libherokubuildpack" }
toml = { version = "0.8.8" }
1 change: 1 addition & 0 deletions examples/basics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ workspace = true

[dependencies]
libcnb.workspace = true
libherokubuildpack.workspace = true
96 changes: 96 additions & 0 deletions examples/basics/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use libcnb::build::{BuildContext, BuildResult, BuildResultBuilder};
use libcnb::data::layer_content_metadata::LayerTypes;
use libcnb::data::layer_name;
use libcnb::detect::{DetectContext, DetectResult, DetectResultBuilder};
use libcnb::generic::{GenericError, GenericMetadata, GenericPlatform};
use libcnb::layer::{Layer, LayerData};
use libcnb::{buildpack_main, Buildpack};
use libherokubuildpack::buildpack_output::{state, BuildpackOutput, LayerOutput};
use std::fmt::Debug;
use std::io::Write;

pub(crate) struct BasicBuildpack;

Expand All @@ -15,9 +21,99 @@ impl Buildpack for BasicBuildpack {
}

fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
let output = BuildpackOutput::new(std::io::stdout())
.start("Basic buildpack")
.section("Running layer");
let out = context.handle_layer(
layer_name!("simple"),
SimpleLayer {
output: Some(output),
},
);
println!("Build runs on stack {}!", context.stack_id);
BuildResultBuilder::new().build()
}
}

struct SimpleLayer<W>
where
W: Write + Debug + Send + Sync + 'static,
{
output: Option<BuildpackOutput<state::Section, W>>,
}

impl<W> LayerOutput<W> for SimpleLayer<W>
where
W: Write + Debug + Send + Sync + 'static,
{
fn get(&mut self) -> BuildpackOutput<state::Section, W> {
self.output
.take()
.expect("Output must be set to use this layer")
}

fn set(&mut self, output: BuildpackOutput<state::Section, W>) {
self.output = Some(output);
}
}

impl<W> Layer for SimpleLayer<W>
where
W: Write + Debug + Send + Sync + 'static,
{
type Buildpack = BasicBuildpack;
type Metadata = GenericMetadata;

fn existing_layer_strategy(
&mut self,
_context: &BuildContext<Self::Buildpack>,
_layer_data: &libcnb::layer::LayerData<Self::Metadata>,
) -> Result<libcnb::layer::ExistingLayerStrategy, <Self::Buildpack as Buildpack>::Error> {
self.step("Examining layer strategy");
Ok(libcnb::layer::ExistingLayerStrategy::Recreate)
}

fn update(
&mut self,
_context: &BuildContext<Self::Buildpack>,
layer_data: &libcnb::layer::LayerData<Self::Metadata>,
) -> Result<libcnb::layer::LayerResult<Self::Metadata>, <Self::Buildpack as Buildpack>::Error>
{
self.step("Calling update");
libcnb::layer::LayerResultBuilder::new(layer_data.content_metadata.metadata.clone())
.env(layer_data.env.clone())
.build()
}

fn migrate_incompatible_metadata(
&mut self,
_context: &BuildContext<Self::Buildpack>,
_metadata: &GenericMetadata,
) -> Result<
libcnb::layer::MetadataMigration<Self::Metadata>,
<Self::Buildpack as Buildpack>::Error,
> {
Ok(libcnb::layer::MetadataMigration::RecreateLayer)
}

fn types(&self) -> libcnb::data::layer_content_metadata::LayerTypes {
LayerTypes {
launch: true,
build: true,
cache: true,
}
}

fn create(
&mut self,
_context: &BuildContext<Self::Buildpack>,
_layer_path: &std::path::Path,
) -> Result<libcnb::layer::LayerResult<Self::Metadata>, <Self::Buildpack as Buildpack>::Error>
{
self.step("Calling create");

libcnb::layer::LayerResultBuilder::new(GenericMetadata::default()).build()
}
}

buildpack_main!(BasicBuildpack);
17 changes: 5 additions & 12 deletions libherokubuildpack/src/buildpack_output/layer_output.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
//! TODO docs
use crate::buildpack_output::{state, BuildpackOutput, Stream};

trait LayerOutput<W>
pub trait LayerOutput<W>
where
W: std::io::Write + std::fmt::Debug + Send + Sync + 'static,
{
fn get(&mut self) -> BuildpackOutput<state::Section, W>;
fn set(
&mut self,
output: BuildpackOutput<state::Section, W>,
) -> BuildpackOutput<state::Section, W>;
fn set(&mut self, output: BuildpackOutput<state::Section, W>);

fn step(&mut self, s: impl AsRef<str>) {
let out = self.get().step(s.as_ref());
Expand All @@ -36,11 +33,7 @@ where
self.set(output);
}

fn error(mut self, s: impl AsRef<str>)
where
Self: Sized,
{
let output = self.get();
output.error(s.as_ref());
}
// Intentionally not implemented because it consumes
// If you want to emit an error inside a layer, raise an error
// fn error
}
4 changes: 2 additions & 2 deletions libherokubuildpack/src/buildpack_output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use std::sync::{Arc, Mutex};
use std::time::Instant;

pub mod layer_output;
pub use layer_output::LayerOutput;
pub mod style;
mod util;

Expand All @@ -38,8 +39,7 @@ pub struct BuildpackOutput<T, W: Debug> {
///
/// The [`BuildpackOutput`] struct acts as an output state machine. These structs
/// are meant to represent those states.
#[doc(hidden)]
pub(crate) mod state {
pub mod state {
#[derive(Debug)]
pub struct NotStarted;

Expand Down

0 comments on commit 97584c2

Please sign in to comment.