diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c55c54e..d97929d 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/Cargo.lock b/Cargo.lock index 8b0d23c..8d29554 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/CHANGELOG.md b/commons/CHANGELOG.md index e2f0618..25be13b 100644 --- a/commons/CHANGELOG.md +++ b/commons/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog for commons features +## 2024-11-11 + +## Changed + +- 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 ### Fixed diff --git a/commons/Cargo.toml b/commons/Cargo.toml index ca78c71..9012e0e 100644 --- a/commons/Cargo.toml +++ b/commons/Cargo.toml @@ -3,22 +3,16 @@ name = "commons" edition.workspace = true rust-version.workspace = true -[[bin]] -name = "print_style_guide" -path = "bin/print_style_guide.rs" - [lints] 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/bin/print_style_guide.rs b/commons/bin/print_style_guide.rs deleted file mode 100644 index b180b35..0000000 --- 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/cache.rs b/commons/src/cache.rs index 12e8b3b..af46f86 100644 --- a/commons/src/cache.rs +++ b/commons/src/cache.rs @@ -1,15 +1,9 @@ mod app_cache; -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}; -#[allow(deprecated)] -pub use self::app_cache_collection::AppCacheCollection; +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; diff --git a/commons/src/cache/app_cache.rs b/commons/src/cache/app_cache.rs index cf09961..773cb9c 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::{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; @@ -235,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 @@ -243,7 +263,6 @@ pub enum PathState { /// # Errors /// /// - If the layer cannot be created -#[allow(deprecated)] pub fn build( context: &BuildContext, config: CacheConfig, @@ -257,11 +276,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 = 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: &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, diff --git a/commons/src/cache/app_cache_collection.rs b/commons/src/cache/app_cache_collection.rs deleted file mode 100644 index ef11e0a..0000000 --- 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(()) - } -} 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 7865079..0000000 --- a/commons/src/cache/in_app_dir_cache_layer.rs +++ /dev/null @@ -1,83 +0,0 @@ -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 -/// -/// 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)] -pub(crate) struct InAppDirCacheLayer { - pub(crate) app_dir_path: PathBuf, - buildpack: PhantomData, -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub(crate) struct InAppDirCacheLayerMetadata { - 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 = InAppDirCacheLayerMetadata; - - 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(InAppDirCacheLayerMetadata { - 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) - } - } -} diff --git a/commons/src/lib.rs b/commons/src/lib.rs index 15edfa4..27499b7 100644 --- a/commons/src/lib.rs +++ b/commons/src/lib.rs @@ -1,11 +1,11 @@ -// Used in the style guide -use ascii_table as _; -use fun_run as _; - 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; diff --git a/commons/src/output/build_log.rs b/commons/src/output/build_log.rs index 39e0d47..d22e9a4 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,10 +30,9 @@ 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")] pub struct BuildLog { pub(crate) io: W, pub(crate) data: BuildData, diff --git a/commons/src/output/fmt.rs b/commons/src/output/fmt.rs index abe5c7a..693c4f2 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})") diff --git a/commons/src/output/mod.rs b/commons/src/output/mod.rs index 705d12a..9a293aa 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; diff --git a/commons/src/output/section_log.rs b/commons/src/output/section_log.rs index 654d9c6..a4ffbb7 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: @@ -48,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()); } @@ -64,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(); @@ -71,23 +71,7 @@ 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, f: impl FnOnce(&mut Box) -> T, @@ -99,21 +83,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()); }