From 550b9b128b5328cb1cb887570f39972a4d4d5c1a Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 12:40:09 -0500 Subject: [PATCH 01/16] Deprecate api for configuring environment variables These structs were used with the old trait based API. They're not needed anymore as env-vars can be written without needing a struct now. --- commons/CHANGELOG.md | 6 ++++++ commons/src/lib.rs | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/commons/CHANGELOG.md b/commons/CHANGELOG.md index e2f06180..d3bdfa00 100644 --- a/commons/CHANGELOG.md +++ b/commons/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog for commons features +## 2024-10-30 + +## Changed + +- Deprecate `layers` including `layers::ConfigureEnvLayer` and `layers::DefaultEnvLayer` () + ## 2024-08-16 ### Fixed diff --git a/commons/src/lib.rs b/commons/src/lib.rs index 15edfa45..0f80c633 100644 --- a/commons/src/lib.rs +++ b/commons/src/lib.rs @@ -6,6 +6,10 @@ pub mod cache; pub mod display; pub mod gem_version; pub mod gemfile_lock; +#[deprecated( + since = "0.0.0", + note = "Use the struct layer API in the latest libcnb.rs instead" +)] pub mod layer; pub mod metadata_digest; pub mod output; From 92ace6c768fb078562d35e59ae076977b4627965 Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 12:41:40 -0500 Subject: [PATCH 02/16] Rename metadata struct --- commons/src/cache/in_app_dir_cache_layer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commons/src/cache/in_app_dir_cache_layer.rs b/commons/src/cache/in_app_dir_cache_layer.rs index 78650795..0753fa57 100644 --- a/commons/src/cache/in_app_dir_cache_layer.rs +++ b/commons/src/cache/in_app_dir_cache_layer.rs @@ -29,7 +29,7 @@ pub(crate) struct InAppDirCacheLayer { } #[derive(Deserialize, Serialize, Debug, Clone)] -pub(crate) struct InAppDirCacheLayerMetadata { +pub(crate) struct Metadata { app_dir_path: PathBuf, } @@ -48,7 +48,7 @@ where B: Buildpack, { type Buildpack = B; - type Metadata = InAppDirCacheLayerMetadata; + type Metadata = Metadata; fn types(&self) -> LayerTypes { LayerTypes { @@ -63,7 +63,7 @@ where _context: &BuildContext, _layer_path: &Path, ) -> Result, B::Error> { - LayerResultBuilder::new(InAppDirCacheLayerMetadata { + LayerResultBuilder::new(Metadata { app_dir_path: self.app_dir_path.clone(), }) .build() From c91bd27e617fd4ef766ad95153530895e15c8aa9 Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 12:49:44 -0500 Subject: [PATCH 03/16] Make metadata internals accessible and PartialEq --- commons/src/cache/in_app_dir_cache_layer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commons/src/cache/in_app_dir_cache_layer.rs b/commons/src/cache/in_app_dir_cache_layer.rs index 0753fa57..6ab16762 100644 --- a/commons/src/cache/in_app_dir_cache_layer.rs +++ b/commons/src/cache/in_app_dir_cache_layer.rs @@ -28,9 +28,9 @@ pub(crate) struct InAppDirCacheLayer { buildpack: PhantomData, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub(crate) struct Metadata { - app_dir_path: PathBuf, + pub(crate) app_dir_path: PathBuf, } impl InAppDirCacheLayer { From 258607da82e3546169bdc1728f64e3dbcd83acfb Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 13:39:26 -0500 Subject: [PATCH 04/16] Replace layer trait with struct layer --- commons/src/cache/app_cache.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/commons/src/cache/app_cache.rs b/commons/src/cache/app_cache.rs index cf099615..10537c86 100644 --- a/commons/src/cache/app_cache.rs +++ b/commons/src/cache/app_cache.rs @@ -1,10 +1,11 @@ use crate::cache::clean::{lru_clean, FilesWithSize}; -use crate::cache::in_app_dir_cache_layer::InAppDirCacheLayer; +use crate::cache::in_app_dir_cache_layer; use crate::cache::{CacheConfig, CacheError, KeepPath}; use byte_unit::{AdjustedByte, Byte, UnitType}; use fs_extra::dir::CopyOptions; use libcnb::build::BuildContext; use libcnb::data::layer::LayerName; +use libcnb::layer::{CachedLayerDefinition, InvalidMetadataAction, RestoredLayerAction}; use std::path::Path; use std::path::PathBuf; use walkdir::WalkDir; @@ -257,11 +258,27 @@ pub fn build( let layer_name = create_layer_name(&context.app_dir, &path)?; let create_state = layer_name_cache_state(&context.layers_dir, &layer_name); - let layer = context - .handle_layer(layer_name, InAppDirCacheLayer::new(path.clone())) - .map_err(|error| CacheError::InternalLayerError(format!("{error:?}")))?; - - let cache = layer.path; + let metadata = in_app_dir_cache_layer::Metadata { + app_dir_path: path.clone(), + }; + let cache = context + .cached_layer( + layer_name, + CachedLayerDefinition { + build: true, + launch: true, + invalid_metadata_action: &|_| InvalidMetadataAction::DeleteLayer, + restored_layer_action: &|old: &in_app_dir_cache_layer::Metadata, _| { + if old == &metadata { + RestoredLayerAction::KeepLayer + } else { + RestoredLayerAction::DeleteLayer + } + }, + }, + ) + .map_err(|error| CacheError::InternalLayerError(format!("{error:?}"))) + .map(|layer_ref| layer_ref.path())?; Ok(AppCache { path, From 2ceb7231d2ef7fcd89fc3fdc29c0920701c5593f Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 13:39:45 -0500 Subject: [PATCH 05/16] Remove deprecation allowance --- commons/src/cache/app_cache.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/commons/src/cache/app_cache.rs b/commons/src/cache/app_cache.rs index 10537c86..ed505a24 100644 --- a/commons/src/cache/app_cache.rs +++ b/commons/src/cache/app_cache.rs @@ -244,7 +244,6 @@ pub enum PathState { /// # Errors /// /// - If the layer cannot be created -#[allow(deprecated)] pub fn build( context: &BuildContext, config: CacheConfig, From 4a2eaf920f2672a41eaa62e0c062d284f9ad23ab Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 13:40:41 -0500 Subject: [PATCH 06/16] Remove unused code --- commons/src/cache/in_app_dir_cache_layer.rs | 62 --------------------- 1 file changed, 62 deletions(-) diff --git a/commons/src/cache/in_app_dir_cache_layer.rs b/commons/src/cache/in_app_dir_cache_layer.rs index 6ab16762..01787bd7 100644 --- a/commons/src/cache/in_app_dir_cache_layer.rs +++ b/commons/src/cache/in_app_dir_cache_layer.rs @@ -1,11 +1,4 @@ -use libcnb::build::BuildContext; -use libcnb::data::layer_content_metadata::LayerTypes; -#[allow(deprecated)] -use libcnb::layer::{ExistingLayerStrategy, Layer, LayerData, LayerResult, LayerResultBuilder}; -use libcnb::Buildpack; use serde::{Deserialize, Serialize}; -use std::marker::PhantomData; -use std::path::Path; use std::path::PathBuf; /// # Caches a folder in the application directory @@ -22,62 +15,7 @@ use std::path::PathBuf; /// Historically, sprockets will keep 3 versions of old files on disk. This /// allows for emails, that might live a long time, to reference a specific SHA of an /// asset. -#[derive(Deserialize, Serialize, Debug, Clone)] -pub(crate) struct InAppDirCacheLayer { - pub(crate) app_dir_path: PathBuf, - buildpack: PhantomData, -} - #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub(crate) struct Metadata { pub(crate) app_dir_path: PathBuf, } - -impl InAppDirCacheLayer { - pub(crate) fn new(app_dir_path: PathBuf) -> Self { - Self { - app_dir_path, - buildpack: PhantomData, - } - } -} - -#[allow(deprecated)] -impl Layer for InAppDirCacheLayer -where - B: Buildpack, -{ - type Buildpack = B; - type Metadata = Metadata; - - fn types(&self) -> LayerTypes { - LayerTypes { - build: true, - launch: true, - cache: true, - } - } - - fn create( - &mut self, - _context: &BuildContext, - _layer_path: &Path, - ) -> Result, B::Error> { - LayerResultBuilder::new(Metadata { - app_dir_path: self.app_dir_path.clone(), - }) - .build() - } - - fn existing_layer_strategy( - &mut self, - _context: &BuildContext, - layer_data: &LayerData, - ) -> Result { - if self.app_dir_path == layer_data.content_metadata.metadata.app_dir_path { - Ok(ExistingLayerStrategy::Keep) - } else { - Ok(ExistingLayerStrategy::Recreate) - } - } -} From 94af5d30289d95f260adf84ef81c7ce65ed38adb Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 13:42:45 -0500 Subject: [PATCH 07/16] Move Metadata struct --- commons/src/cache.rs | 1 - commons/src/cache/app_cache.rs | 25 ++++++++++++++++++--- commons/src/cache/in_app_dir_cache_layer.rs | 21 ----------------- 3 files changed, 22 insertions(+), 25 deletions(-) delete mode 100644 commons/src/cache/in_app_dir_cache_layer.rs diff --git a/commons/src/cache.rs b/commons/src/cache.rs index 12e8b3b6..8f39528c 100644 --- a/commons/src/cache.rs +++ b/commons/src/cache.rs @@ -3,7 +3,6 @@ mod app_cache_collection; mod clean; mod config; mod error; -mod in_app_dir_cache_layer; pub use self::app_cache::{build, PathState}; pub use self::app_cache::{AppCache, CacheState}; diff --git a/commons/src/cache/app_cache.rs b/commons/src/cache/app_cache.rs index ed505a24..773cb9c9 100644 --- a/commons/src/cache/app_cache.rs +++ b/commons/src/cache/app_cache.rs @@ -1,11 +1,11 @@ use crate::cache::clean::{lru_clean, FilesWithSize}; -use crate::cache::in_app_dir_cache_layer; use crate::cache::{CacheConfig, CacheError, KeepPath}; use byte_unit::{AdjustedByte, Byte, UnitType}; use fs_extra::dir::CopyOptions; use libcnb::build::BuildContext; use libcnb::data::layer::LayerName; use libcnb::layer::{CachedLayerDefinition, InvalidMetadataAction, RestoredLayerAction}; +use serde::{Deserialize, Serialize}; use std::path::Path; use std::path::PathBuf; use walkdir::WalkDir; @@ -236,6 +236,25 @@ pub enum PathState { HasFiles, } +/// # Caches a folder in the application directory +/// +/// Layers are used for caching, however layers cannot be inside of the app directory. +/// This layer can be used to hold a directory's contents so they are preserved +/// between deploys. +/// +/// The primary usecase of this is for caching assets. After `rake assets:precompile` runs +/// file in `/public/assets` need to be preserved between deploys. This allows +/// for faster deploys, and also allows for prior generated assets to remain on the system +/// until "cleaned." +/// +/// Historically, sprockets will keep 3 versions of old files on disk. This +/// allows for emails, that might live a long time, to reference a specific SHA of an +/// asset. +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] +pub(crate) struct Metadata { + pub(crate) app_dir_path: PathBuf, +} + /// Converts a `CacheConfig` into an `AppCache` /// /// Same as `AppCache::new_and_load` without loading @@ -257,7 +276,7 @@ pub fn build( let layer_name = create_layer_name(&context.app_dir, &path)?; let create_state = layer_name_cache_state(&context.layers_dir, &layer_name); - let metadata = in_app_dir_cache_layer::Metadata { + let metadata = Metadata { app_dir_path: path.clone(), }; let cache = context @@ -267,7 +286,7 @@ pub fn build( build: true, launch: true, invalid_metadata_action: &|_| InvalidMetadataAction::DeleteLayer, - restored_layer_action: &|old: &in_app_dir_cache_layer::Metadata, _| { + restored_layer_action: &|old: &Metadata, _| { if old == &metadata { RestoredLayerAction::KeepLayer } else { diff --git a/commons/src/cache/in_app_dir_cache_layer.rs b/commons/src/cache/in_app_dir_cache_layer.rs deleted file mode 100644 index 01787bd7..00000000 --- a/commons/src/cache/in_app_dir_cache_layer.rs +++ /dev/null @@ -1,21 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::path::PathBuf; - -/// # Caches a folder in the application directory -/// -/// Layers are used for caching, however layers cannot be inside of the app directory. -/// This layer can be used to hold a directory's contents so they are preserved -/// between deploys. -/// -/// The primary usecase of this is for caching assets. After `rake assets:precompile` runs -/// file in `/public/assets` need to be preserved between deploys. This allows -/// for faster deploys, and also allows for prior generated assets to remain on the system -/// until "cleaned." -/// -/// Historically, sprockets will keep 3 versions of old files on disk. This -/// allows for emails, that might live a long time, to reference a specific SHA of an -/// asset. -#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] -pub(crate) struct Metadata { - pub(crate) app_dir_path: PathBuf, -} From ee8d5667fdd138a44f6b527e211aa0d592565f5b Mon Sep 17 00:00:00 2001 From: Schneems Date: Wed, 30 Oct 2024 13:45:13 -0500 Subject: [PATCH 08/16] Remove previously deprecated interface --- commons/CHANGELOG.md | 1 + commons/src/cache.rs | 3 - commons/src/cache/app_cache_collection.rs | 91 ----------------------- 3 files changed, 1 insertion(+), 94 deletions(-) delete mode 100644 commons/src/cache/app_cache_collection.rs diff --git a/commons/CHANGELOG.md b/commons/CHANGELOG.md index d3bdfa00..d3cfa570 100644 --- a/commons/CHANGELOG.md +++ b/commons/CHANGELOG.md @@ -5,6 +5,7 @@ ## Changed - Deprecate `layers` including `layers::ConfigureEnvLayer` and `layers::DefaultEnvLayer` () +- Remove `AppCacheCollection` () ## 2024-08-16 diff --git a/commons/src/cache.rs b/commons/src/cache.rs index 8f39528c..a6735c4b 100644 --- a/commons/src/cache.rs +++ b/commons/src/cache.rs @@ -1,13 +1,10 @@ mod app_cache; -mod app_cache_collection; mod clean; mod config; mod error; pub use self::app_cache::{build, PathState}; pub use self::app_cache::{AppCache, CacheState}; -#[allow(deprecated)] -pub use self::app_cache_collection::AppCacheCollection; pub use self::clean::FilesWithSize; pub use self::config::CacheConfig; pub use self::config::{mib, KeepPath}; diff --git a/commons/src/cache/app_cache_collection.rs b/commons/src/cache/app_cache_collection.rs deleted file mode 100644 index ef11e0ad..00000000 --- a/commons/src/cache/app_cache_collection.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::cache::{AppCache, CacheConfig, CacheError, CacheState, PathState}; -use crate::output::{interface::SectionLogger, section_log as log}; -use libcnb::{build::BuildContext, Buildpack}; -use std::fmt::Debug; - -/// App Cache Collection -/// -/// Load and store multiple cache's from an application's directory. This essentially acts -/// as a group of `InAppDirCache` that run together -/// -/// Used for loading/unloading asset cache and communicating what's happening to the user. -/// -/// Default logging is provided for each operation. -/// -#[derive(Debug)] -#[deprecated( - since = "0.1.0", - note = "Use `AppCache` directly to manage cache for a single path" -)] -pub struct AppCacheCollection<'a> { - _log: &'a dyn SectionLogger, - collection: Vec, -} -#[allow(deprecated)] -impl<'a> AppCacheCollection<'a> { - /// Store multiple application paths in the cache - /// - /// # Errors - /// - /// - Error if the cache layer cannot be created - /// - Error if loading (copying) files from the cache to the app fails - /// - Error if app or cache directory cannot be created (for example, due to permissions) - pub fn new_and_load( - context: &BuildContext, - config: impl IntoIterator, - log: &'a dyn SectionLogger, - ) -> Result { - let caches = config - .into_iter() - .map(|config| { - AppCache::new_and_load(context, config).inspect(|store| { - let path = store.path().display(); - - log::log_step(match store.cache_state() { - CacheState::NewEmpty => format!("Creating cache for {path}"), - CacheState::ExistsEmpty => format!("Loading (empty) cache for {path}"), - CacheState::ExistsWithContents => format!("Loading cache for {path}"), - }); - }) - }) - .collect::, CacheError>>()?; - - Ok(Self { - collection: caches, - _log: log, - }) - } - - /// # Errors - /// - /// Returns an error if the cache cannot be moved or copied, for example - /// due to file permissions or another process deleting the target directory. - /// Returns an error if cleaning the cache directory cannot - /// be completed. For example due to file permissions. - pub fn save_and_clean(&self) -> Result<(), CacheError> { - for store in &self.collection { - let path = store.path().display(); - - log::log_step(match store.path_state() { - PathState::Empty => format!("Storing cache for (empty) {path}"), - PathState::HasFiles => format!("Storing cache for {path}"), - }); - - if let Some(removed) = store.save_and_clean()? { - let path = store.path().display(); - let limit = store.limit(); - let removed_len = removed.files.len(); - let removed_size = removed.adjusted_bytes(); - - log::log_step(format!( - "Detected cache size exceeded (over {limit} limit by {removed_size}) for {path}" - )); - log::log_step(format!( - "Removed {removed_len} files from the cache for {path}", - )); - } - } - - Ok(()) - } -} From c5b1e8e4d196b2fe6df3c303f8b64f0443edb985 Mon Sep 17 00:00:00 2001 From: Schneems Date: Thu, 31 Oct 2024 09:07:40 -0500 Subject: [PATCH 09/16] Deprecate BuildLog --- commons/CHANGELOG.md | 1 + commons/src/output/build_log.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/commons/CHANGELOG.md b/commons/CHANGELOG.md index d3cfa570..e6701efb 100644 --- a/commons/CHANGELOG.md +++ b/commons/CHANGELOG.md @@ -6,6 +6,7 @@ - Deprecate `layers` including `layers::ConfigureEnvLayer` and `layers::DefaultEnvLayer` () - Remove `AppCacheCollection` () +- Deprecate `output` module in favor of the `bullet_stream` crate () ## 2024-08-16 diff --git a/commons/src/output/build_log.rs b/commons/src/output/build_log.rs index 39e0d47f..21e9e1a7 100644 --- a/commons/src/output/build_log.rs +++ b/commons/src/output/build_log.rs @@ -32,6 +32,7 @@ use std::time::{Duration, Instant}; /// For usage details run `cargo run --bin print_style_guide` #[derive(Debug)] +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub struct BuildLog { pub(crate) io: W, pub(crate) data: BuildData, From d19ceedc83f15826d79731344d6c944cdf6ae563 Mon Sep 17 00:00:00 2001 From: Schneems Date: Thu, 31 Oct 2024 09:09:45 -0500 Subject: [PATCH 10/16] Remove style guide (since it's deprecated) --- .github/workflows/ci.yml | 16 --- commons/Cargo.toml | 4 - commons/bin/print_style_guide.rs | 216 ------------------------------ commons/src/output/build_log.rs | 4 +- commons/src/output/section_log.rs | 2 - 5 files changed, 2 insertions(+), 240 deletions(-) delete mode 100644 commons/bin/print_style_guide.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c55c54e9..d97929da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,19 +95,3 @@ jobs: run: pack build my-image --force-color --builder heroku/builder:24 --trust-extra-buildpacks --buildpack heroku/nodejs-engine --buildpack packaged/${{ matrix.target }}/debug/heroku_ruby --path tmp/ruby-getting-started --pull-policy never - name: "PRINT: Cached getting started guide output" run: pack build my-image --force-color --builder heroku/builder:24 --trust-extra-buildpacks --buildpack heroku/nodejs-engine --buildpack packaged/${{ matrix.target }}/debug/heroku_ruby --path tmp/ruby-getting-started --pull-policy never - - print-style-guide: - runs-on: ubuntu-24.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Install musl-tools - run: sudo apt-get install musl-tools --no-install-recommends - - name: Update Rust toolchain - run: rustup update - - name: Install Rust linux-musl target - run: rustup target add x86_64-unknown-linux-musl - - name: Rust Cache - uses: Swatinem/rust-cache@v2.7.5 - - name: "PRINT: Style guide" - run: cargo run --quiet --bin print_style_guide diff --git a/commons/Cargo.toml b/commons/Cargo.toml index ca78c717..f4281e54 100644 --- a/commons/Cargo.toml +++ b/commons/Cargo.toml @@ -3,10 +3,6 @@ name = "commons" edition.workspace = true rust-version.workspace = true -[[bin]] -name = "print_style_guide" -path = "bin/print_style_guide.rs" - [lints] workspace = true diff --git a/commons/bin/print_style_guide.rs b/commons/bin/print_style_guide.rs deleted file mode 100644 index b180b350..00000000 --- a/commons/bin/print_style_guide.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Required due to: https://github.com/rust-lang/rust/issues/95513 -#![allow(unused_crate_dependencies)] - -use ascii_table::AsciiTable; -use commons::output::fmt::{self, DEBUG_INFO, HELP}; -#[allow(clippy::wildcard_imports)] -use commons::output::{ - build_log::*, - section_log::{log_step, log_step_stream, log_step_timed}, -}; -use fun_run::CommandWithName; -use indoc::formatdoc; -use std::io::stdout; -use std::process::Command; - -#[allow(clippy::too_many_lines)] -fn main() { - println!( - "{}", - formatdoc! {" - - Living build output style guide - =============================== - "} - ); - - { - let mut log = BuildLog::new(stdout()).buildpack_name("Section logging features"); - log = log - .section("Section heading example") - .step("step example") - .step("step example two") - .end_section(); - - log = log - .section("Section and step description") - .step( - "A section should be a noun i.e. 'Ruby Version', consider this the section topic.", - ) - .step("A step should be a verb i.e. 'Downloading'") - .step("Related verbs should be nested under a single section") - .step( - formatdoc! {" - Steps can be multiple lines long - However they're best as short, factual, - descriptions of what the program is doing. - "} - .trim(), - ) - .step("Prefer a single line when possible") - .step("Sections and steps are sentence cased with no ending puncuation") - .step(&format!("{HELP} capitalize the first letter")) - .end_section(); - - let mut command = Command::new("bash"); - command.args(["-c", "ps aux | grep cargo"]); - - let mut stream = log.section("Timer steps") - .step("Long running code should execute with a timer printing to the UI, to indicate the progam did not hang.") - .step("Example:") - .step_timed("Background progress timer") - .finish_timed_step() - .step("Output can be streamed. Mostly from commands. Example:") - .step_timed_stream(&format!("Running {}", fmt::command(command.name()))); - - // TODO: Remove usage of unwrap(): https://github.com/heroku/buildpacks-ruby/issues/238 - #[allow(clippy::unwrap_used)] - command.stream_output(stream.io(), stream.io()).unwrap(); - log = stream.finish_timed_stream().end_section(); - drop(log); - } - - { - let mut log = BuildLog::new(stdout()).buildpack_name("Section log functions"); - log = log - .section("Logging inside a layer") - .step( - formatdoc! {" - Layer interfaces are neither mutable nor consuming i.e. - - ``` - fn create( - &self, - _context: &BuildContext, - layer_path: &Path, - ) -> Result, RubyBuildpackError> - ``` - - To allow logging within a layer you can use the `output::section_log` interface. - "} - .trim_end(), - ) - .step("This `section_log` inteface allows you to log without state") - .step("That means you're responsonsible creating a section before calling it") - .step("Here's an example") - .end_section(); - - let section_log = log.section("Example:"); - - log_step("log_step()"); - log_step_timed("log_step_timed()", || { - // do work here - }); - log_step_stream("log_step_stream()", |stream| { - // TODO: Remove usage of unwrap(): https://github.com/heroku/buildpacks-ruby/issues/238 - #[allow(clippy::unwrap_used)] - Command::new("bash") - .args(["-c", "ps aux | grep cargo"]) - .stream_output(stream.io(), stream.io()) - .unwrap() - }); - log_step(formatdoc! {" - If you want to help make sure you're within a section then you can require your layer - takes a reference to `&'a dyn SectionLogger` - "}); - section_log.end_section(); - } - - { - // TODO: Remove usage of unwrap(): https://github.com/heroku/buildpacks-ruby/issues/238 - #[allow(clippy::unwrap_used)] - let cmd_error = Command::new("iDoNotExist").named_output().err().unwrap(); - - let mut log = BuildLog::new(stdout()).buildpack_name("Error and warnings"); - log = log - .section("Debug information") - .step("Should go above errors in section/step format") - .end_section(); - - log = log - .section(DEBUG_INFO) - .step(&cmd_error.to_string()) - .end_section(); - - log.announce() - .warning(&formatdoc! {" - Warning: This is a warning header - - This is a warning body. Warnings are for when we know for a fact a problem exists - but it's not bad enough to abort the build. - "}) - .important(&formatdoc! {" - Important: This is important - - Important is for when there's critical information that needs to be read - however it may or may not be a problem. If we know for a fact that there's - a problem then use a warning instead. - - An example of something that is important but might not be a problem is - that an application owner upgraded to a new stack. - "}) - .error(&formatdoc! {" - Error: This is an error header - - This is the error body. Use an error for when the build cannot continue. - An error should include a header with a short description of why it cannot continue. - - The body should include what error state was observed, why that's a problem, and - what remediation steps an application owner using the buildpack to deploy can - take to solve the issue. - "}); - } - - { - let mut log = BuildLog::new(stdout()).buildpack_name("Formatting helpers"); - - log = log - .section("The fmt module") - .step(&formatdoc! {" - Formatting helpers can be used to enhance log output: - "}) - .end_section(); - - let mut table = AsciiTable::default(); - table.set_max_width(240); - table.column(0).set_header("Example"); - table.column(1).set_header("Code"); - table.column(2).set_header("When to use"); - - let data: Vec> = vec![ - vec![ - fmt::value("2.3.4"), - "fmt::value(\"2.3.f\")".to_string(), - "With versions, file names or other important values worth highlighting".to_string(), - ], - vec![ - fmt::url("https://www.schneems.com"), - "fmt::url(\"https://www.schneems.com\")".to_string(), - "With urls".to_string(), - ], - vec![ - fmt::command("bundle install"), - "fmt::command(command.name())".to_string(), - "With commands (alongside of `fun_run::CommandWithName`)".to_string(), - ], - vec![ - fmt::details("extra information"), - "fmt::details(\"extra information\")".to_string(), - "Add specific information at the end of a line i.e. 'Cache cleared (ruby version changed)'".to_string() - ], - vec![ - fmt::HELP.to_string(), - "fmt::HELP.to_string()".to_string(), - "A help prefix, use it in a step or section title".to_string() - ], - vec![ - fmt::DEBUG_INFO.to_string(), - "fmt::DEBUG_INFO.to_string()".to_string(), - "A debug prefix, use it in a step or section title".to_string() - ] - ]; - - table.print(data); - drop(log); - } -} diff --git a/commons/src/output/build_log.rs b/commons/src/output/build_log.rs index 21e9e1a7..d22e9a4e 100644 --- a/commons/src/output/build_log.rs +++ b/commons/src/output/build_log.rs @@ -1,6 +1,8 @@ use crate::output::background_timer::{start_timer, StopJoinGuard, StopTimer}; +#[allow(deprecated)] use crate::output::fmt; #[allow(clippy::wildcard_imports)] +#[allow(deprecated)] pub use crate::output::interface::*; use std::fmt::Debug; use std::io::Write; @@ -28,8 +30,6 @@ use std::time::{Duration, Instant}; /// ``` /// /// To log inside of a layer see [`section_log`]. -/// -/// For usage details run `cargo run --bin print_style_guide` #[derive(Debug)] #[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] diff --git a/commons/src/output/section_log.rs b/commons/src/output/section_log.rs index 654d9c64..af491bc4 100644 --- a/commons/src/output/section_log.rs +++ b/commons/src/output/section_log.rs @@ -17,8 +17,6 @@ use std::marker::PhantomData; /// - Ensuring that you are not attempting to log while already logging i.e. calling `step()` within a /// `step_timed()` call. /// -/// For usage details run `cargo run --bin print_style_guide` -/// /// ## Use /// /// The main use case is logging inside of a layer: From 0ba59aa94ccbe3acb62f003433e157f049e24e82 Mon Sep 17 00:00:00 2001 From: Schneems Date: Thu, 31 Oct 2024 09:13:27 -0500 Subject: [PATCH 11/16] Allow deprecated in internal code --- commons/src/output/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/commons/src/output/mod.rs b/commons/src/output/mod.rs index 705d12ac..9a293aa4 100644 --- a/commons/src/output/mod.rs +++ b/commons/src/output/mod.rs @@ -1,7 +1,13 @@ mod background_timer; + +#[allow(deprecated)] pub mod build_log; +#[allow(deprecated)] pub mod fmt; +#[allow(deprecated)] pub mod interface; +#[allow(deprecated)] pub mod section_log; mod util; +#[allow(deprecated)] pub mod warn_later; From 7b90bbf66d9456921814dcd9cc387c0e5bb6e03d Mon Sep 17 00:00:00 2001 From: Schneems Date: Thu, 31 Oct 2024 09:14:20 -0500 Subject: [PATCH 12/16] Deprecate fmt --- commons/src/output/fmt.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/commons/src/output/fmt.rs b/commons/src/output/fmt.rs index abe5c7a6..693c4f2b 100644 --- a/commons/src/output/fmt.rs +++ b/commons/src/output/fmt.rs @@ -5,25 +5,30 @@ use std::fmt::Write; /// Helpers for formatting and colorizing your output /// Decorated str for prefixing "Help:" +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub const HELP: &str = formatcp!("{IMPORTANT_COLOR}! HELP{RESET}"); /// Decorated str for prefixing "Debug info:" +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub const DEBUG_INFO: &str = formatcp!("{IMPORTANT_COLOR}Debug info{RESET}"); /// Decorate a URL for the build output #[must_use] +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn url(contents: impl AsRef) -> String { colorize(URL_COLOR, contents) } /// Decorate the name of a command being run i.e. `bundle install` #[must_use] +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn command(contents: impl AsRef) -> String { value(colorize(COMMAND_COLOR, contents.as_ref())) } /// Decorate an important value i.e. `2.3.4` #[must_use] +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn value(contents: impl AsRef) -> String { let contents = colorize(VALUE_COLOR, contents.as_ref()); format!("`{contents}`") @@ -31,6 +36,7 @@ pub fn value(contents: impl AsRef) -> String { /// Decorate additional information at the end of a line #[must_use] +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn details(contents: impl AsRef) -> String { let contents = contents.as_ref(); format!("({contents})") From 436ebc7501db1407b5f7519de57974c682fd0c96 Mon Sep 17 00:00:00 2001 From: Schneems Date: Thu, 31 Oct 2024 09:14:31 -0500 Subject: [PATCH 13/16] Deprecate section log --- commons/src/output/section_log.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/commons/src/output/section_log.rs b/commons/src/output/section_log.rs index af491bc4..f6a1cee8 100644 --- a/commons/src/output/section_log.rs +++ b/commons/src/output/section_log.rs @@ -46,6 +46,7 @@ use std::marker::PhantomData; /// /// log_step("Clearing cache (ruby version changed)"); /// ``` +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_step(s: impl AsRef) { logger().step(s.as_ref()); } @@ -62,6 +63,7 @@ pub fn log_step(s: impl AsRef) { /// ``` /// /// Timing information will be output at the end of the step. +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_step_timed(s: impl AsRef, f: impl FnOnce() -> T) -> T { let timer = logger().step_timed(s.as_ref()); let out = f(); @@ -86,6 +88,7 @@ pub fn log_step_timed(s: impl AsRef, f: impl FnOnce() -> T) -> T { /// ``` /// /// Timing information will be output at the end of the step. +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_step_stream( s: impl AsRef, f: impl FnOnce(&mut Box) -> T, @@ -97,21 +100,25 @@ pub fn log_step_stream( } /// Print an error block to the output +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_error(s: impl AsRef) { logger().announce().error(s.as_ref()); } /// Print an warning block to the output +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_warning(s: impl AsRef) { logger().announce().warning(s.as_ref()); } /// Print an warning block to the output at a later time +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_warning_later(s: impl AsRef) { logger().announce().warn_later(s.as_ref()); } /// Print an important block to the output +#[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_important(s: impl AsRef) { logger().announce().important(s.as_ref()); } From 3e774754951914599082ac324f310974e9076905 Mon Sep 17 00:00:00 2001 From: Schneems Date: Fri, 1 Nov 2024 10:16:39 -0500 Subject: [PATCH 14/16] Remove unused dependencies These were used in the style guide and docs for a deprecated feature. --- Cargo.lock | 12 ------------ commons/Cargo.toml | 2 -- commons/src/lib.rs | 4 ---- commons/src/output/section_log.rs | 17 ----------------- 4 files changed, 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b0d23c4..8d29554f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,16 +40,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "ascii_table" -version = "4.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed8a80a95ab122e7cc43bfde1d51949c89ff67e0c76eb795dc045003418473e2" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -278,14 +268,12 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" name = "commons" version = "0.0.0" dependencies = [ - "ascii_table", "byte-unit", "const_format", "fancy-regex", "filetime", "fs-err", "fs_extra", - "fun_run", "glob", "indoc", "lazy_static", diff --git a/commons/Cargo.toml b/commons/Cargo.toml index f4281e54..9012e0ea 100644 --- a/commons/Cargo.toml +++ b/commons/Cargo.toml @@ -7,14 +7,12 @@ rust-version.workspace = true workspace = true [dependencies] -ascii_table = { version = "4", features = ["color_codes"] } byte-unit = "5" const_format = "0.2" # TODO: Consolidate on either the regex crate or the fancy-regex crate, since this repo currently uses both. fancy-regex = "0.13" fs_extra = "1" fs-err = "3" -fun_run = "0.2" glob = "0.3" indoc = "2" lazy_static = "1" diff --git a/commons/src/lib.rs b/commons/src/lib.rs index 0f80c633..27499b7a 100644 --- a/commons/src/lib.rs +++ b/commons/src/lib.rs @@ -1,7 +1,3 @@ -// Used in the style guide -use ascii_table as _; -use fun_run as _; - pub mod cache; pub mod display; pub mod gem_version; diff --git a/commons/src/output/section_log.rs b/commons/src/output/section_log.rs index f6a1cee8..a4ffbb71 100644 --- a/commons/src/output/section_log.rs +++ b/commons/src/output/section_log.rs @@ -71,23 +71,6 @@ pub fn log_step_timed(s: impl AsRef, f: impl FnOnce() -> T) -> T { out } -/// Will print the input string and yield a `Box` that can be used to print -/// to the output. The main use case is running commands -/// -/// ```no_run -/// use fun_run::CommandWithName; -/// use commons::output::section_log::log_step_stream; -/// use commons::output::fmt; -/// -/// let mut cmd = std::process::Command::new("bundle"); -/// cmd.arg("install"); -/// -/// log_step_stream(format!("Running {}", fmt::command(cmd.name())), |stream| { -/// cmd.stream_output(stream.io(), stream.io()).unwrap() -/// }); -/// ``` -/// -/// Timing information will be output at the end of the step. #[deprecated(since = "0.0.0", note = "Use `bullet_stream` instead")] pub fn log_step_stream( s: impl AsRef, From 2e0b0c4cddd1fb57f1e37b724161e23bcf73bdfc Mon Sep 17 00:00:00 2001 From: Schneems Date: Fri, 1 Nov 2024 10:18:54 -0500 Subject: [PATCH 15/16] Consolidate imports --- commons/src/cache.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/commons/src/cache.rs b/commons/src/cache.rs index a6735c4b..af46f861 100644 --- a/commons/src/cache.rs +++ b/commons/src/cache.rs @@ -3,9 +3,7 @@ mod clean; mod config; mod error; -pub use self::app_cache::{build, PathState}; -pub use self::app_cache::{AppCache, CacheState}; +pub use self::app_cache::{build, AppCache, CacheState, PathState}; pub use self::clean::FilesWithSize; -pub use self::config::CacheConfig; -pub use self::config::{mib, KeepPath}; +pub use self::config::{mib, CacheConfig, KeepPath}; pub use self::error::CacheError; From 65782e26dcd31620d4d73a5c1f87ef3c7c645ff3 Mon Sep 17 00:00:00 2001 From: Schneems Date: Sun, 10 Nov 2024 09:12:17 -0600 Subject: [PATCH 16/16] Update changelog date --- commons/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commons/CHANGELOG.md b/commons/CHANGELOG.md index e6701efb..25be13bd 100644 --- a/commons/CHANGELOG.md +++ b/commons/CHANGELOG.md @@ -1,12 +1,12 @@ # Changelog for commons features -## 2024-10-30 +## 2024-11-11 ## Changed -- Deprecate `layers` including `layers::ConfigureEnvLayer` and `layers::DefaultEnvLayer` () -- Remove `AppCacheCollection` () -- Deprecate `output` module in favor of the `bullet_stream` crate () +- Deprecate `layers` including `layers::ConfigureEnvLayer` and `layers::DefaultEnvLayer` (https://github.com/heroku/buildpacks-ruby/pull/345) +- Remove `AppCacheCollection` (https://github.com/heroku/buildpacks-ruby/pull/345) +- Deprecate `output` module in favor of the `bullet_stream` crate (https://github.com/heroku/buildpacks-ruby/pull/345) ## 2024-08-16